Create a paid order
POST/orders
Sends a paid delivery, takeaway or pickup order from your application. A new order answers 201.
Before you call
- Register your source with
PUT /order-sourcefirst. X-User-IDis optional. Without it the order runs as your source and needs no open shift.X-User-IDis needed to usemanual_price, a linediscount,order_discount, a manual SKU line or a cash tender.- Whenever you send
X-User-ID, the user needs an open shift at the outlet and the cashier app permission to create sales.
Request
- POS prices every line itself: you send items and quantities, never prices, and
expected_totalis your check of the result. - Active outlet rollout cohorts use their assigned outlet's canonical current base, including active finite plans and due permanent assignments. Zero is configured; reads do not materialize plans. Legacy and first-preparing cohorts use the legacy engine.
- A live catalog item without that base answers
422 PRICE_OUTLET_PRICE_MISSING; there is no compatibility-scalar fallback in enabled mode. - Source-specific manual-price, promotion/member and idempotency rules still apply. A previously activated outlet pauses on master/company disablement; it never reverts to legacy. Both rail-pricing passes use one mode observation, revalidated in the financial transaction before writes. Committed replay retains its existing result.
- A catalog line needs
variant_idand a manual line amanual_*sku, never both. Any otherskuis refused onlines[i].sku. - A manual line needs
X-User-ID,manual_priceandproduct_name.
Behaviour
- POS writes the order, its payments and a ticket on the outlet's kitchen board in one step, and sends
order.paid. - Stock, loyalty points and the voucher are applied when the ticket is accepted: at once with
accepted_typeauto, or when the cashier accepts it withmanual(the default). - When the cashier rejects the ticket, POS records a refund to the original payment, and refunding your customer is up to you.
- An
external_order_idyour source already sent answers409 DUPLICATE_EXTERNAL_ORDER_IDwithdata.order_id, the id of the first order, whatever theIdempotency-Keyand the body (even for an order sent to another outlet of the same merchant).
Retries and idempotency
- To retry safely after a timeout or a network error, send the same
Idempotency-Keyand the same body: you get the stored answer. - An error from this call is stored under its
Idempotency-Key: after you fix the cause, send a new key.
Errors
| Status | Code | When |
|---|---|---|
| 400 | VALIDATION_FAILED | A field is wrong, with data.fields. A tender problem names tenders[i].payment_method_id (an unknown method, a method that GET /payment-methods does not list at the outlet, with code NOT_ALLOWED, or a cash tender without X-User-ID), and tenders when the tenders plus the payment fee do not add up to the total. An unknown voucher names voucher_code. A line that breaks a line rule of Request. |
| 400 | IDEMPOTENCY_KEY_REQUIRED | Idempotency-Key is missing. |
| 403 | PERMISSION_DENIED | You sent X-User-ID and the user has no cashier app permission to create sales. |
| 403 | PLAN_FEATURE_REQUIRED | The plan has no kitchen order management, or no Public API add-on. For the kitchen feature, data.reason is not_in_plan or disabled (the merchant can turn it on in Settings > Features) and data.feature is the feature key; the add-on answer has no data. |
| 403 | OUTLET_FORBIDDEN | The outlet is not allowed. |
| 409 | DUPLICATE_EXTERNAL_ORDER_ID | Your source already sent this external_order_id; data.order_id is the first order. |
| 409 | CART_REPRICED | expected_total differs from the total POS priced. data holds the POS amounts and includes total, subtotal, line_discount, tax, service_fee, payment_fee and rounding. Nothing is recorded, so send the order again with the POS total. |
| 409 | PRICE_ROLLOUT_PAUSED | New outlet price decisions are paused, including after master/company disablement. |
| 409 | PRICE_ROLLOUT_CHANGED | The rollout mode or version changed after pricing; nothing is recorded. |
| 409 | ORDER_SOURCE_NOT_REGISTERED | Your source is not registered with PUT /order-source. |
| 409 | SHIFT_NOT_OPEN | You sent X-User-ID and the user has no open shift at the outlet. |
| 409 | SALES_TYPE_DISABLED | The outlet does not sell this sales_type. |
| 409 | IDEMPOTENCY_KEY_REUSED | The key was used with another body. |
| 409 | IDEMPOTENCY_IN_PROGRESS | The first request with this key is still running. |
| 422 | INVALID_USER | X-User-ID is an unknown user. |
| 422 | KITCHEN_ACCEPT_STOCK_INSUFFICIENT | Only with accepted_type auto: stock is short, data.shortages names the items, and nothing is recorded. |
Request
Responses
- 201
- 400
- 401
- 403
- 409
- 422
The new order
Error envelope
Error envelope
Error envelope
Error envelope
Error envelope