Skip to content
OCPI Endpoints Reference: API Guide for 2.1.1 and 2.2.1

OCPI Endpoints Reference: API Guide for 2.1.1 and 2.2.1

·25 min read
Share:

OCPI is a REST API protocol. Every interaction between a CPO and an eMSP -- or between either party and a roaming hub like GIREVE -- is a standard HTTP request carrying a JSON payload. There are no WebSocket connections, no binary frames, no persistent channels. If you understand REST, you understand the transport layer of OCPI. What makes OCPI distinct is its module-based architecture: each functional domain (locations, sessions, billing, authorization) has its own set of endpoints with clearly defined ownership between parties.

This reference covers every endpoint across all OCPI modules for versions 2.1.1 and 2.2.1. For each module, you will find the purpose, which party implements which endpoints, the full endpoint table, key data fields, and implementation notes. If you are new to OCPI as a protocol, start there first. This document assumes you understand the basics and need the endpoint-level detail.

For version-specific implementation validation, pair this reference with OCPI 2.1.1 testing and OCPI 2.2.1 testing.

Base URL Structure and Versioning

Every OCPI implementation exposes a single entry point: the versions endpoint. From there, all module endpoints are discovered dynamically. There are no hardcoded paths. The base URL structure follows this pattern:

https://api.example.com/ocpi/

From this root, the protocol defines two discovery endpoints that every implementation must support:

  • GET /versions -- returns a list of supported OCPI versions with their URLs
  • GET /versions/{version_id} -- returns the list of module endpoints for a specific version

A typical versions response looks like this:

{
  "status_code": 1000,
  "data": [
    {
      "version": "2.1.1",
      "url": "https://api.example.com/ocpi/2.1.1"
    },
    {
      "version": "2.2.1",
      "url": "https://api.example.com/ocpi/2.2.1"
    }
  ]
}

When you call the version-specific URL, you receive the full list of module endpoints that party supports:

{
  "status_code": 1000,
  "data": {
    "version": "2.1.1",
    "endpoints": [
      { "identifier": "credentials", "url": "https://api.example.com/ocpi/2.1.1/credentials" },
      { "identifier": "locations", "url": "https://api.example.com/ocpi/2.1.1/locations" },
      { "identifier": "sessions", "url": "https://api.example.com/ocpi/2.1.1/sessions" },
      { "identifier": "cdrs", "url": "https://api.example.com/ocpi/2.1.1/cdrs" },
      { "identifier": "tariffs", "url": "https://api.example.com/ocpi/2.1.1/tariffs" },
      { "identifier": "tokens", "url": "https://api.example.com/ocpi/2.1.1/tokens" },
      { "identifier": "commands", "url": "https://api.example.com/ocpi/2.1.1/commands" }
    ]
  }
}

This dynamic discovery is a core design principle. You never assume where a module lives. You always discover it through the version endpoint. This allows implementations to host modules on different servers, use different URL structures, or version independently.

Authentication and the Credentials Handshake

OCPI uses token-based authentication. Every HTTP request includes an Authorization header with a Token prefix:

Authorization: Token IpbJOXxkxOAuKR92z0nEcmVF3Qc09VG7I7d/WCg0koM=

These tokens are not JWTs. They are opaque strings, typically base64-encoded random bytes. The critical aspect is how they are exchanged: through the credentials handshake.

The Credentials Exchange Flow

The credentials module is the only module that uses a pre-shared token (TOKEN_A) for initial authentication. The flow works as follows:

Step 1: Out-of-band, Party A and Party B agree on a TOKEN_A. This is typically exchanged via email, a hub's admin portal, or a registration API.

Step 2: Party A calls GET /versions on Party B's platform, authenticating with TOKEN_A, to discover supported versions.

Step 3: Party A calls GET /versions/2.1.1 (or whichever version both support) to discover Party B's module endpoints.

Step 4: Party A sends POST /credentials to Party B, including:

  • Party A's own credentials URL
  • Party A's generated TOKEN_B (the token Party B will use to call Party A)
  • Party A's business details (party_id, country_code, name, roles)

