Why hubs exist
Direct OCPI connections scale badly. Ten parties who all want to roam with each other need forty-five connections; thirty parties need four hundred and thirty-five. Each one is a separate registration, a separate credential to rotate, and a separate integration to certify.
A hub collapses that. Every party connects once, to the hub. The hub routes messages between them using the OCPI-to-country-code and OCPI-to-party-id headers. From your side the integration count stops growing as the network does.
The trade-off is that you lose direct visibility. When you send a request to a partner through a hub, a failure could be the hub, the partner, or the link between them. HubClientInfo restores some of that visibility.
The ClientInfo object
Small, and deliberately so — it is a status feed, not a directory of capabilities.
| Field | Meaning |
|---|---|
party_id | Three-character party identifier |
country_code | Two-character country code; with party_id forms the unique key |
role | CPO, EMSP, HUB, NSP, SCSP or OTHER |
status | CONNECTED, OFFLINE, PLANNED or SUSPENDED |
last_updated | When this status last changed — the field that tells you whether to trust it |
The four statuses
| Status | Meaning | What you should do |
|---|---|---|
CONNECTED | Party is online and reachable through the hub | Route normally |
OFFLINE | Registered but currently unreachable | Stop routing; queue or fail fast |
PLANNED | Registration agreed but not yet live | Do not route; expect it to appear |
SUSPENDED | Deliberately disabled — commercial or compliance reasons | Do not route; escalate rather than retry |
The distinction between OFFLINE and SUSPENDED matters operationally. OFFLINE is a transient technical condition you should expect to resolve itself. SUSPENDED is a deliberate act — usually a contract or compliance issue — and no amount of retrying will change it. Treating them identically means your on-call gets paged for a commercial dispute.
Worked example
Pulling the full client list from a hub:
GET /ocpi/2.2.1/hubclientinfo?limit=100
Authorization: Token <base64 token>
{
"data": [
{ "party_id": "EFI", "country_code": "IN", "role": "CPO",
"status": "CONNECTED", "last_updated": "2026-08-11T08:40:11Z" },
{ "party_id": "GRN", "country_code": "IN", "role": "CPO",
"status": "OFFLINE", "last_updated": "2026-08-11T09:02:47Z" },
{ "party_id": "EMS", "country_code": "IN", "role": "EMSP",
"status": "CONNECTED", "last_updated": "2026-08-10T17:21:03Z" },
{ "party_id": "NEW", "country_code": "IN", "role": "CPO",
"status": "PLANNED", "last_updated": "2026-08-09T11:00:00Z" }
],
"status_code": 1000,
"timestamp": "2026-08-11T09:15:00Z"
}And a push from the hub when one party's status changes — note that a push carries a single object, not the full list:
PUT /ocpi/2.2.1/hubclientinfo/IN/GRN
Authorization: Token <base64 token>
{
"party_id": "GRN",
"country_code": "IN",
"role": "CPO",
"status": "CONNECTED",
"last_updated": "2026-08-11T09:18:22Z"
}
Push and pull, and why you need both
Like most OCPI modules, HubClientInfo supports both directions. The hub pushes status changes as they happen, and you can pull the full list on demand. The correct implementation uses both:
- Push gives you low-latency updates, but pushes get lost. A missed push leaves you with a stale status and no indication anything is wrong.
- Pull on a schedule — every few minutes is ample — reconciles your view against the hub's and repairs the drift.
Relying on push alone is the common failure. It works perfectly in testing, where nothing is dropped, and then diverges quietly in production.
Using status without hurting drivers
The obvious use is routing: skip parties marked OFFLINE and fail immediately instead of waiting for a timeout. That is correct, but it needs care at the edges.
- Do not hide locations because a CPO is briefly offline. A driver planning a trip cares that a charger exists. Showing it with a “live status unavailable” indicator is better than making it vanish and reappear.
- Do harden the commands path. Sending
START_SESSIONto an offline CPO produces a driver standing at a charger watching a spinner. Fail fast with a clear message instead. - Check
last_updatedbefore trusting a status. ACONNECTEDflag from six hours ago is not evidence of anything. Treat stale entries as unknown. - Never cache status without expiry. The whole point is that it changes.
Production lessons
- Keep a status history, not just current state. When a partner disputes an outage window, an append-only log of their status transitions settles it. This is also the first artefact a compliance audit asks for.
- Alert on your own status. The hub is reporting on you too. If you appear
OFFLINEto the network, you want to know from your own monitoring, not from a partner's email. - Distinguish
SUSPENDEDin your alerting. It is a commercial condition, not an incident. Route it to account management, not to engineering on-call. - Do not treat the hub as infallible. Hub status reflects the hub's view of a party, which can itself be stale. Reconcile against your own request success rates — a party marked
CONNECTEDthat fails every call is still broken. - Handle parties appearing and disappearing. New
PLANNEDentries arrive without warning as the hub onboards. Your ingestion has to tolerate parties you have never seen.
Frequently asked questions
It is how an OCPI hub publishes the connectivity status of every party connected to it. Each ClientInfo object carries a party's country code, party ID, role, status and the time that status last changed.
CONNECTED means online and reachable. OFFLINE means registered but currently unreachable. PLANNED means registration is agreed but not yet live. SUSPENDED means deliberately disabled, usually for commercial or compliance reasons.
Direct connections scale as N squared — thirty parties roaming with each other would need 435 separate integrations. A hub means each party integrates once and the hub routes between them using the OCPI-to-country-code and OCPI-to-party-id headers.
No. A driver planning a route still needs to know the charger exists. Show it with a live-status-unavailable indicator instead. Do use the status to fail fast on commands, where sending START_SESSION to an offline CPO leaves a driver waiting at a charger.
OFFLINE is a transient technical condition that should resolve itself, so retrying is reasonable. SUSPENDED is a deliberate administrative act, usually contractual or compliance related, and retrying will never help — it needs escalation rather than an engineering page.