Flavoso APIFundamentalsRequests
Requests
Base URL, headers, JSON, money in cents, timestamps, ids, external_id, livemode and versions: the rules of every request.
Base URL
Every route lives under https://api.flavoso.com/v1. HTTPS only. The version is in the path (v1), the version date in the Flavoso-Api-Version header.
Headers
| Header | Direction | Meaning |
|---|---|---|
Authorization | Request | Bearer <access_token>. Required, except for openapi.json and postman.json. |
Content-Type | Request | application/json on every request with a body. |
Idempotency-Key | Request | On POST: makes a retry safe. See Idempotency. |
User-Agent | Request | Recommended: your app's name and version, for example ExamplePOS/4.2. Shown in the request log. |
X-Request-Id | Response | The id of this request (req_…). Quote it to support. |
Flavoso-Api-Version | Response | The version date of the response. |
RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset | Response | The rate limit. See Rate limits. |
Retry-After | Response | On 429: seconds until the next attempt. |
Idempotent-Replayed | Response | true when the response is a stored replay. |
Cache-Control | Response | Always no-store. |
curl -i -X POST https://api.flavoso.com/v1/orders/ORDER_ID/accept \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: accept-ORDER_ID" \
-H "User-Agent: ExamplePOS/4.2 (support@example.com)"JSON
Bodies are JSON objects, and so are responses. Field names are English and in snake_case. A body may be up to 64 KB (2 MB for the menu sync, PUT /menu), counted in bytes; a larger one gets 413 payload_too_large. An unknown field or query parameter gets 400 invalid_request with param, so a typo never fails silently.
Every object names its kind in object, a list is { "object": "list", "data": [ … ] }. A field without a value is null.
Money and taxes
Amounts of money are integers in the currency's smallest unit, so cents: 1290 is €12.90. The currency is next to it (currency, ISO 4217) or on the restaurant. Never decimals.
Tax rates are in basis points: 700 is 7 %, 1900 is 19 %. Prices on Flavoso are gross prices; an order additionally carries its tax split by rate (tax.lines). If the restaurant has no rate on file for a share, that line has rate_bps: null, and net and tax are null; an item's tax_rate_bps can be null as well. Book such a share as needing clarification, not as tax-free.
Time
- Timestamps follow ISO 8601 in UTC with
Z:2026-10-04T17:44:59.942Z. Send them with a time zone,Zor an offset like+02:00; without one the answer is 400. In a query string, write+as%2B(or useZ). Responses always come in UTC. - Calendar days as
YYYY-MM-DDin the restaurant's local time, for example for special days and reports. - Times of day as
HH:MMin the restaurant's local time, for example for opening hours.weekday0 is Monday, 6 is Sunday. - The restaurant's time zone (IANA, for example
Europe/Berlin) is inGET /meandGET /store.
Ids
Ids are UUIDs and never change. Exceptions: events (evt_…) and requests (req_…). An order also has a short code the guest sees, for example 3271CD; it is not meant for mapping.
Your own ids: external_id
With external_id you attach your own id to an object: your POS item number to a product, the receipt number to an order. After that you find the object by it and do not need to keep a mapping.
- 1 to 100 characters, no control characters, no space at the start or end. Counted in characters, not bytes.
- Unique per app, restaurant and kind: two products of your app in the same restaurant cannot carry the same one, a product and an order can.
- Only your app sees its ids, in the responses of the routes. For every other app the field is
null, and in events it is alwaysnull: one envelope goes to every recipient alike. - Available on categories, products, option groups, options and orders.
- Set via
PUT /menu, when creating and changing, and for orders withPOST /orders/{id}/acknowledge. - Filter with
?external_id=on the lists. - If it is already taken, Flavoso answers 409
external_id_taken. - If the object is deleted, its id disappears with it.
# Find the dish your POS knows as ART-1001
curl "https://api.flavoso.com/v1/menu/products?external_id=ART-1001" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Find the order you booked as receipt R-2026-000123
curl "https://api.flavoso.com/v1/orders?external_id=R-2026-000123" \
-H "Authorization: Bearer $ACCESS_TOKEN"livemode
livemode is in GET /me and in every event: false for a test restaurant, true for every real one. There is no separate address and there are no separate keys for it.
Versions
Within v1, only non-breaking additions arrive: new fields, new routes, new error codes, new events. Anything breaking (a field disappears or changes its meaning) comes only in a new version, and the old one keeps running for at least six months afterwards.
Flavoso-Api-Version in every response and api_version in every event name the version date, currently 2026-10-08. What changed when is listed under Changelog.
No CORS
The API is server-to-server only. Routes with data send no Access-Control-Allow-Origin, so no browser lets a foreign page read their response. A token in a browser would be a published token. Only openapi.json, postman.json and the OAuth metadata can be fetched without authentication.
Methods
| Method | For |
|---|---|
GET | Reading. Never changes anything. |
POST | Creating (answers 201) and actions (accept, pause). Safe to retry with an Idempotency-Key. |
PUT | Replacing something as a whole: the menu (/menu), the opening hours (/store/hours). |
PATCH | Changing single fields; what is missing stays. |
DELETE | Deleting or disconnecting. |
An unknown path under /v1 answers 404 not_found in the same error format.
Still unclear? Write to support@flavoso.com and include the id from X-Request-Id. It lets us find your request in the log.