> ## Documentation Index
> Fetch the complete documentation index at: https://developer.plugsurfing.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Roam OCPI FAQ

> Quick answers to common implementation questions about Plugsurfing Roam OCPI.

## About Roam OCPI

Read a summary about Roam OCPI: [About Roam OCPI →](/docs/roam-ocpi/about-roam-ocpi)

<Accordion title="What is Roam OCPI?">
  Roam OCPI is Plugsurfing’s OCPI-based roaming interface designed to share the entire Plugsurfing network to EMPs via a single OCPI integration.  It includes managed roaming (agreements, communication and invoicing handled by Plugsurfing).
</Accordion>

<Accordion title="What does “managed roaming” include?">
  Managed roaming means Plugsurfing handles the roaming network operations: CPO relationships, commercial negotiation, technical onboarding, quality assurance, price/tariff management, support, invoice processing, reconciliation, CDR validation, and CPO dispute handling.
</Accordion>

<Accordion title="Which OCPI version is used?">
  Roam OCPI is exposed to EMPs as an OCPI 2.2.1 integration. Some underlying CPO integrations may still use OCPI 2.1.1 or other protocols, which can affect edge cases such as token/CDR attribution.
</Accordion>

<Accordion title="What are the main deviations from standard OCPI?">
  The deviations to OCPI 2.2.1 are lined out under each module.&#x20;
</Accordion>

<Accordion title="Which OCPI modules are supported (pull/push)?">
  [Module overview →](/docs/roam-ocpi/module-overview)
</Accordion>

<Accordion title="How is Roam OCPI different from Drive API?">
  Roam OCPI is a separate product from Drive API. Use Roam OCPI for managed roaming through OCPI 2.2.1. Do not mix Drive API endpoints, user flows, payment flows, charging-key ordering, AI tooling, or proprietary session flows with Roam OCPI module documentation.
</Accordion>

***

## Access and limits

Read the details of how to access the API here: [Accessing the API →](/docs/roam-ocpi/accessing-the-api)

<Accordion title="How do we authenticate / is IP filtering used?">
  Plugsurfing does not currently use IP filtering to access the API.  Access control is based on the API key exchanged during the Credentials module handshake.
</Accordion>

<Accordion title="Are IDs unique across all CPOs exposed via Roam OCPI?">
  Yes — the following IDs are unique across all CPOs exposed via the API: Location id, EVSE uid, Connector id, Tariff id, Session id, CDR id.
</Accordion>

<Accordion title="Are rate-limit backoff headers returned?">
  If the limit is reached, Plugsurfing returns HTTP `429`. Currently, no rate-limiting headers such as `Retry-After` are returned. Location pull is allowed up to once per minute, excluding pagination.
</Accordion>

<Accordion title="Rate limiting / fair usage">
  Per-minute limit: A maximum of 3,000 requests per clock minute (e.g., from 12:07:00 to 12:07:59). Per-day limit: A maximum of 1,000,000 requests per calendar day (from 00:00 to 23:59 UTC). Soft limit for Roam OCPI Location pull: up to once per minute (pagination excluded).

  **Related documentation:** [Fair usage policy →](/fair-usage-policy)
</Accordion>

***

## Credentials

Read the details of the Credentials module deviations and specifications here: [Credentials module →](/docs/roam-ocpi/credentials-module)

<Accordion title="What do we receive during the Credentials handshake?">
  During the Credentials handshake, Plugsurfing assumes the CPO role with business name `Plugsurfing`, `country_code = DE`, and `party_id = 8PS`. The roles list contains only this Plugsurfing CPO role. Plugsurfing does not use HubClientInfo. The actual CPO/operator is communicated through Locations using `country_code`, `party_id`, and the `operator` field.&#x20;
</Accordion>

<Accordion title="How do we know which operators are part of the solution?">
  Operators are identified through the Locations feed, not through the Credentials roles list. During the Credentials handshake, Plugsurfing is shared as the CPO role with `country_code = DE` and `party_id = 8PS`. The actual CPO/operator information is communicated in each Location object using the connection owner’s `country_code` + `party_id` and the `operator` field. There might be several operators linked to one `country_code` + `party_id` combination. If a CPO is removed, its Locations will no longer appear in Location pulls.&#x20;
