Order Changes
What can still change on an order at each status, how the API refuses locked changes, replacing an order's items, cancel reasons, and the realtime events and driver pushes that announce a change.
Order Changes
Orders change after they are created: a customer adds an item, the address was wrong, the cash to collect goes up. Fleet-Ops decides what may still change from the order's status, refuses the rest, and tells the driver, the customer's app and your console what changed.
Everything on this page arrives with Fleet-Ops v0.6.72. The fix that delivers order lifecycle events on the assigned driver's channel needs core-api v1.6.69.
What can change at each status
| Stage | Order statuses | What can change |
|---|---|---|
| Open | created, pending, accepted, confirmed, preparing | Everything |
| Ready | ready, pickup_ready | Route, contact, notes and cash to collect. Items can only be removed, and the schedule can only move earlier. |
| In transit | dispatched, started, enroute, in_progress, picked_up, arrived, out_for_delivery, any driver_* status, or any custom status once the order is dispatched or started | Route (the driver is rerouted), contact, notes and cash to collect. Items and schedule are locked. |
| Finished | completed, canceled, expired, or the order config's completing or terminal activity | Nothing |
Item changes made while the order is preparing are flagged on the order (meta.kitchen_changed_at) so the kitchen notices them. Storefront applies the same stages to its own order edits.
In the console, Edit Route refuses changes to a finished order. On an order under way, a route change keeps the driver on the stop they are heading to; the current stop only moves when the route itself changed. The order's distance and time are recalculated and the public tracking page is updated.
Changes through the API
PUT /v1/orders/{id}, PUT /v1/payloads/{id} and the entity endpoints check every change against the order's stage before writing anything. A locked change is refused with 422, naming each refused field:
{
"error": "Items cannot be changed once a driver has the order.",
"locked": {
"items": "Items cannot be changed once a driver has the order."
}
}The fields are pickup, dropoff, return, waypoints, items, schedule, contact, notes and cod_amount.
Replacing an order's items
By default, entities sent with an order or payload update are added to the existing ones. Send entities_mode=replace (at the top level of an order update, or in payload) to make the list you send the order's full list:
PUT /v1/orders/order_9Kx2mQ1
Authorization: Bearer flb_live_...
{
"payload": {
"entities_mode": "replace",
"entities": [
{ "id": "entity_8Kd2mQ1", "name": "Fries", "meta": { "quantity": 1 } },
{ "name": "Lemonade", "meta": { "quantity": 2 } }
]
}
}Entities with an id are updated, entities without one are created, and existing entities left out are deleted. On a ready order, a replace that only keeps or removes existing entities counts as a removal and is allowed.
The entity endpoints follow the same rules: POST, PUT and DELETE /v1/entities are refused with 422 once the order's items are locked. Once the order is ready, deleting an entity is still allowed; adding or changing one is not.
Cash to collect
Send cod_amount at the top level of an order update or in payload. 0 is a valid amount and clears the cash to collect; it is kept rather than ignored as an empty value. PUT /v1/payloads/{id} keeps a cod_amount of 0 too.
Cancelling with a reason
DELETE /v1/orders/order_9Kx2mQ1/cancel
{ "reason": "Customer asked to cancel" }reason is optional, up to 1,000 characters. It is recorded as the details of the canceled status and sent with the cancellation notifications, including the driver's push. Fleet-Ops' internal cancel endpoint, used by the console, accepts reason too; Storefront's cancel dialog asks for one.
Realtime events
Every event uses the usual envelope:
{ "id": "event_6714…", "api_version": "v1", "event": "order.changed", "created_at": "2026-10-13 12:04:11", "data": { … } }| Event | Channels | data |
|---|---|---|
order.changed | order.{public_id}, order.{uuid}, driver.{public_id} and driver.{uuid} of the assigned driver, customer.{public_id}, company.{uuid} | id, changes (e.g. ["dropoff", "cod_amount"]), summary, dropoff (id, address, location as a GeoJSON point), cod_amount, total, currency, changed_by, changed_at |
order.driver_unassigned | driver.{public_id} and driver.{uuid} of the driver taken off the order, company.{uuid} | id, driver |
order.changed is sent for edits made through the Fleet-Ops API and console and for Storefront edits. order.driver_unassigned is sent whenever a driver is taken off an order, whether it was unassigned or given to another driver.
With core-api v1.6.69, order lifecycle events also reach the assigned driver's driverAssigned.{driver uuid} channel, which they previously missed.
See Socket Events for connecting to channels.
Driver pushes
| Push | Sent when | Data |
|---|---|---|
| Order … changed | A change concerns the assigned driver: the route, items, schedule, notes or cash to collect | { "type": "order_changed", "id": "order_…", "changes": [...] }; on Android (FCM) changes is a comma-separated string |
| Order … unassigned | The order was taken off the driver or given to another driver | { "type": "order_unassigned", "id": "order_…" } |
| Order canceled | The order was canceled | The existing cancellation push, now with reason when one was given |
In Navigator
Navigator v3 (in development) listens for these events and pushes: it shows This order changed with the summary on the order, offers Re-open navigation when the drop-off moved, removes orders that were reassigned, and asks the driver to confirm the cash collected before completing a cash order.