Flavours Partner API

Endpoints

Order ListGET

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.

Order CreatePOST

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.