The short answer: which OCPI version should you pick?
Target OCPI 2.2.1 for any new roaming implementation, and plan to support 2.1.1 as well if you connect to real partners. That dual stance is the honest answer for most CPOs and eMSPs entering live roaming today.
OCPI (the Open Charge Point Interface) is the REST API that lets CPOs and eMSPs exchange locations, sessions, CDRs, and tariffs so EV drivers can charge across networks. The version question is which release of that interface you implement: the widely deployed 2.1.1 or the newer, more capable 2.2.1.
The reasoning is simple. OCPI 2.2.1 is the better-designed version, with cleaner hub messaging, richer charging-profile support, and a more explicit registration and credentials flow. But OCPI is a federation protocol, so your version choice is only as useful as what your counterparties can actually speak. A large share of production peers, hubs, and bilateral links still run 2.1.1, and they upgrade on their own commercial timelines, not yours.
So the practical target is not one version. It is a primary version (2.2.1) plus a compatibility commitment (2.1.1) that you isolate cleanly inside your platform rather than spreading through every service.
Key changes between OCPI 2.1.1 and 2.2.1
OCPI 2.2.1 reworks how platforms find and address each other, introduces formal hub roaming, and extends the data model for tariffs and smart charging. The headline shift is the move from a flat peer model toward role-aware, hub-routable messaging that scales past one-to-one bilateral links.
The most consequential change is the credentials and versions handshake. In 2.2.1, a party declares its roles and party identity explicitly, which makes hub-mediated routing and many-to-many topologies tractable. Charging profiles also become a first-class concern, so smart-charging signals can travel across the roaming boundary rather than staying trapped inside the OCPP session between charger and operator. Tariffs gain more structure, including better handling of time and energy components.
Here is a side-by-side view of where the two versions differ in practice.
| Area | OCPI 2.1.1 | OCPI 2.2.1 |
|---|---|---|
| Topology | Mostly bilateral, peer-to-peer | Role-aware, hub-routable many-to-many |
| Party identity | Implicit per connection | Explicit roles + party_id in credentials |
| Charging profiles | Not standardized | Dedicated module for smart charging |
| Tariffs | Basic structure | Richer time/energy components |
| Hub support | Workarounds in practice | First-class hub messaging |
| Partner footprint | Still very common in production | Growing, but uneven adoption |
Treat the table as direction-of-travel, not a feature checklist. What matters operationally is which modules your specific partners have certified, not the spec's full surface.
Why is 2.2.1 usually the better long-term target?
OCPI 2.2.1 is the version you would choose if you designed your roaming layer from first principles, because it removes the assumptions that make 2.1.1 awkward at scale. It is built for a world of hubs and multi-role platforms rather than a handful of direct peer links.
Three properties make it the better destination. First, explicit roles and party identity mean you can onboard counterparties through a hub without inventing routing conventions. Second, the charging-profiles module lets smart-charging and load-management intent cross the roaming boundary, which matters as more sites run constrained grid connections. Third, the credentials flow is more disciplined, so token rotation and registration are less error-prone in mixed deployments.
In practice, teams that start on 2.2.1 spend less effort later untangling implicit assumptions they baked in during a quick 2.1.1 launch. If you are deciding where to anchor a new build, anchor it here.
Why does OCPI 2.1.1 still matter in production?
OCPI 2.1.1 still matters because EV charging is not redesigned every quarter, and large parts of the live ecosystem still speak it. Your architectural preference does not change what a partner's certified integration can accept on the day you go live.
In real rollouts, 2.1.1 shows up because of inertia you do not control: existing bilateral integrations, hub peers mid-migration, and partners whose roadmaps treat OCPI upgrades as low priority. The failure mode is predictable. A team builds cleanly against 2.2.1, then discovers a key roaming counterparty only accepts 2.1.1 CDRs or locations, and the launch stalls on the protocol boundary. Commercial timelines rarely wait for both sides to converge on the newer spec.
That is why 2.1.1 compatibility is a launch requirement, not a legacy footnote. The teams that ship fastest assume version skew exists and design for it, rather than betting every partner has finished migrating.
How should the version decision actually be framed?
The decision is not "which version do we prefer?" It is "which version do our partners require, and how do we keep that requirement from hard-coding itself into the rest of our platform?" Framing it that way moves the choice from taste to architecture.
Once you accept that you will speak more than one version, the design question becomes containment. You want partner-specific and version-specific quirks to live at the edge of your system, not in your billing logic, your session model, or your analytics. When version handling leaks inward, every new partner becomes a cross-cutting change, and every spec revision risks a regression somewhere unexpected.
A practical rule of thumb
Choose 2.2.1 as the primary target when you are building a new roaming layer, expect hub workflows to matter, or want a cleaner long-term path. Maintain 2.1.1 compatibility when existing partners depend on it, you are entering a mature roaming ecosystem, or commercial rollout matters more than version purity. Most serious deployments end up doing both at once.
The implementation mistake to avoid
The mistake is letting version-specific payload handling leak into every internal service, so 2.1.1 and 2.2.1 differences ripple through billing, sessions, and reporting. Keep version translation at the protocol boundary and your internals stay stable as partners and specs change underneath you.
The pattern that holds up looks like this:
- Normalize the objects you care about, sessions, CDRs, locations, tariffs, into one internal model.
- Handle version translation at the protocol boundary, where messages enter and leave.
- Keep partner-specific compatibility logic isolated and named, not scattered through shared code.
This is the same discipline that lets teams run OCPP 1.6 and 2.0.1 side by side without the older protocol contaminating new work. We cover that adjacent case in our OCPI vs OCPP breakdown. If you normalize once and translate at the edge, adding a third version later is an edge change, not a platform rewrite.
How does this affect CPOs and eMSPs differently?
For CPOs, the dominant concern is partner compatibility and operational onboarding: getting locations, sessions, and CDRs flowing to each peer with minimal per-partner special-casing. For eMSPs, the harder problem is breadth, supporting many counterparties of inconsistent maturity without the cost scaling linearly with each new connection.
Both roles benefit from the same principle: version flexibility beats version idealism. A CPO that can speak whichever version a partner certified onboards faster and argues less about whose spec is correct. An eMSP with a normalized internal model can add a counterparty without reshaping its core, because the version difference is absorbed at the edge.
If you are weighing how to staff and sequence this, the OCPI Roaming guide maps the broader stack, and our team is happy to pressure-test a target-version plan with you directly on the contact page.