Step 5: Party B validates the request, stores TOKEN_B for future use, and responds with:

  • Party B's generated TOKEN_C (the token Party A will use to call Party B going forward)
  • Party B's business details

From this point forward, TOKEN_A is invalidated. Party A uses TOKEN_C to authenticate requests to Party B. Party B uses TOKEN_B to authenticate requests to Party A.

Credentials Module Endpoints

Method Path Description Used By
GET /credentials Retrieve the credentials object of the other party Both
POST /credentials Register with the other party (initial handshake) Both
PUT /credentials Update credentials (token rotation) Both
DELETE /credentials Unregister from the other party Both

The PUT /credentials endpoint allows either party to rotate tokens at any time without disrupting the connection. This is a significant security advantage and should be done periodically in production deployments.

Locations Module

The Locations module is the backbone of OCPI. It contains the complete inventory of charge points, their physical locations, capabilities, and real-time status. Every roaming connection starts with location data exchange.

OCPI uses a three-level hierarchy: Location (a physical site) contains one or more EVSEs (individual charge points), each of which has one or more Connectors (physical sockets).

Implemented by: CPO (sender/owner of location data), eMSP (receiver)

CPO Endpoints (Sender Interface)

These endpoints are implemented by the CPO. The eMSP calls them to pull location data.

Method Path Description
GET /locations Fetch list of all locations (paginated, supports date_from/date_to filtering)
GET /locations/{location_id} Fetch a specific location with all EVSEs and connectors
GET /locations/{location_id}/{evse_uid} Fetch a specific EVSE
GET /locations/{location_id}/{evse_uid}/{connector_id} Fetch a specific connector

eMSP Endpoints (Receiver Interface)

These endpoints are implemented by the eMSP. The CPO calls them to push location updates.

Method Path Description
PUT /locations/{country_code}/{party_id}/{location_id} Push a full location object (create or replace)
PUT /locations/{country_code}/{party_id}/{location_id}/{evse_uid} Push a full EVSE object
PUT /locations/{country_code}/{party_id}/{location_id}/{evse_uid}/{connector_id} Push a full connector object
PATCH /locations/{country_code}/{party_id}/{location_id} Partial update to a location
PATCH /locations/{country_code}/{party_id}/{location_id}/{evse_uid} Partial update to an EVSE
PATCH /locations/{country_code}/{party_id}/{location_id}/{evse_uid}/{connector_id} Partial update to a connector

Key Location Data Fields

Field Type Description
id string Unique identifier of the location within the CPO's platform
type LocationType ON_STREET, PARKING_GARAGE, UNDERGROUND_GARAGE, PARKING_LOT, OTHER
address string Street address
city string City name
coordinates GeoLocation Latitude and longitude
evses EVSE[] List of EVSEs at this location
operator BusinessDetails Operator information (name, website, logo)
time_zone string IANA time zone identifier (2.2.1 only)
last_updated DateTime Timestamp of the last update

Key EVSE Data Fields

Field Type Description
uid string Unique identifier within the CPO's platform
evse_id string Compliant EVSE ID following the standard format (e.g., DECPOE12345)
status Status AVAILABLE, BLOCKED, CHARGING, INOPERATIVE, OUTOFORDER, PLANNED, REMOVED
connectors Connector[] List of connectors on this EVSE
capabilities Capability[] CHARGING_PROFILE_CAPABLE, REMOTE_START_STOP_CAPABLE, RFID_READER, etc.
last_updated DateTime Timestamp of the last update

Push vs Pull for Locations

In production, CPOs push EVSE status changes in real-time using PATCH requests. The eMSP uses GET /locations with date_from filtering for periodic full synchronization -- typically daily or weekly -- to catch any missed push updates. When a CPO sends a PATCH, it should include only the changed fields. A common implementation error is sending full objects via PATCH instead of partial updates, which defeats the purpose of the method.

Sessions Module

The Sessions module tracks active charging sessions in near-real-time. An eMSP uses session data to show drivers the status of their ongoing charge, including energy delivered, duration, and estimated cost.

