What it does
RESERVE_NOW asks the CPO to reserve a charging point for a given token until a stated expiry. The CPO relays it to the charger as an OCPP ReserveNow. A reserved connector rejects other drivers and typically shows a distinct status on the operator's own app and on the charger display.
It is the only OCPI command that changes availability for people who are not party to the transaction, which is why it is the one CPOs most often decline to support.
The fields
| Field | Required | Notes |
|---|---|---|
response_url | Yes | Where the CommandResult is POSTed |
token | Yes | Full Token object — the driver who may claim the reservation |
expiry_date | Yes | When the hold lapses. The single most important field. |
reservation_id | Yes | Your identifier, needed later to cancel |
location_id | Yes | The site being reserved |
evse_uid | No | Omit to reserve at location level; include to pin a specific EVSE |
authorization_reference | No | Correlation key echoed onto the resulting Session and CDR |
Location-level versus EVSE-level
Omitting evse_uid reserves “a charger at this site” rather than a specific one. This is better for the CPO, which keeps freedom to allocate, and usually better for the driver, who cares about charging rather than about bay number 3. Pin a specific EVSE only when the driver has a real reason — an accessible bay, a specific connector type, a particular power level.
REJECTED with no explanation.Worked example
POST /ocpi/2.2.1/commands/RESERVE_NOW
Authorization: Token <base64 token>
OCPI-from-country-code: IN
OCPI-from-party-id: EMS
OCPI-to-country-code: IN
OCPI-to-party-id: EFI
X-Request-ID: 3ac70f18
{
"response_url": "https://emsp.example.com/ocpi/2.2.1/commands/RESERVE_NOW/3ac70f18",
"reservation_id": "resv-2026-0811-4471",
"expiry_date": "2026-08-11T18:45:00Z",
"location_id": "LOC-ND-014",
"evse_uid": "EVSE-014-02",
"authorization_reference": "auth-4471",
"token": {
"country_code": "IN", "party_id": "EMS",
"uid": "DR-88231", "type": "APP_USER",
"contract_id": "IN-EMS-C0142",
"issuer": "Example Mobility Services",
"valid": true, "whitelist": "ALLOWED",
"last_updated": "2026-08-11T08:55:00Z"
}
}Acknowledgement, then the outcome once the charger confirms:
HTTP/1.1 200 OK
{ "data": { "result": "ACCEPTED", "timeout": 30 }, "status_code": 1000,
"timestamp": "2026-08-11T18:14:02Z" }
POST /ocpi/2.2.1/commands/RESERVE_NOW/3ac70f18
{ "result": "ACCEPTED" }The most common non-success is EVSE_OCCUPIED — someone is already plugged in. This is normal, not exceptional, and your product flow needs a graceful path for it: offer the next-nearest EVSE rather than surfacing an error.
Expiry is the whole design
expiry_date determines whether reservations are a feature or a liability. Set it too short and drivers arrive to find their hold gone. Too long and the CPO has a connector earning nothing.
What works:
- Derive it from routing, not from a constant. Estimated arrival plus a modest buffer beats a flat 30 minutes for every driver.
- Cap it at whatever the CPO permits. Many enforce a maximum and will reject or silently truncate beyond it.
- Show the driver a countdown. An expiry the driver cannot see is a support ticket in waiting.
- Cancel proactively. If the driver's ETA slips past expiry, cancel and re-reserve rather than letting it lapse silently.
When a reservation expires the connector returns to available with no notification to you. There is no “reservation expired” event in OCPI. You have to track expiry yourself.
The commercial reality
Reservations block revenue. A held connector earns nothing while it waits, and the CPO carries that cost. The consequences are worth stating plainly because they shape what you can build:
- Many CPOs simply do not support it. Expect
NOT_SUPPORTEDand treat it as a per-partner capability flag, not an error. - Some charge for reservations — a fee, or a no-show penalty. That pricing appears in the Tariffs module, not here.
- Some cap duration or concurrency to limit exposure.
- Enforcement is imperfect. A reserved bay can still be physically blocked by a car that ignored the signage. The protocol cannot solve a parking problem.
Design the driver-facing feature so that reservation is a bonus when available rather than a promise you have made on every network.
Production lessons
- Generate
reservation_idyourself and keep it. Without it you cannot cancel, and an uncancellable reservation is a partner complaint. - Track expiry locally. OCPI sends no expiry event. Your own timer is the only thing that knows.
- Prefer location-level. Higher acceptance rates and fewer
EVSE_OCCUPIEDrejections. - Cache
NOT_SUPPORTEDper partner. Stop offering reservations for networks that will never accept them. - Cancel on arrival. Once the session starts, the reservation has served its purpose — release it explicitly rather than assuming the CPO will.
- Set
authorization_reference. It is what lets you prove later that a given session came from a given reservation, which matters if no-show fees are in play.
Frequently asked questions
It asks a CPO to hold a charging point for a specific token until a stated expiry time. The CPO relays it to the charger as an OCPP ReserveNow, and the reserved connector rejects other drivers until the hold lapses or is cancelled.
Location level is usually better — omit evse_uid. It gives the CPO freedom to allocate, produces fewer EVSE_OCCUPIED rejections, and matches what drivers actually want. Pin a specific EVSE only for a real reason such as an accessible bay or a particular connector type.
The connector simply becomes available again. OCPI sends no expiry notification, so you have to track expiry yourself with your own timer and update the driver's view accordingly.
Because a reservation blocks revenue — a held connector earns nothing while it waits. Some CPOs decline it entirely, others charge a fee or a no-show penalty, and others cap duration or concurrency. Treat support as a per-partner capability.