Order Create
Creates an order. On a branch whose waiter.qr.enabled is on, in a table section whose qr_enabled is on, a body from a customer carrying a table_id is a QR self-order (waiter contract §15.2, W13): the table's open order is reused when it has one and created WAITING / DINING with no owner when it has not, and the lines become a round on that order with status = PENDING — priced at once, so the guest sees a total, but held back from the kitchen until a waiter sends ROUND_ACCEPT (or at once when waiter.qr.auto_accept is on). The response is the order with rounds[], which on a reused table is the table's existing order and not a second one. A pending round the waiter never answers is auto-rejected after waiter.qr.pending_minutes with reject_reason = EXPIRED. A QR round on a table whose open order ZATCA has already reported (order_zatcas.is_synced 1 or 2) answers 423 order.money_locked (data.error.code, data.money_lock) and adds no round. A branch or section with QR off, and every caller that is not a customer, keep today's behaviour exactly: a new order per submission and no round. Gated by the branch cutover switch (branch_settings.waiter.table_service, contract §15.7): a staff body with type = DINING and a table_id answers 409 waiter.table_service_off — data.error.code, with the branch's current value at data.table_service — on a branch set to SETTLE_ONLY or OFF, because opening a table belongs to the waiter app there. A DINING body without a table_id is allowed at every value, and a guest's QR submission is never refused by the switch. Off-hours (FP-1083): on a branch that uses its schedule as the workday, a caller with no open attendance (guest QR — a first order or another round on the table's order —, online, admin/merchant) is refused outside the trading window, i.e. before the opening (the early check-in window is for cashier prep only) or once closing plus overtime has passed: 409 branch.closed at data.error.code, with data.next_opening_at (epoch ms) and data.timezone (the branch's IANA zone) for the client's "closed, opens at" note. A branch with no open day at all is never refused. An order by a cashier with an open attendance, POST /v2/sync/orders and /v2/orders/calc are never refused.
Authorization
API-TOKEN Your partner API key. Send it in the API-TOKEN header on every request.
In: header
Header Parameters
API contract version to target. See the Changelog for what changed in each version.
"2.0.0""2.3.0" | "2.2.0" | "2.1.0" | "2.0.0"Request Body
application/json
"MODEL" | "ID"Must match an existing stored value.
Must match an existing stored value.
"ADMIN_APP" | "ADMIN_WEB" | "LANDING_APP" | "LANDING_WEB" | "GRUBTECH" | "ODOO""TAKE_AWAY" | "DINING" | "DRIVE_THROUGH" | "DELIVERY" | "PICKUP"This field is required when type is DINING.
Must be at least 1 character. Must not be greater than 64 characters.
Must have at least 1 items.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://api.flavours.sa/dev/api/v2/orders" \ -H "X-API-Version: 2.3.0" \ -H "Content-Type: application/json" \ -d '{ "market_id": "ut", "branch_id": "vel", "source": "ODOO", "type": "PICKUP", "products": [ [] ] }'{
"meta": {
"code": 401,
"status": "error",
"message": "Unauthenticated."
},
"data": null
}{
"meta": {
"code": 403,
"status": "error",
"message": "Unauthorized."
},
"data": null
}{
"meta": {
"code": 404,
"status": "error",
"message": "Resource not found."
},
"data": null
}{
"meta": {
"code": 409,
"status": "error",
"message": "This branch is closed. It opens at Tue 09:00."
},
"data": {
"next_opening_at": 1791266400000,
"timezone": "Asia/Riyadh",
"error": {
"code": "branch.closed",
"message": "This branch is closed. It opens at Tue 09:00."
}
}
}{
"meta": {
"code": 500,
"status": "error",
"message": "Internal server error."
},
"data": null
}Update Branch POST
Update an existing branch.
Order List GET
Orders of the caller's market and branch, paginated, with the standard `sort`, `key_by`, `includes[]` and `filter.*` parameters. Rows that tie on the `sort` key (or on `created_at`, newest first, when no `sort` is sent) are ordered by `id` in the same direction, so consecutive pages never repeat or skip an order. Every row carries `workday` (the business day the order was stamped with, `YYYY-MM-DD` in the branch timezone; additive, at every `X-API-Version`). **Workday range (FP-1083):** `filter.workday_min` / `filter.workday_max` (`Y-m-d`, inclusive, at most 366 dates) are sent **together with** `filter.created_at_min/max` (or the legacy `created_at_after/before`). With `WORKDAY_ENABLED` on, a branch whose workday switch is ON is then bounded by `orders.workday` (an order rung up after midnight or in overtime belongs to the workday it was taken in) and OFF branches keep the epochs; the response adds `meta.workday` (per-branch period, orders/sales and per-workday rows: the `/v2/reports/overview` block). The live list (`filter.start_at` + `filter.close_at`) and `filter.period_type` / `time_period` win over the range and ignore the workday dates. Without the workday params the response is unchanged. `filter.attendance_id` matches the orders of a shift: on a workday branch by the shift's `workday` (so overtime orders stay with their shift), otherwise by the shift's start and close times.