Implemented by: CPO (sender/owner of session data), eMSP (receiver)

CPO Endpoints (Sender Interface)

Method Path Description
GET /sessions Fetch list of sessions (paginated, supports date_from/date_to)
GET /sessions/{session_id} Fetch a specific session (2.1.1 only)

eMSP Endpoints (Receiver Interface)

Method Path Description
PUT /sessions/{country_code}/{party_id}/{session_id} Push a full session object (create or replace)
PATCH /sessions/{country_code}/{party_id}/{session_id} Partial update to a session (status change, energy update)

Key Session Data Fields

Field Type Description
id string Unique session identifier
start_datetime DateTime When the session started
end_datetime DateTime When the session ended (null if still active)
kwh number Total energy delivered in kWh
auth_id string Token used for authorization
location Location Reference to the location where charging occurs
currency string ISO 4217 currency code
total_cost number Current total cost (updated during charging)
status SessionStatus ACTIVE, COMPLETED, INVALID, PENDING
last_updated DateTime Timestamp of the last update

Implementation Notes

During an active session, the CPO should push session updates to the eMSP at regular intervals -- typically every 30 to 60 seconds. Each update includes the latest kwh value and total_cost. When the session ends, a final PATCH sets the status to COMPLETED and the end_datetime. The session object is then considered immutable. For billing, always rely on the CDR, not the final session object.

CDRs Module (Charge Detail Records)

CDRs are the billing backbone of OCPI. After a charging session completes, the CPO generates a CDR containing the definitive record of what was consumed and what it costs. CDRs are immutable once created -- they cannot be updated or deleted through OCPI.

Implemented by: CPO (sender), eMSP (receiver)

CPO Endpoints (Sender Interface)

Method Path Description
GET /cdrs Fetch list of CDRs (paginated, supports date_from/date_to)
GET /cdrs/{cdr_id} Fetch a specific CDR (2.1.1 only, removed in 2.2.1 sender interface)

eMSP Endpoints (Receiver Interface)

Method Path Description
POST /cdrs Push a new CDR to the eMSP
GET /cdrs/{cdr_id} Fetch a specific CDR by ID (2.2.1 receiver can retrieve stored CDRs)

Key CDR Data Fields

Field Type Description
id string Unique CDR identifier
start_date_time DateTime Start of the charging session
end_date_time DateTime End of the charging session
auth_id string Token used for authorization
auth_method AuthMethod AUTH_REQUEST, COMMAND, WHITELIST
location Location Location where charging occurred
currency string ISO 4217 currency code
total_cost number Total cost of the session
total_energy number Total energy delivered in kWh
total_time number Total duration in hours
total_parking_time number Total idle/parking time in hours
charging_periods ChargingPeriod[] Detailed breakdown of the session into time periods with dimensions
last_updated DateTime Timestamp of last update

Charging Periods and Dimensions

Each CDR contains an array of ChargingPeriod objects, which break the session into time-based segments. Each period has a start_date_time and an array of CdrDimension objects:

Dimension Type Description
ENERGY Energy consumed in kWh during this period
FLAT Flat fee applied (value is always 1 when present)
MAX_CURRENT Maximum current in A during this period
MIN_CURRENT Minimum current in A during this period
PARKING_TIME Idle/parking time in hours
TIME Charging time in hours

These dimensions map directly to tariff elements, enabling precise cost calculation. If you are building a billing system, the CDR's charging periods are the source of truth for invoice generation.

Tariffs Module

The Tariffs module defines pricing structures for charging sessions. CPOs publish their tariffs so eMSPs can display estimated costs to drivers before they start charging.

Implemented by: CPO (sender), eMSP (receiver)

CPO Endpoints (Sender Interface)

Method Path Description
GET /tariffs Fetch list of all tariffs (paginated, supports date_from/date_to)

eMSP Endpoints (Receiver Interface)

Method Path Description
PUT /tariffs/{country_code}/{party_id}/{tariff_id} Push a full tariff object (create or replace)
DELETE /tariffs/{country_code}/{party_id}/{tariff_id} Remove a tariff

