OCPI MODULE · UPDATED 11 AUG 2026

Versions: the handshake before the handshake

Every OCPI connection starts here. Before either party can exchange a location, a token, or a single rupee of settlement, they have to agree on which version of the spec they are speaking and where each module actually lives.

PART OF THE OCPI 2.2.1 COMPLETE GUIDE · 15 MODULE & COMMAND GUIDES

IN ONE PARAGRAPH

The Versions module is two GET endpoints. The first returns the list of OCPI versions a party supports; the second returns, for one chosen version, the full endpoint directory — every module, its role, and its URL. Everything else in OCPI is discovered through it, which is why a misconfigured Versions endpoint is the single most common reason a new partner integration never gets off the ground.

Why a discovery module exists at all

OCPI is a peer-to-peer protocol between independent companies. There is no central registry that tells a CPO where an eMSP's Locations endpoint lives, and no guarantee that two parties run the same version of the spec. Hard-coding a partner's URLs would mean a code change every time they reorganise their API or upgrade a version.

The Versions module solves both problems with one rule: you are given exactly one URL out of band, and you discover everything else from it. That single URL is the versions endpoint. From there you learn which versions the partner supports, and for the version you agree on, the exact URL of every module they expose.

This is why the Versions module is the only part of OCPI whose location you are allowed to know in advance. Everything else is discovered.

The two endpoints

1. The version list

A GET against the versions URL returns every OCPI version this party can speak, each with the URL of its own details endpoint. It is deliberately minimal.

GET /ocpi/versions
Authorization: Token <base64-encoded-token>

{
  "data": [
    { "version": "2.1.1", "url": "https://cpo.example.com/ocpi/2.1.1" },
    { "version": "2.2",   "url": "https://cpo.example.com/ocpi/2.2"   },
    { "version": "2.2.1", "url": "https://cpo.example.com/ocpi/2.2.1" }
  ],
  "status_code": 1000,
  "status_message": "Success",
  "timestamp": "2026-08-11T09:04:12Z"
}

2. The version details

A GET against one of those version URLs returns the endpoint directory: which modules exist, and for each, whether this party acts as the SENDER or the RECEIVER.

GET /ocpi/2.2.1
Authorization: Token <base64-encoded-token>

{
  "data": {
    "version": "2.2.1",
    "endpoints": [
      { "identifier": "credentials",     "role": "SENDER",   "url": "https://cpo.example.com/ocpi/2.2.1/credentials" },
      { "identifier": "locations",       "role": "SENDER",   "url": "https://cpo.example.com/ocpi/2.2.1/locations" },
      { "identifier": "sessions",        "role": "SENDER",   "url": "https://cpo.example.com/ocpi/2.2.1/sessions" },
      { "identifier": "cdrs",            "role": "SENDER",   "url": "https://cpo.example.com/ocpi/2.2.1/cdrs" },
      { "identifier": "tariffs",         "role": "SENDER",   "url": "https://cpo.example.com/ocpi/2.2.1/tariffs" },
      { "identifier": "tokens",          "role": "RECEIVER", "url": "https://cpo.example.com/ocpi/2.2.1/tokens" },
      { "identifier": "commands",        "role": "RECEIVER", "url": "https://cpo.example.com/ocpi/2.2.1/commands" },
      { "identifier": "chargingprofiles","role": "RECEIVER", "url": "https://cpo.example.com/ocpi/2.2.1/chargingprofiles" }
    ]
  },
  "status_code": 1000,
  "timestamp": "2026-08-11T09:04:13Z"
}

Sender and receiver — the field people misread

The role field was added in OCPI 2.2 and it trips up almost every first integration. It does not describe what the other party does. It describes the role this party plays for that module.

In OCPI, the Sender owns the data and is the source of truth. The Receiver consumes it. A CPO is the Sender of Locations because it owns the chargers; the eMSP is the Receiver. For Tokens it inverts — the eMSP owns its customer tokens and is the Sender, while the CPO is the Receiver.

