update_target does the work
Unlike the earlier actions, update has no fixed shape — an order has many mutable parts and the action has to say which one it is touching. update_target is a path into the order object:
update_target | Changes | Typical use |
|---|---|---|
order.fulfillments[0].state | The fulfilment state | Stop charging |
order.fulfillments[0].stops[0].time | Timing | Extend or move a reservation |
order.payments[0] | Payment | Marking payment settled |
order.items | The items | Changing requested energy — often unsupported |
Stopping a charge
The most common update in EV charging. A driver taps “stop” in a BAP app and the BPP has to end a session on hardware it operates:
POST https://cpo.electreefi.in/beckn/update
{
"context": {
"domain": "ev-charging:uei", "action": "update", "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-9041",
"timestamp": "2026-08-11T10:03:00Z"
},
"message": {
"update_target": "order.fulfillments[0].state",
"order": {
"id": "ord-EFI-2026-0811-4471",
"fulfillments": [{
"id": "FUL-1",
"state": { "descriptor": { "code": "COMPLETED" } }
}]
}
}
}The BPP ACKs, translates the request into an OCPI STOP_SESSION or a direct OCPP stop against its own charger, and calls back once the hardware has actually responded:
POST https://emsp.example.com/beckn/on_update
{
"context": { "...": "same transaction_id", "action": "on_update",
"message_id": "msg-9041" },
"message": {
"order": {
"id": "ord-EFI-2026-0811-4471",
"status": "ACTIVE",
"fulfillments": [{
"id": "FUL-1",
"state": { "descriptor": { "code": "COMPLETED" } },
"tags": [{ "descriptor": { "code": "progress" }, "list": [
{ "descriptor": { "code": "energy_delivered" }, "value": "24.550" },
{ "descriptor": { "code": "ended_at" },
"value": "2026-08-11T10:03:41Z" }
]}]
}],
"quote": { "price": { "currency": "INR", "value": "535.93" } }
}
}
}Note the same race that afflicts OCPI STOP_SESSION: the driver may have unplugged while the request was in flight. A BPP that returns “already completed” has not failed — from the driver's point of view the outcome is exactly what they asked for.
Provider-initiated updates
on_update can arrive without a preceding update. This is how a BPP reports things the BAP could not have asked about:
- Charging ended on its own — battery full, or the driver unplugged at the charger.
- A fault occurred — the session terminated abnormally.
- The final quote is ready — metering finalised, the estimate replaced by an actual.
- A reservation lapsed — the driver never arrived.
A BAP that only handles on_update as a response to its own requests will silently drop all of these. Handle unsolicited updates from day one; they are not an edge case.
update versus cancel
| Situation | Action |
|---|---|
| Driver stops a charge that already started | update — the service was delivered |
| Driver abandons a reservation before plugging in | cancel — nothing was delivered |
| Charging ends naturally | on_update from the BPP |
| Reservation expires unused | on_update, or on_cancel by BPP policy |
The dividing line is whether anything was delivered. Cancelling an order that already produced energy leaves the BPP with an unpaid charge and no clean way to bill it — the correct move is to complete it via update and let the quote reflect what was consumed.
Production lessons
- Always set
update_targetprecisely. A vague target produces a silent no-op. - Handle unsolicited
on_updatefrom the start. Natural completion arrives this way, and it is the most common update of all. - Make updates idempotent. Two stop requests should produce one stop and the same response.
- Do not treat “already completed” as an error. It is the outcome the driver wanted.
- Use update, not cancel, once energy has flowed.
- Expect a final
on_updatecarrying the settled quote and reconcile your billing against it rather than against the last live estimate.
Frequently asked questions
It names the path into the order object that is being changed, such as order.fulfillments[0].state. Because an order has many mutable parts, the target is what tells the BPP which change is intended. A vague or missing target typically produces a silent no-op.
The BAP sends an update with update_target set to the fulfilment state and the state set to COMPLETED. The BPP relays that to its charger, usually via OCPI STOP_SESSION or a direct OCPP stop, then calls back with on_update once the hardware has responded.
Yes, and it must. Charging ending naturally, a fault, a lapsed reservation, and the final settled quote all arrive as unsolicited on_update messages. A BAP that only handles on_update as a response will silently drop all of them.
Use update when energy has already been delivered, since the order needs completing and billing rather than voiding. Use cancel only when nothing was delivered, such as a reservation the driver abandoned before plugging in.