Flavoso APIGuidesOrder flow
Order flow
The lifecycle of an order, its fields, tax lines, payment methods and sources.
The lifecycle
pending
new, waiting for the restaurant
confirmed
accepted
preparing
being prepared
ready
done; for delivery, ready for the driver
completed
picked up, served or delivered
cancelled cancelled, from any open status; from pending this means rejecting
Moving forward may skip statuses (confirmed → ready), moving back is not possible.
A restaurant can switch off confirmed, preparing and ready; accepting then moves to the next status it uses. Which statuses it uses is listed in GET /store under order_statuses.
The statuses
| status | Meaning | How to get there |
|---|---|---|
pending | New, waiting for the restaurant. | The order is created. |
confirmed | Accepted. | POST /orders/{id}/accept (if the restaurant uses confirmed; otherwise accept moves to its next status) |
preparing | Being prepared. | POST /orders/{id}/status with preparing |
ready | Done; for delivery, ready for the driver. | POST /orders/{id}/status with ready |
completed | Picked up, served or delivered. | POST /orders/{id}/status with completed |
cancelled | Cancelled or rejected. | POST /orders/{id}/reject (only from pending) or POST /orders/{id}/cancel |
Advancing
- Moving forward may skip statuses, for example
confirmed→ready. Moving back is not possible: 409invalid_transition. - A restaurant can switch statuses off. Which ones it uses is listed in
GET /storeunderorder_statuses; a switched-off status answers 409stage_not_used. - If the order is already at the target, it comes back unchanged with 200.
acceptmoves apendingorder to the next status the restaurant uses (if it switched offconfirmed,preparingandready,completed); an order already pastpendingcomes back unchanged, a completed or cancelled one answers 409invalid_transition. - Reject and cancel take a reason (
reason, up to 200 characters; longer gets 400) for the restaurant's audit log; the guest does not see it. - Every change works like a click in the dashboard: the guest gets their message, the team its notification, and the restaurant's audit log names your app.
# Accept (pending → confirmed)
curl -X POST https://api.flavoso.com/v1/orders/ORDER_ID/accept \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: accept-ORDER_ID"
# Advance: confirmed → preparing → ready → completed (skipping ahead is allowed)
curl -X POST https://api.flavoso.com/v1/orders/ORDER_ID/status \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "preparing"}'
# Reject an order that was not accepted yet; the reason goes to the audit log
curl -X POST https://api.flavoso.com/v1/orders/ORDER_ID/reject \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason": "Out of dough"}'
# Cancel from any open status
curl -X POST https://api.flavoso.com/v1/orders/ORDER_ID/cancel \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason": "Guest called to cancel"}'When an order exists
With payment on site, the order exists immediately. With online payment, only once the payment is confirmed: before that, it appears in no list and triggers no event. order.created arrives exactly once per order.
The fields
| Field | Meaning |
|---|---|
code | Short code the guest sees, for example 3271CD. |
type | pickup, delivery or dine_in. |
source | Where it comes from, see below. |
requested_for | Requested time of a pre-order; null means as soon as possible. |
amounts | subtotal, delivery_fee, service_fee, discount, tip, total, all in cents. |
tax | The tax per rate, see below. |
payment | method, status, paid_at. |
customer | Name, for pickup and delivery the phone number. |
delivery | For delivery, the address. |
table | At the table: id and label. |
note | The guest's note for the kitchen. Allergies are often here. |
items | Items with quantity, unit and line price, options (with id, group_id and group_name) and the tax rate frozen at order time (tax_rate_bps, null without a rate on file). |
external_id, acknowledged_at | Your app's id and takeover, see POS integration. Always null in events. |
{
"object": "order",
"id": "cce01f52-5188-410f-9659-6ce26ba9b784",
"code": "3271CD",
"type": "delivery",
"status": "pending",
"source": "storefront",
"created_at": "2026-10-04T17:44:59.942Z",
"updated_at": "2026-10-04T17:45:10.118Z",
"requested_for": null,
"currency": "EUR",
"amounts": {
"subtotal": 2490,
"delivery_fee": 250,
"service_fee": 0,
"discount": 0,
"tip": 200,
"total": 2940
},
"tax": {
"included": true,
"lines": [
{
"rate_bps": 700,
"gross": 2421,
"net": 2263,
"tax": 158
},
{
"rate_bps": 1900,
"gross": 319,
"net": 268,
"tax": 51
}
]
},
"payment": {
"method": "online",
"status": "paid",
"paid_at": "2026-10-04T17:45:10.000Z"
},
"customer": {
"name": "Alex",
"phone": "+49 151 00000000"
},
"delivery": {
"address": "Musterstraße 1",
"postal_code": "10115",
"city": "Berlin"
},
"table": null,
"note": "Please ring twice",
"external_id": null,
"acknowledged_at": null,
"items": [
{
"id": "e9c0ce66-7f7f-42cf-a4bf-7d66f87768c1",
"product_id": "303b87c9-58a3-4644-9a8b-2841cc1f89d6",
"name": "Pizza Margherita",
"quantity": 2,
"unit_price": 1100,
"line_total": 2200,
"tax_rate_bps": 700,
"options": [
{
"id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b",
"name": "Extra cheese",
"price_delta": 150,
"group_id": "8e7d6c5b-4a39-4281-b0f9-e8d7c6b5a4f3",
"group_name": "Extras"
}
]
},
{
"id": "0d1e2f3a-4b5c-4d6e-8f70-81a2b3c4d5e6",
"product_id": "6a7b8c9d-0e1f-4a2b-9c3d-4e5f6a7b8c9d",
"name": "Cola 0,33 l",
"quantity": 1,
"unit_price": 290,
"line_total": 290,
"tax_rate_bps": 1900,
"options": []
}
]
}Tax lines
tax splits the order's gross amount by tax rate: { "included": true, "lines": [{ "rate_bps", "gross", "net", "tax" }] }. The lines cover items, delivery fee and service fee, by the same calculation as the receipt and the DATEV export. The tax is included in the price (included: true).
In the example above: pizza at 7 %, cola at 19 %, the delivery fee split proportionally between both. The tip is not revenue and appears in no line.
If the restaurant has no rate on file for a share, that share is in a line with rate_bps: null, and net and tax are null there, not 0. Book it as needing clarification, not as tax-free.
Payment methods
| payment.method | payment.status | Meaning |
|---|---|---|
online | paid | Paid online. The order only exists from here on. |
on_site | open | Payment on site, still open: cash or card at pickup, delivery or at the table. |
online | open | Never visible: an online order exists for the API only once it is paid. Payments on site are not recorded in Flavoso, so on_site stays open. |
With online payment the money goes directly to the restaurant; Flavoso is never the payee. The tip is in amounts.tip and included in total.
Sources
| source | From |
|---|---|
storefront | The restaurant's ordering page, including when embedded on its website. |
table | The QR code at the table. |
app | The Flavoso app for guests. |
Guest data
An order contains only what is needed to hand it over: the name, for pickup and delivery the phone number, for delivery the address. Never the e-mail address, never the guest account. At the table the phone number is left out as well. See Privacy.
Still unclear? Write to support@flavoso.com and include the id from X-Request-Id. It lets us find your request in the log.