ModuleSender (owns data)Receiver (consumes)
locationsCPOeMSP
sessionsCPOeMSP
cdrsCPOeMSP
tariffsCPOeMSP
tokenseMSPCPO
commandseMSPCPO
chargingprofilesSCSP / eMSPCPO
hubclientinfoHubCPO / eMSP

Because a single party can list the same module twice with different roles, the pair (identifier, role) — not identifier alone — is the unique key. Building your endpoint cache keyed on identifier only is a bug that surfaces the first time you connect to a hub or a party operating in both roles.

Version negotiation in practice

The spec does not mandate an algorithm for picking a version. The convention that works is: fetch the partner's list, intersect it with yours, and take the highest common version. If the intersection is empty, you cannot proceed and must report 3002 — Unsupported version.

Two operational realities make this less clean than it sounds:

  • Version pinning is often contractual, not technical. A partner may support 2.2.1 on paper while their production deployment has only been certified against 2.2. Agreeing the version in the onboarding document and asserting it in code beats auto-negotiating to the highest available.
  • Endpoint URLs change without warning. Partners reorganise their API gateways. If you cached the endpoint directory at registration and never refreshed it, you will find out through failed requests. Re-fetch version details on a schedule and on any unexplained 404.
A note on 2.2 vs 2.2.1. OCPI 2.2.1 is a documentation and correction revision of 2.2 rather than a feature release — the object model is compatible. Partners frequently advertise one and implement the other. Treat them as interchangeable at the transport layer, but confirm which the partner has actually certified before you sign off an integration.

Error handling

The Versions module is where authentication failures surface first, because it is the first authenticated call either party makes. Distinguishing the failure modes saves hours of partner email:

SymptomAlmost always means
HTTP 401 on the versions URLWrong token, or the token was sent unencoded — OCPI 2.2.1 requires the credentials token to be base64-encoded in the Authorization: Token header
HTTP 404 on the versions URLYou were given the version details URL instead of the version list URL — an extremely common onboarding mix-up
3002 Unsupported versionNo overlap between the two version lists
3003 No matching endpointsThe version details response omitted a module you require
Empty endpoints arrayPartner has deployed the version shell without wiring the modules — their side is incomplete

Production lessons

  • Store the versions URL, derive everything else. The only partner URL that belongs in your database is the versions endpoint. Every other URL should be a cached derivation you can rebuild on demand. Integrations that persist module URLs as configuration become unmaintainable at partner number ten.
  • Re-discover on a schedule. Refreshing the endpoint directory daily costs two HTTP calls per partner and catches silent URL migrations before they become an incident.
  • Log the negotiated version on every downstream request. When a partner reports a malformed payload, the first question is always which version each side thought it was speaking. Having it in the request log ends that conversation immediately.
  • Validate the endpoint directory at registration. If a partner's role assignments contradict the module they are asking to use, catch it during onboarding rather than at the first live session.
  • Expose all versions you genuinely support, and no more. Advertising a version you have not tested guarantees that some partner will negotiate to it.

Frequently asked questions

What are the two OCPI Versions endpoints?

The version list, which returns every OCPI version a party supports along with a URL for each, and the version details endpoint, which returns the full endpoint directory for one specific version — every module identifier, its role, and its URL.

What does the role field mean in an OCPI endpoint?

It states whether the party publishing the directory acts as SENDER or RECEIVER for that module. The Sender owns the data and is the source of truth; the Receiver consumes it. A CPO is Sender for Locations and Receiver for Tokens.

How do two OCPI parties agree on a version?

Each fetches the other's version list, intersects it with its own, and takes the highest common version. If there is no overlap, the request fails with status code 3002, Unsupported version. In practice the version is usually fixed contractually during onboarding.

Why does the OCPI versions endpoint return 401?

Almost always because the credentials token was not base64-encoded in the Authorization header. OCPI 2.2.1 requires Token followed by the base64-encoded token value.