Order lifecycle
An order’s status is one of a small, stable set. Each change sends a webhook and increases the order’s version.
placedawaiting_goodssearchingdriver_assignedpicked_updelivered
Can end early: cancelledfailed
placedscheduledpicked_updelivered
Can end early: cancelledfailed
Statuses
Section titled “Statuses”| Status | Type | Meaning | Webhook |
|---|---|---|---|
placed |
both | Booked. Transport is being arranged. | order.placed |
awaiting_goods |
on demand | Waiting for your goods. The driver search has not started. | order.placed |
searching |
on demand | Goods released; Delivr is finding a driver. | order.searching |
scheduled |
window | Booked on its window’s route. | order.scheduled |
driver_assigned |
on demand | A driver accepted and is on the way to the store. | order.driver_assigned |
picked_up |
both | The driver has the goods. | order.picked_up |
delivered |
both | Handed over. proofOfDelivery has deliveredAt and, when recorded, receiverName. |
order.delivered |
cancelled |
both | Cancelled, with a reason. |
order.cancelled |
failed |
both | Could not be delivered, with a reason. |
order.failed |
placed and awaiting_goods both send order.placed: that is the moment to create the delivery in your system. An on-demand order usually shows awaiting_goods from the start, while it waits for the goods. You are billed for delivered orders and for cancellation fees, not for placing.
Reasons
Section titled “Reasons”cancelled and failed orders carry a reason:
| Reason | Ends as | Meaning |
|---|---|---|
no_driver |
failed |
No driver accepted the on-demand order in time. Your fallback may follow. |
goods_not_ready |
failed |
The goods were never reported ready, and the ready deadline and its grace passed. Your fallback may follow. |
no_capacity |
failed |
The transport could not be booked, for example the window filled up. |
undeliverable |
failed |
The transport partner could not complete the delivery. |
cancelled_by_merchant |
cancelled |
You cancelled. |
cancelled_by_delivr |
cancelled |
Delivr’s operators cancelled. |
other |
either | Anything else. |
New reasons may be added. Treat an unknown one like other.
Other events
Section titled “Other events”Some webhooks are not status changes:
| Event | When |
|---|---|
order.ready_at_changed |
You reported when the goods will be ready (readyAt). |
order.ready_overdue |
The goods are due (readyBy) and not reported ready. |
order.window_changed |
Booked on another window than quoted (previousWindow), after onWindowFull: reschedule. |
order.awaiting_recipient |
A failed order waits for the recipient to choose a window, until choiceDeadline. |
order.successor_created |
A failed order got a successor order (successorId). |
order.fallback_cancelled |
No successor follows (fallbackReason: expired or no_window). |
order.held |
An assisted checkout order is held for a pending sale. |
See Event types for the payloads.
Reading orders
Section titled “Reading orders”GET /v1/merchant/orders/{order}takes Delivr’sidor theDD-reference. It is the source of truth.GET /v1/merchant/ordersis a change feed. Page throughnextCursorto see every change once, and filter byupdatedSince,statusorexternalRef. A nightly reconciliation withupdatedSincecatches anything a webhook missed.versionincreases with every change. Keep the highest you have seen, and ignore older data.
Reconciling
Section titled “Reconciling”Webhooks can be missed, for example while your endpoint was down for longer than the retries last. Run a job, nightly or hourly, that reads every order changed since its last run and applies it with the same version check as your webhook handler.
updatedSince counts from when Delivr recorded a change, and nextCursor is absent on the last page, so keep the time each run started and overlap the next run a little:
const startedAt = new Date();const since = new Date(lastRunStartedAt.getTime() - 10 * 60_000); // overlap: applying twice is harmlesslet cursor;do { const url = new URL("/v1/merchant/orders", process.env.DELIVR_API_URL); url.searchParams.set("updatedSince", since.toISOString()); url.searchParams.set("limit", "100"); if (cursor) url.searchParams.set("cursor", cursor); const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.DELIVR_API_KEY}` } }); if (!res.ok) throw new Error(`Delivr answered ${res.status}`); const page = await res.json(); for (const order of page.items) await applyIfNewer(order); // update only when order.version is higher cursor = page.nextCursor;} while (cursor);await saveLastRunStartedAt(startedAt);Held assisted checkout orders are not listed until their sale completes; read them by id.
Times on an order
Section titled “Times on an order”| Field | Meaning |
|---|---|
createdAt, placedAt |
When the order was created and placed. |
readyBy |
On demand. When the goods are due. |
readyAt |
On demand. When the goods are (or are assumed to be) ready. |
window |
Window orders. The delivery window. |
confirmedAt |
A driver accepted (on demand), or the transport was booked (window). |
updatedAt |
The last change. |