</Accordion>

<Accordion title="How are new CPOs added after go-live? Do partners need a new handshake?">
  For standard Roam OCPI setups using the Plugsurfing role `DE*8PS`, partners do not need a new handshake when CPOs are added or removed. New CPOs are reflected through new locations becoming available in the Location pulls. If a CPO is removed, its locations will no longer be part of the Location pull.
</Accordion>

***

## Retrieving locations

Read the details of the Locations module deviations and specifications here: [Locations module →](/docs/roam-ocpi/locations-module)

<Accordion title="Can we connect to specific CPOs, or do we subscribe by country?">
  Production setup is country-based: all locations within your selected countries are available to you. You cannot select only a subset of CPOs to include, but you can request specific CPOs to be filtered out (blocked). Newly added CPOs within your supported countries are available by default.
</Accordion>

<Accordion title="How do full and delta pulls work?">
  Locations are pulled by the EMP; Plugsurfing does not push Locations, EVSEs, or connectors. A full pull using `GET /locations` builds or reconciles the complete cache. A full pull is recommended e.g. once per 24h so that you can remove locations that are no longer available. Delta pulls using `date_from` / `date_to` return locations where location data or inlined tariff data has changed during the specified time period. Delta pulls can be performed up to once per minute.
</Accordion>

<Accordion title="How often should partners pull Locations?">
  For status and tariff freshness, partners should use delta pulls. We recommend every 1–5 minutes depending on the partner’s use case and traffic profile.
</Accordion>

<Accordion title="How does Location pagination work?">
  Maximum page size is 250 locations. Plugsurfing does not use deep pagination; partners should follow the next-page URL in the `Link` response header. The `Link` header contains a `smart_paging` parameter. Parallel pulling of Locations is not supported because smart pagination is used.
</Accordion>

<Accordion title="How are removed Locations handled?">
  Removed locations are detected through a full pull: if a previously available location is absent from the full pull, it should be removed from the partner’s system. A nightly full pull is recommended.
</Accordion>

<Accordion title="Can a Location be delivered without a name?">
  The `name` field (display name of the location) is optional in OCPI 2.2.1, so some locations can be delivered without a `name`.
</Accordion>

<Accordion title="Which EVSE capabilities are supported?">
  The following capabilities are supported, and they will be returned from the EVSEs the API: CHIP\_CARD\_SUPPORT, CONTACTLESS\_CARD\_SUPPORT, CREDIT\_CARD\_PAYABLE,  DEBIT\_CARD\_PAYABLE , PED\_TERMINAL,  REMOTE\_START\_STOP\_CAPABLE,  RFID\_READER, START\_SESSION\_CONNECTOR\_REQUIRED.<br /><br />The following capabilities are not supported, and they will be stripped from the EVSEs returned via the API: CHARGING\_PROFILE\_CAPABLE, CHARGING\_PREFERENCES\_CAPABLE, RESERVABLE, TOKEN\_GROUP\_CAPABLE, UNLOCK\_CAPABLE.
</Accordion>

<Accordion title="Does Plugsurfing support OCPI routing headers?">
  Yes, but only on the Locations pull endpoint. When `OCPI-to-country-code` and  `OCPI-to-party-id` are provided, Plugsurfing uses them to filter locations for that routed CPO within the EMP’s accessible charging network.
</Accordion>

<Accordion title="How are tariffs represented?">
  The relevant tariffs are inlined on the connector, via the locations module.
</Accordion>

<Accordion title="When a CPO updates tariffs, will last_updated change on Locations?">
  Tariff updates are exposed through the Locations module because tariffs are inlined on connectors. Delta pulls using `date_from` / `date_to` return Locations where either Location data or inlined tariff data has changed. Partners should process the returned Location and inlined tariff object, including the tariff’s own `last_updated`.
</Accordion>

<Accordion title="How should partners treat tariff IDs?">
  Treat tariff IDs as stable identifiers. Tariffs are immutable, which means that the tariff content associated with a specific `tariff_id` will not change after it has been issued.
</Accordion>

***

## Tokens and authorization

Read the details of the Tokens module deviations and specifications here: [Tokens module →](/docs/roam-ocpi/tokens-module)

