The three-level hierarchy
The nesting is strict and the distinctions matter more than they first appear.
| Level | Represents | Key identity | Rough analogy |
|---|---|---|---|
| Location | A geographic site — a car park, forecourt or hub | id, unique per party | The building |
| EVSE | One charge point that can serve one vehicle at a time | uid, plus evse_id for display | One petrol pump |
| Connector | A physical socket with a standard, power and tariff | id, unique within its EVSE | One nozzle on that pump |
The critical rule: an EVSE serves one vehicle at a time regardless of how many connectors it has. A charge point with a CCS and a CHAdeMO socket is one EVSE with two connectors, not two EVSEs. Modelling it as two is the single most common data error in the module, and it makes an app show two available bays where only one car can charge.
Why uid and evse_id are different fields
uid is the internal identifier used in every OCPI message. evse_id is the human-readable, ISO 15118 / eMI3 style identifier printed on the charger and shown to drivers. They are separate because the printed identity can change — a charger is relabelled, a site is renumbered — without the underlying object changing. Key your storage on uid and display evse_id.
Status, and what it does not tell you
EVSE status is the field drivers actually consume, whether they know it or not.
| Status | Meaning | Show as available? |
|---|---|---|
AVAILABLE | Free and operational | Yes |
CHARGING | In use right now | No |
OCCUPIED | A vehicle is connected but not drawing power | No |
RESERVED | Held for another driver | No |
OUTOFORDER | Faulted | No — and flag it |
INOPERATIVE | Administratively disabled | No |
PLANNED | Not yet built | Only on a “coming soon” layer |
REMOVED | Decommissioned | No — delete from your map |
BLOCKED | Physically obstructed | No |
UNKNOWN | CPO cannot determine state | Show with an explicit caveat |
UNKNOWN is not a bug, and hiding it is a mistake. It usually means the charger is offline and the CPO is honestly reporting that it does not know. Suppressing those chargers makes them vanish from the map entirely; showing them as available strands drivers. Show them with a “status unavailable” marker — the honest option is also the one drivers prefer.Worked example: one location, trimmed
{
"country_code": "IN", "party_id": "EFI",
"id": "LOC-ND-014",
"publish": true,
"name": "Sector 62 Hub",
"address": "Block A, Sector 62", "city": "Noida",
"postal_code": "201309", "country": "IND",
"coordinates": { "latitude": "28.627400", "longitude": "77.372200" },
"parking_type": "PARKING_LOT",
"evses": [
{
"uid": "EVSE-014-02",
"evse_id": "IN*EFI*E014002",
"status": "AVAILABLE",
"physical_reference": "A2",
"connectors": [
{
"id": "1",
"standard": "IEC_62196_T2_COMBO",
"format": "CABLE",
"power_type": "DC",
"max_voltage": 500, "max_amperage": 125,
"max_electric_power": 60000,
"tariff_ids": ["TRF-DC-STD"],
"last_updated": "2026-08-11T09:00:00Z"
}
],
"capabilities": ["REMOTE_START_STOP_CAPABLE", "RESERVABLE"],
"last_updated": "2026-08-11T09:12:04Z"
}
],
"opening_times": { "twentyfourseven": true },
"last_updated": "2026-08-11T09:12:04Z"
}Three fields in there carry disproportionate weight:
publish—falsemeans the CPO does not want this location shown publicly. Honour it. Ignoring it is a contractual problem, not a technical one.tariff_ids— the join into the Tariffs module. Without it you cannot show a price, and a charging app that cannot show a price loses to one that can.capabilities— tells you what commands this EVSE will accept. CheckingREMOTE_START_STOP_CAPABLEbefore offering a start button saves a guaranteed failure.
Push, pull and partial updates
Locations supports both directions, and getting the combination right is what separates an accurate map from a stale one.
- Pull (
GET) with pagination, anddate_fromto fetch only what changed. This is your baseline sync and your repair mechanism. - Push (
PUT) replaces a whole object — a Location, an EVSE, or a Connector. - Push (
PATCH) updates individual fields. Status changes almost always arrive this way, because sending an entire Location object every time a bay frees up would be absurd.
PATCH is where implementations break. A PATCH may target a nested object directly — a specific connector inside a specific EVSE inside a location — and your handler has to apply it without disturbing sibling data. Naive implementations that fetch, merge in memory and write back will lose concurrent updates under load.
last_updated exists to protect you here: reject any update whose last_updated is older than what you already hold. Out-of-order delivery is normal, and without this check a delayed “available” can overwrite a newer “charging”.
Keeping the map honest
Availability is the most-read and least-trusted data in EV charging. What keeps it accurate:
- Never infer status from your own sessions. Your sessions are a subset — the CPO's other roaming partners and its own app are also using those chargers. The CPO's status is authoritative; yours is a guess.
- Age your data visibly. Status more than a few minutes old should be presented with a timestamp rather than as current fact.
- Full reconciliation on a schedule. Nightly full pulls catch the objects that pushes missed — and pushes always miss some.
- Handle
REMOVEDproperly. Decommissioned EVSEs must disappear. A phantom charger sends a driver to a site where nothing exists, which is the worst possible failure for a navigation feature. - Alert on silence, not just on errors. A CPO that has sent no location updates in 24 hours has probably broken its push integration, and you will not see an error — you will see nothing.
Frequently asked questions
A Location is a geographic site such as a car park. An EVSE is one charge point that can serve one vehicle at a time. A Connector is a physical socket on that EVSE with its own standard, power rating and tariff. A charge point offering both CCS and CHAdeMO is one EVSE with two connectors, not two EVSEs.
uid is the internal identifier used in OCPI messages and is what you should key your storage on. evse_id is the human-readable eMI3-style identifier printed on the charger and shown to drivers, which can change without the underlying object changing.
Show the charger with an explicit status-unavailable marker. UNKNOWN usually means the charger is offline and the CPO is honestly reporting that it cannot determine state. Hiding it makes real chargers vanish; showing it as available strands drivers.
Network delays and retries mean pushes do not arrive in the order they were sent. Always compare last_updated against what you already hold and reject older updates, otherwise a delayed available status can overwrite a newer charging status.
It indicates whether the CPO permits the location to be shown publicly. When it is false the location must not be displayed. Ignoring it is a contractual breach rather than a technical error.