What confirm commits to
Up to this point nothing exists on the BPP's side but a conversation. confirm creates a durable order: the provider allocates capacity, the payment obligation becomes real, and the cancellation terms agreed at init start to apply.
The BAP sends back the order it received from on_init, unchanged apart from payment status. Modifying the order at this point — a different item, a different quantity — is not a confirm; it is a new transaction.
The exchange
POST https://cpo.electreefi.in/beckn/confirm
{
"context": {
"domain": "ev-charging:uei", "action": "confirm", "version": "1.1.0",
"bap_id": "emsp.example.com", "bap_uri": "https://emsp.example.com/beckn",
"bpp_id": "cpo.electreefi.in", "bpp_uri": "https://cpo.electreefi.in/beckn",
"transaction_id": "txn-4471", "message_id": "msg-9024",
"timestamp": "2026-08-11T09:00:44Z", "ttl": "PT30S"
},
"message": {
"order": {
"provider": { "id": "EFI" },
"items": [{ "id": "EVSE-014-02",
"quantity": { "selected": { "measure": { "value": "25", "unit": "kWh" } } } }],
"billing": { "name": "Example Mobility Services",
"email": "billing@emsp.example.com" },
"fulfillments": [{ "id": "FUL-1",
"customer": { "contact": { "phone": "+919136075015" } } }],
"payments": [{ "id": "PAY-1", "type": "POST-FULFILLMENT",
"status": "NOT-PAID", "collected_by": "BAP" }]
}
}
}And the response that matters:
POST https://emsp.example.com/beckn/on_confirm
{
"context": { "...": "same transaction_id", "action": "on_confirm",
"message_id": "msg-9024" },
"message": {
"order": {
"id": "ord-EFI-2026-0811-4471",
"status": "ACTIVE",
"provider": { "id": "EFI" },
"items": [{ "id": "EVSE-014-02" }],
"quote": { "price": { "currency": "INR", "value": "535.93" } },
"fulfillments": [{
"id": "FUL-1",
"state": { "descriptor": { "code": "RESERVED" } },
"authorization": {
"type": "OTP",
"token": "884213",
"valid_from": "2026-08-11T09:05:00Z",
"valid_to": "2026-08-11T09:35:00Z"
},
"stops": [{ "type": "START",
"location": { "gps": "28.6270,77.3721" },
"instructions": { "name": "Bay A2" } }]
}],
"created_at": "2026-08-11T09:00:45Z"
}
}
}
The authorization object
This is where a Beckn order becomes a physical action. The authorization block is what the driver presents at the charge point to begin charging.
| Field | Meaning |
|---|---|
type | How it is presented — OTP, QR or similar |
token | The value itself |
valid_from | Not usable before this |
valid_to | Expires here — the reservation window |
valid_to is a reservation expiry in disguise. The BPP is holding a connector until then, and it stops holding it afterwards. Show the driver a countdown, and if their arrival slips, cancel and re-book rather than letting the window lapse silently — the same discipline as an OCPI RESERVE_NOW expiry.On the BPP side, this token is what links the Beckn order to the charging session underneath. When the driver enters it, the CPO starts a session and can now correlate that session — and the CDR that follows — back to transaction_id. Without that link, reconciling Beckn orders against charging records becomes guesswork.
Idempotency is mandatory here
Every other action in the chain is safe to retry. confirm is not: a duplicate creates a second order, a second reservation, and eventually a second charge.
Retries are unavoidable — a timeout, a dropped callback, an impatient driver tapping twice. The BPP has to absorb them:
- Key idempotency on
transaction_id. A second confirm for a transaction that already has an order returns the existing order, not a new one. - Return the same
on_confirmpayload for a repeat, including the same order ID and the same authorization token. - On the BAP side, disable the button the moment confirm is sent, and keep it disabled until a callback or the TTL expires.
A BPP without confirm idempotency will produce duplicate orders in production. It is not a question of whether the retry happens.
When confirm fails
| Situation | Correct handling |
|---|---|
| EVSE taken between init and confirm | NACK or an on_confirm with an unavailable fulfilment state — offer alternatives from the original search |
| Payment authorisation declined | Fail before creating the order; do not create then cancel |
| Callback never arrives | Query with status on transaction_id before retrying — the order may exist |
| Duplicate confirm received | Return the existing order |
The third row is the one that catches teams out. A missing callback does not mean a missing order. Retrying blind is how duplicates get created even when the BPP is behaving correctly.
Production lessons
- Idempotency on
transaction_id, without exception. The single most important rule in this action. - Never retry confirm without checking status first. Silence is not failure.
- Persist the order ID and authorization token immediately on receipt. Losing the token strands a driver holding a phone at a working charger.
- Surface
valid_toprominently and treat it as a live countdown. - Store the confirmed order verbatim. It is the contract, and it is what a dispute is judged against.
- Link the order to the charging session as soon as the token is used — without that join, Beckn orders and CDRs never reconcile.
Frequently asked questions
It commits the draft order, creating a durable order on the BPP's side with an ID and a fulfilment state. The BPP allocates capacity, the payment obligation becomes real, and the cancellation terms agreed at init begin to apply.
For EV charging it is what the driver presents at the charge point to begin charging — typically an OTP or QR code, with valid_from and valid_to bounds. The valid_to timestamp is effectively a reservation expiry, since the BPP stops holding the connector after it.
Because a retry can create a second order, a second reservation and eventually a second charge. Retries are unavoidable from timeouts, dropped callbacks and repeated taps, so the BPP must key idempotency on transaction_id and return the existing order for a duplicate.
Query with the status action on the same transaction_id before retrying. A missing callback does not mean a missing order — the order may already exist, and retrying blind is how duplicates are created.