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

HeaderDirectionMeaning
AuthorizationRequestBearer <access_token>. Required, except for openapi.json and postman.json.
Content-TypeRequestapplication/json on every request with a body.
Idempotency-KeyRequestOn POST: makes a retry safe. See Idempotency.
User-AgentRequestRecommended: your app's name and version, for example ExamplePOS/4.2. Shown in the request log.
X-Request-IdResponseThe id of this request (req_…). Quote it to support.
Flavoso-Api-VersionResponseThe version date of the response.
RateLimit-Limit, RateLimit-Remaining, RateLimit-ResetResponseThe rate limit. See Rate limits.
Retry-AfterResponseOn 429: seconds until the next attempt.
Idempotent-ReplayedResponsetrue when the response is a stored replay.
Cache-ControlResponseAlways 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.

New fields, new event types and new error codes can be added at any time. Your program should ignore what it does not know rather than reject it.

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, Z or an offset like +02:00; without one the answer is 400. In a query string, write + as %2B (or use Z). Responses always come in UTC.
  • Calendar days as YYYY-MM-DD in the restaurant's local time, for example for special days and reports.
  • Times of day as HH:MM in the restaurant's local time, for example for opening hours. weekday 0 is Monday, 6 is Sunday.
  • The restaurant's time zone (IANA, for example Europe/Berlin) is in GET /me and GET /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 always null: 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 with POST /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

MethodFor
GETReading. Never changes anything.
POSTCreating (answers 201) and actions (accept, pause). Safe to retry with an Idempotency-Key.
PUTReplacing something as a whole: the menu (/menu), the opening hours (/store/hours).
PATCHChanging single fields; what is missing stays.
DELETEDeleting 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.