Key Tariff Data Fields

Field Type Description
id string Unique tariff identifier
currency string ISO 4217 currency code
elements TariffElement[] List of pricing elements
type TariffType AD_HOC_PAYMENT, PROFILE_CHEAP, PROFILE_FAST, PROFILE_GREEN, REGULAR (2.2.1 only)
tariff_alt_text DisplayText[] Human-readable tariff description
tariff_alt_url URL Link to a human-readable tariff page
energy_mix EnergyMix Energy source information (renewable percentage, etc.)
last_updated DateTime Timestamp of last update

Tariff Elements and Restrictions

Each TariffElement contains a list of PriceComponent objects and optional TariffRestrictions:

Price Components:

Field Description
type ENERGY (per kWh), FLAT (per session), PARKING_TIME (per hour idle), TIME (per hour charging)
price Price per unit excluding VAT
step_size Minimum granularity (e.g., step_size=300 for TIME means billing in 5-minute increments)

Tariff Restrictions (conditions under which the element applies):

Field Description
start_time / end_time Time-of-day restrictions
start_date / end_date Date range restrictions
min_kwh / max_kwh Energy consumption range
min_power / max_power Power range
min_duration / max_duration Session duration range
day_of_week Day-of-week restrictions

This structure enables complex pricing models: different rates for peak vs off-peak hours, penalties for overstaying after charging completes, tiered energy pricing, and more.

Tokens Module

The Tokens module handles driver authorization. eMSPs push their driver tokens (RFID cards, app credentials) to CPOs so that authorization can happen locally without requiring a real-time API call for every charge attempt.

Implemented by: eMSP (sender/owner of token data), CPO (receiver)

Note the reversed ownership: unlike most modules where the CPO is the data owner, here the eMSP owns and pushes token data to the CPO.

eMSP Endpoints (Sender Interface)

Method Path Description
GET /tokens Fetch list of all tokens (paginated, supports date_from/date_to)
GET /tokens/{token_uid} Fetch a specific token (2.1.1)

CPO Endpoints (Receiver Interface)

Method Path Description
GET /tokens/{country_code}/{party_id}/{token_uid} Fetch a specific token
PUT /tokens/{country_code}/{party_id}/{token_uid} Push a full token (create or replace)
PATCH /tokens/{country_code}/{party_id}/{token_uid} Partial update to a token
POST /tokens/{token_uid}/authorize Real-time authorization request (CPO asks eMSP to authorize a token)

Key Token Data Fields

Field Type Description
uid string Unique token identifier (e.g., RFID UID)
type TokenType RFID, APP_USER, OTHER
auth_id string Authorization identifier linking the token to a contract
visual_number string Number printed on the token (if physical card)
issuer string Name of the token issuer
valid boolean Whether the token is currently valid for authorization
whitelist WhitelistType ALWAYS (always accept offline), ALLOWED (accept offline, verify later), NEVER (always verify online), ALLOWED_OFFLINE (2.2.1)
language string Preferred language of the driver
last_updated DateTime Timestamp of last update

Real-Time Authorization

The POST /tokens/{token_uid}/authorize endpoint is special. When a driver presents an RFID card at a charger, the CPO's backend can call this endpoint on the eMSP to get a real-time authorization decision. The eMSP responds with an AuthorizationInfo object containing ALLOWED, BLOCKED, EXPIRED, NO_CREDIT, or NOT_ALLOWED. This is used when the whitelist value is NEVER or when the token is not in the CPO's local cache.

Commands Module

The Commands module enables remote operations on charge points through the roaming chain. An eMSP can instruct a CPO to start a session, stop a session, reserve a charger, or unlock a connector -- all on behalf of the driver.

Implemented by: CPO (receiver of commands), eMSP (sender of commands)

CPO Endpoints (Receiver Interface)

Method Path Description
POST /commands/START_SESSION Request the CPO to start a charging session
POST /commands/STOP_SESSION Request the CPO to stop an active session
POST /commands/RESERVE_NOW Request the CPO to reserve a charge point
POST /commands/UNLOCK_CONNECTOR Request the CPO to unlock a connector