<Accordion title="What do partners need to send?">
  Token pull is not supported; EMPs must push new or updated tokens to Plugsurfing. Tokens must be pushed before remote start is initiated. By default, tokens are shared with CPOs using issuer `DE*8PS`.
</Accordion>

<Accordion title="Are all token types supported?">
  `AD_HOC_USER` is not supported.
</Accordion>

<Accordion title="How do whitelist types work?">
  Roam OCPI accepts OCPI whitelist types. `NEVER` and `ALLOWED_OFFLINE` are forwarded to CPOs. `ALWAYS` and `ALLOWED` are overwritten to `ALLOWED_OFFLINE` when shared with CPOs. Token whitelist type controls behavior between Plugsurfing and the CPO; real-time authorization between Plugsurfing and the EMP is controlled by an organization setting in Plugsurfing Power Portal.
</Accordion>

<Accordion title="How does real-time authorization work?">
  Real-time authorization can be configured per organization by Plugsurfing. If enabled, Plugsurfing performs primary checks first, including whether the Location is within supported countries based on an existing Location reference and whether the key is enabled. If those checks pass, Plugsurfing forwards the authorization request to the EMP. Timeout is configurable from 1–10 seconds, and timeout/malformed-response behavior can be configured to accept or deny.
</Accordion>

<Accordion title="Can partners block charging attempts for unknown or unsupported locations?">
  They can get tighter control by using `whitelist=NEVER`, enabling external real-time authorization, and denying authorizations when the location reference is missing or unknown. This improves control but can negatively affect driver experience because not all CPOs do real-time authorization for all sessions and not all authorization requests include a resolvable location reference.
</Accordion>

<Accordion title="Can multiple tokens share one contract_id?">
  Yes, if configured. By default, one key is supported per `contract_id`, but an organization can be configured to support multiple keys per `contract_id`. A maximum of 25 tokens per `contract_id` applies. If an older CPO integration only provides the `contract_id` in a local-start CDR, Plugsurfing may not be able to identify the exact charging key and will pick the first key matching that `contract_id`. The `X-Original-Protocol` header on outgoing Session/CDR requests can help identify when this limitation may apply.
</Accordion>

<Accordion title="What happens if multiple tokens share one contract_id and an old CDR arrives later?">
  When multiple tokens share the same `contract_id`, some upstream protocols may not identify the exact key used in a CDR. In those cases, Plugsurfing matches the CDR to the first token with that `contract_id`. The `X-Original-Protocol` header can be used to understand when this limitation may apply.
</Accordion>

<Accordion title="What is X-Original-Protocol?">
  `X-Original-Protocol` is a header available on outgoing Session and CDR requests in cases where there may be uncertainty about the exact charging key used. This can happen when multiple tokens share the same `contract_id` and an older upstream protocol only provides the `contract_id` in the CDR. The header contains \<protocol>-\<version>, for example `OCPI-2.1.1`, `OCPI-2.2`, `OCPI-2.2.1`, or `OICP-2.3`.
</Accordion>

<Accordion title="Can contract_id be changed after a token has been pushed?">
  Allow change of `contract_id` is based on an organization setting, please create a support ticket to learn about or update the setting for your organization.
</Accordion>

<Accordion title="Why does contract_id come back in a different format (with dashes)?">
  Plugsurfing normalizes incoming `contract_id` to a consistent format for downstream partners, and the original formatting is not preserved. You may see the normalized version in sessions/CDRs. Example: DE8PSABCDEFGHI1 becomes DE-8PS-ABCDEFGHI-1
</Accordion>

<Accordion title="Can partners have multiple contract_id prefixes?">
  Multiple prefixes are allowed for `contract_id`. Plugsurfing needs a list of the `contract_id` prefixes before tokens are pushed, as those have to be registered in the Plugsurfing portal as well as with some CPO partners before you can roam with them. We expect the `contract_id` to follow the eMI3/eMA ID format where applicable.
</Accordion>

<Accordion title="Why would a Location reference be missing in authorization?">
  The location reference is optional in OCPI. Hence, some real-time authorization requests may not include a usable Location reference. This depends on the CPO and originating protocol. Plugsurfing can check whether a Location is within the supported countries when a resolvable Location reference is provided, but partners should not assume that `location_id` is always available in the authorization flows.
