Order flow
An order you create appears on the store’s point of sale and kitchen screens within a second. From there the store drives it: accept, prepare, mark ready, complete. Your job is to submit a correct order and to reflect the state back to your customer.
Create
Section titled “Create”curl -s "$API_BASE_URL/online-orders" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{ "storeId": 1, "orderType": 3, "status": 1, "customerId": 5521, "customerName": "Priya Nair", "customerPhone": "+919845012345", "note": "Leave at reception", "takenBy": "acme-web", "subtotal": 11.25, "taxAmount": 0.56, "totalAmount": 11.81, "items": [ { "id": 8841, "item": "Flat White", "qty": 2, "rate": 3.75, "itemModifiers": [14], "modifiers": [{ "ID": 41, "ModifierId": 14 }] }, { "id": 8905, "item": "Almond croissant", "qty": 1, "rate": 3.75 } ] }'storeId and items are the only required fields. The complete field table — header and
line — is on the Full API online orders page; the
payload is identical for both products.
Two fields deserve attention:
orderType—2takeout,3delivery. It selects which modifier price column applies and how the store treats the ticket.takenBy— set it to a stable identifier for your channel. It is what the merchant sees when they ask “where did this order come from?”.
{ "data": { "id": 51023, "storeId": 1, "status": 1, "orderType": 3, "totalAmount": 11.81 }}Keep the returned id. It is the only handle you have on the order.
The lifecycle
Section titled “The lifecycle”The order carries one lifecycle value plus two independent flags. Read all three — they are not a single ladder.
| Field | Values | Meaning |
|---|---|---|
status | 0 | Draft or failed — not visible to the store |
1 | Active: live in the store’s queue | |
2 | Completed | |
3 | Cancelled | |
accepted | boolean | The store confirmed the order and committed to a prep time |
foodReady | boolean | The kitchen finished it — ready for collection or handover |
The normal progression:
- Received — you create it with
status: 1. It appears on the POS and kitchen screens. - Accepted — a staff member accepts it, optionally with a prep time in minutes.
acceptedbecomes true. - Food ready — the kitchen marks it done.
foodReadybecomes true. - Completed — handed over or delivered.
statusbecomes2.
Cancellation can happen from any state before completion and sets status to 3.
Polling for status
Section titled “Polling for status”curl -s "$API_BASE_URL/online-orders/51023/status" \ -H "Authorization: Bearer $ACCESS_TOKEN"{ "data": { "orderId": 51023, "orderNo": "51023", "storeId": 1, "status": "preparing", "accepted": true, "foodReady": false, "orderDate": "2026-07-29T09:30:00.000Z", "totalAmount": 43.50 }}status is a readable summary — new, preparing, ready, completed, cancelled —
derived from the order’s lifecycle state plus the accepted and foodReady flags, using the
same buckets the merchant’s backoffice counts. Drive your customer-facing UI from it, and keep
the raw flags for anything precise.
A cadence that fits the rate limit
Section titled “A cadence that fits the rate limit”| Phase | Interval |
|---|---|
Waiting for acceptance (new) | Every 10 seconds, for up to 5 minutes |
Accepted (preparing), waiting for ready | Every 30 seconds |
| After completion or cancellation | Stop |
At 300 requests per minute per app, one order polled every 10 seconds costs 6 requests a minute. Fifty concurrent orders at that rate is your entire budget — back off as soon as an order is accepted, and stop the moment it is terminal.
Polling the list endpoint once for a store is cheaper than polling twenty orders individually:
curl -s "$API_BASE_URL/online-orders?storeId=1&status=1&limit=100" \ -H "Authorization: Bearer $ACCESS_TOKEN"Failure handling
Section titled “Failure handling”| Response | What happened | What to do |
|---|---|---|
400 with a field message | A line is malformed or an id does not exist | Fix the basket. Do not retry unchanged |
404 db.not_found | storeId, item id or customerId is not in this merchant | Re-sync your menu — it is stale |
403 partner.scope_denied | App product does not include online_orders.write | Use an Online Order or Full API app |
403 partner.grant_missing | Merchant link revoked | Stop sending; the merchant disconnected you |
429 partner.rate_limited | Too many requests this minute | Wait for X-RateLimit-Reset |
5xx | Platform error | Retry once with backoff, then surface a failure to the customer rather than duplicating |
Show the merchant’s own message to your operations team, not to the end customer — it is written for the person fixing the integration.