eMSP Endpoints (Callback)

Method Path Description
POST {callback_url} Async result callback -- CPO posts the command result to the URL provided in the original request

Command Request Fields

START_SESSION:

Field Description
response_url Callback URL for the async result
token Token object identifying the driver
location_id Target location
evse_uid Target EVSE (optional in 2.1.1, required in 2.2.1)

STOP_SESSION:

Field Description
response_url Callback URL for the async result
session_id ID of the session to stop

RESERVE_NOW:

Field Description
response_url Callback URL for the async result
token Token object identifying the driver
location_id Target location
evse_uid Target EVSE
expiry_date When the reservation expires

UNLOCK_CONNECTOR:

Field Description
response_url Callback URL for the async result
location_id Target location
evse_uid Target EVSE
connector_id Target connector

Asynchronous Command Flow

Commands are asynchronous by design. The flow is:

  1. eMSP sends POST /commands/START_SESSION to the CPO
  2. CPO responds immediately with ACCEPTED or REJECTED (synchronous response indicating whether the command was received, not whether it succeeded)
  3. CPO forwards the command to the charger via OCPP
  4. When the charger responds, the CPO sends the final result (ACCEPTED, REJECTED, TIMEOUT, UNKNOWN_SESSION, etc.) to the response_url provided in the original request

This two-step flow is necessary because charger communication via OCPP can take several seconds. The eMSP must handle both the synchronous acknowledgment and the asynchronous callback.

ChargingProfiles Module (2.2.1 Only)

The ChargingProfiles module was introduced in OCPI 2.2.1 to enable smart charging through the roaming chain. It allows an eMSP or hub to set power limits on active charging sessions, enabling demand response, fleet management, and grid balancing use cases.

Implemented by: CPO (receiver), eMSP (sender)

CPO Endpoints (Receiver Interface)

Method Path Description
PUT /chargingprofiles/{session_id} Set or update a charging profile for an active session
DELETE /chargingprofiles/{session_id} Clear the charging profile for an active session
GET /chargingprofiles/{session_id} Request the active charging profile for a session

eMSP Endpoints (Callback)

Method Path Description
POST {callback_url} Async result callback with the command outcome or the active profile

Charging Profile Structure

Field Type Description
start_date_time DateTime Start time for the profile
duration integer Duration in seconds
charging_rate_unit ChargingRateUnit W (watts) or A (amperes)
min_charging_rate number Minimum charging rate
charging_profile_period ChargingProfilePeriod[] Time-based power limits

Each ChargingProfilePeriod specifies:

  • start_period: Offset in seconds from start_date_time
  • limit: Maximum power (W) or current (A) for this period

This module maps closely to OCPP's Smart Charging profile. The CPO translates the OCPI charging profile into an OCPP SetChargingProfile request sent to the charger.

HubClientInfo Module (2.2.1 Only)

The HubClientInfo module is used exclusively in hub-based topologies (like GIREVE or Hubject). It allows the hub to inform connected parties about the status and capabilities of other parties connected to the hub.

Implemented by: Hub (sender), CPO/eMSP (receiver)

Hub Endpoints (Sender Interface)

Method Path Description
GET /hubclientinfo Fetch list of all connected parties (paginated)

CPO/eMSP Endpoints (Receiver Interface)

Method Path Description
PUT /hubclientinfo/{country_code}/{party_id} Push client info for a connected party
DELETE /hubclientinfo/{country_code}/{party_id} Notify that a party has disconnected

Key HubClientInfo Data Fields

Field Type Description
party_id string Two-character party identifier
country_code string ISO 3166-1 alpha-2 country code
role Role CPO, EMSP, HUB
status ConnectionStatus CONNECTED, OFFLINE, PLANNED, SUSPENDED
last_updated DateTime Timestamp of last update

This module is primarily used for discovery. An eMSP can use it to know which CPOs are reachable through the hub and what their connection status is.