</Accordion>

<Accordion title="Can charging be restricted by supported countries?">
  Plugsurfing can restrict charging to specific countries via the EMP's Supported Countries list, and deny starts when the CPO sends online authorization with a resolvable location reference. Limitations: if a station/CPO does offline starts / no online authorization, we can't fully guarantee blocking. To tighten this, set field whitelist=NEVER (vs default ALLOWED\_OFFLINE). By requiring real-time auth with whitelist = never and denying real-time auth request where the location reference is missing or unknown, you have full control.
</Accordion>

***

## Commands

Read the details of the Commands module deviations and specifications here: [Commands module →](/docs/roam-ocpi/commands-module)

<Accordion title="Which remote commands are supported?">
  `START_SESSION` and `STOP_SESSION` are supported. `RESERVE_NOW`, `CANCEL_RESERVATION`, and `UNLOCK_CONNECTOR` are not supported. If an unsupported command is sent, an OCPI response with result `NOT_SUPPORTED` is returned.
</Accordion>

***

## Sessions

Read the details of the Sessions module deviations and specifications here: [Sessions module →](/docs/roam-ocpi/sessions-module)

<Accordion title="How are Sessions delivered, and are pull/PATCH updates supported?">
  Sessions are push-only. Plugsurfing pushes Sessions to the EMP; Session pull is not supported. For generic payload examples, refer to the OCPI 2.2.1 Sessions module examples. We support PATCH updates for incremental kWh data during an ongoing session, but not for charging periods.
</Accordion>

***

## CDRs

Read the details of the CDRs module deviations and specifications here: [CDRs module →](/docs/roam-ocpi/cdrs-module)

<Accordion title="When and how are CDRs delivered?">
  CDRs are pushed by Plugsurfing to the partner once they are received by the CPO and fully processed. You should expect one CDR per completed charging transaction
</Accordion>

<Accordion title="Can CDRs be delayed?">
  CDR timing depends on when the CPO provides the CDR and whether processing, validation, or dispute handling is needed. Some CDRs may be delivered shortly after the session, while others can be delayed.
</Accordion>

<Accordion title="What is the retry behavior of CDRs?">
  If the EMP does not respond with `HTTP 200`, the CDR will be resent nightly for up to 7 days.
</Accordion>

<Accordion title="Are credit CDRs supported?">
  No, credit CDRs are not supported.
</Accordion>

<Accordion title="Is the CDR ID always the same as the Session ID?">
  When there is a Session ID, the CDR ID is always the same as the Session ID.
</Accordion>

<Accordion title="Can a CDR be sent without a Session ID?">
  Yes. Not all CPOs behind Roam OCPI support the Sessions module. There may also be very short sessions where the CDR is created before the session event is delivered.
</Accordion>

<Accordion title="Is cost breakdown always populated?">
  Yes. Even when the CPO does not provide cost breakdown per tariff element, Plugsurfing populates it in the CDR shared with the EMP.
</Accordion>

<Accordion title="Can anything be missing from CDRs?">
  Offline/semi-offline sessions can occur without authorization; later session messages may have no `authorization_reference`. Downstream OCPI 2.1.1 integrations don’t have the `authorization_reference` field.
</Accordion>

***

## Stage testing and support

<Accordion title="What should partners test in stage?">
  Credentials handshake; Location full pull; Location delta pull; token push; token disable/update; remote start/stop; local-start simulation with agreed test token/location; real-time auth accept/deny and timeout/failure behavior if enabled.
</Accordion>

<Accordion title="What information should partners include when raising support issues?">
  Environment, timestamp, token UID or contract ID, CPO, EVSE ID, and Session ID when session specific. When necessary, request URL/method, request/response body, OCPI `status_code/status_message`, `X-Original-Protocol` if present, and whether issue is CPO-specific or global.
</Accordion>

<Accordion title="Where can partners monitor platform status?">
  Operational status of the Plugsurfing platform. Consider subscribing to be directly notified to get updates directly via email.

  **Related documentation:** [Plugsurfing status page →](https://status.plugsurfing.com/)
</Accordion>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.