OCPI Data Types Reference

Several data types are shared across multiple modules. Understanding these is essential for correct implementation.

Common Enumerations

Type Values Used In
Status AVAILABLE, BLOCKED, CHARGING, INOPERATIVE, OUTOFORDER, PLANNED, REMOVED Locations (EVSE status)
ConnectorType CHADEMO, IEC_62196_T1 (Type 1), IEC_62196_T2 (Type 2), IEC_62196_T2_COMBO (CCS2), TESLA_S, DOMESTIC_A, etc. Locations (Connector)
ConnectorFormat SOCKET, CABLE Locations (Connector)
PowerType AC_1_PHASE, AC_3_PHASE, DC Locations (Connector)
Capability CHARGING_PROFILE_CAPABLE, CREDIT_CARD_PAYABLE, REMOTE_START_STOP_CAPABLE, RESERVABLE, RFID_READER, UNLOCK_CAPABLE Locations (EVSE)
TokenType RFID, APP_USER, OTHER Tokens
AuthMethod AUTH_REQUEST, COMMAND, WHITELIST CDRs
SessionStatus ACTIVE, COMPLETED, INVALID, PENDING Sessions
CommandResponseType NOT_SUPPORTED, REJECTED, ACCEPTED, UNKNOWN_SESSION, TIMEOUT Commands

CdrToken Object

The CdrToken is a lightweight token reference embedded within CDRs and Sessions, distinct from the full Token object:

Field Type Description
uid string Token UID
type TokenType RFID, APP_USER, OTHER
contract_id string Contract identifier (e.g., EMAID)

DisplayText Object

Used throughout OCPI for multilingual text content:

Field Type Description
language string ISO 639-1 language code
text string The text content

GeoLocation Object

Field Type Description
latitude string Latitude in decimal degrees (string type to preserve precision)
longitude string Longitude in decimal degrees

Note that coordinates are strings, not floating-point numbers. This is intentional to avoid floating-point precision loss during serialization.

Error Handling and Status Codes

Every OCPI response includes a status_code field. This is distinct from the HTTP status code. The OCPI status code provides protocol-level information about the request outcome.

OCPI Status Code Ranges

Range Category Description
1xxx Success Request processed successfully
2xxx Client errors Problem with the request from the client
3xxx Server errors Problem on the server side

Specific Status Codes

Code Meaning
1000 Generic success
2000 Generic client error
2001 Invalid or missing parameters
2002 Not enough information (e.g., unknown location)
2003 Unknown token
3000 Generic server error
3001 Unable to use the client's API (e.g., connection refused, timeout)
3002 Unsupported version
3003 No matching endpoints

HTTP Status Codes

OCPI also uses standard HTTP status codes:

HTTP Code Usage
200 Successful GET, PUT, PATCH, DELETE
201 Successful POST (resource created)
400 Bad request (malformed JSON, missing required fields)
401 Unauthorized (invalid or missing token)
404 Resource not found
405 Method not allowed

A critical implementation detail: always check both the HTTP status code AND the OCPI status code. A 200 HTTP response with an OCPI status code of 2001 means the request was received but contained invalid parameters. Many implementations incorrectly check only the HTTP code and miss protocol-level errors.

Pagination

All GET list endpoints support pagination through the following headers and parameters:

Request parameters: offset (starting index), limit (max items per page), date_from, date_to

Response headers: X-Total-Count (total number of objects), X-Limit (server-imposed max per page), Link (URL to next page)

Always respect the server's X-Limit header. If you request limit=1000 but the server returns X-Limit: 100, you must paginate with 100-item pages.

OCPI 2.1.1 vs 2.2.1: Key Differences

While the core architecture remains the same, OCPI 2.2.1 introduced several important changes:

New Modules in 2.2.1

  • ChargingProfiles: Smart charging through the roaming chain (described above)
  • HubClientInfo: Hub connection status information (described above)

Structural Changes

Area 2.1.1 2.2.1
Token authorize POST /tokens/{token_uid}/authorize Path includes {type}: POST /tokens/{token_uid}/authorize?type=RFID
CDR sender GET by ID GET /cdrs/{cdr_id} available Removed from sender interface
Session sender GET by ID GET /sessions/{session_id} available Removed from sender interface
Tariff types No type field Added TariffType enum for categorization
Location time zones Not available Added time_zone field to Location objects
EVSE ID format Recommended More strictly defined
Connector ID in commands Not required for START_SESSION evse_uid required for START_SESSION

Module Identifier Changes

The module identifiers used in version endpoint discovery are the same across both versions: credentials, locations, sessions, cdrs, tariffs, tokens, commands. The 2.2.1 additions use chargingprofiles and hubclientinfo.

Data Model Changes

In 2.2.1, several objects gained additional fields for richer data exchange. The Location object added time_zone and publish fields. The Tariff object added the type field for categorizing pricing structures. The Token object refined the whitelist types and added group_id for corporate fleet management.

If you are implementing a new system, target 2.2.1 as the primary version. Most hubs and major CPOs/eMSPs support 2.2.1. Maintain 2.1.1 compatibility only if your roaming partners require it.

Frequently Asked Questions

How does OCPI differ from OCPP?

OCPP is the protocol between a charger and a backend system (CSMS). It uses WebSocket connections and handles charge point management, firmware updates, and local authorization. OCPI is the protocol between backend systems (CPO-to-eMSP or CPO-to-Hub). It uses standard REST APIs and handles roaming, data exchange, and inter-network billing. A typical deployment uses both: OCPP from charger to CPO backend, and OCPI from CPO backend to eMSP or hub.

Do I need to implement all OCPI modules?

No. The only mandatory module is Credentials. All other modules are optional. In practice, a minimal viable implementation typically includes Locations, Sessions, CDRs, and Tokens. Commands is highly recommended if you want to support remote start/stop from roaming partners. Tariffs is important for cost transparency.

How do roaming hubs like GIREVE fit into the endpoint structure?

A roaming hub acts as an intermediary. Instead of establishing direct peer-to-peer OCPI connections with every partner, you connect once to the hub. The hub then proxies requests to and from all other connected parties. From an endpoint perspective, your implementation is identical -- you implement the same sender/receiver interfaces. The only addition is the HubClientInfo module (2.2.1), which the hub uses to inform you about other connected parties.

What happens if a push update fails?

OCPI does not define a retry mechanism in the specification. If a push request fails (network error, 5xx response), the sending party should implement its own retry logic with exponential backoff. The pull mechanism serves as a safety net: the receiving party's periodic pull synchronization will eventually catch updates that were missed during push failures.

Can I use OCPI without a roaming hub?

Yes. OCPI supports direct peer-to-peer connections between a CPO and an eMSP. This is common in markets where a CPO has a small number of roaming partners. However, as the number of partners grows, the hub model becomes more efficient because it reduces the number of connections from O(n^2) to O(n).

What is the difference between PUT and PATCH in OCPI?

PUT replaces the entire object. The request body must contain all required fields. PATCH performs a partial update -- only the fields included in the request body are updated. In practice, use PUT when creating or fully replacing an object, and PATCH for incremental updates like status changes. A PATCH with a field set to null removes that optional field from the object.


OCPI's module-based, REST architecture makes it approachable for any team with HTTP API experience. The key to a successful implementation is getting the credential handshake right, implementing both push and pull modes for resilience, and testing thoroughly against real roaming partners or a hub's sandbox environment. For testing your OCPP charger integration that feeds data into your OCPI layer, an OCPP simulator can validate your entire charging and roaming chain end-to-end.

Last updated:

Test your OCPP implementation today

Deploy 1000+ virtual charge points in minutes. No hardware needed.

Get OCPP & EV charging insights

Protocol updates, testing best practices, and industry news. No spam.

Validate More Before You Touch Real Hardware

Launch virtual chargers quickly, inspect protocol traffic, and validate backend changes before you push them into a real charger fleet.

No credit card required · Deploy your first virtual charger in 2 minutes · Contact sales for enterprise