Flavoso APIFundamentalsPagination and filters
Pagination and filters
Lists come in pages with a cursor. With filters, updated_since and acknowledged you reliably fetch only what is new.
Lists
Every list has the same shape: object: "list", the entries in data, plus has_more and next_cursor. limit picks 1 to 100 entries per page, the default is 25. For GET /events the cursor is called after and the default is 50.
If there is more, the response says has_more: true. Then pass next_cursor back as cursor until has_more is false. The cursor is opaque: pass it back, do not build it, do not store it.
# First page: the filters go along on every page
curl "https://api.flavoso.com/v1/orders?created_since=2026-10-03T22:00:00Z&created_until=2026-10-04T22:00:00Z&limit=100" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# has_more is true: pass next_cursor back, with the SAME filters
curl "https://api.flavoso.com/v1/orders?created_since=2026-10-03T22:00:00Z&created_until=2026-10-04T22:00:00Z&limit=100&cursor=NEXT_CURSOR" \
-H "Authorization: Bearer $ACCESS_TOKEN"Filters
Separate multiple values of a filter with commas: status=pending,confirmed.
| List | Filters | Order |
|---|---|---|
GET /orders | status, type, paid, acknowledged, updated_since, created_since, created_until, external_id | Most recently changed first; with updated_since ascending by updated_at. |
GET /reservations | status, updated_since, starts_from, starts_until | Most recently changed first; with starts_from or starts_until ascending by starts_at. |
GET /menu/products | category_id (an id or none), available, external_id, updated_since | Always ascending by updated_at. |
GET /menu/categories, GET /menu/option-groups, GET /menu/options | external_id, updated_since | Always ascending by updated_at. |
GET /events | after (also latest), types (also menu.*) | Ascending, the oldest first. |
A filter the list does not support gets 400 invalid_request with param. acknowledged refers to your app: acknowledged=false returns the orders your app has not taken over yet, without any time limit (see below). Another app sees its own state.
Pattern: everything since the last run
Without webhooks, updated_since is the way. Remember the updated_at of the last order you processed and poll with it regularly; it is in UTC and can be sent back as it is (a timestamp without a time zone gets 400). With updated_since, entries come in ascending order, the oldest change first. The same works for reservations and the menu lists, GET /menu/options included.
updated_since one minute before the last value) and detect duplicates by id and updated_at. Otherwise two changes in the same second can slip between two polls.// Everything that changed since the last run, oldest change first. listAll() as above.
const OVERLAP_MS = 60_000;
export async function pollOrders(accessToken, state) {
const since = new Date(Date.parse(state.since) - OVERLAP_MS).toISOString();
for await (const order of listAll(accessToken, "/orders", { updated_since: since })) {
if (state.seen[order.id] === order.updated_at) continue; // handled in the overlap already
await handleOrder(order); // your code; must tolerate seeing an order again
state.seen[order.id] = order.updated_at;
if (order.updated_at > state.since) state.since = order.updated_at;
}
// Forget what lies before the overlap, then persist the state for the next run
for (const [id, at] of Object.entries(state.seen)) {
if (Date.parse(at) < Date.parse(state.since) - OVERLAP_MS) delete state.seen[id];
}
await saveState(state);
}Both together are safest: the webhook is fast, the regular poll catches what got lost. Simpler still, GET /events delivers everything in order.
Pattern: only what has not been taken over yet
For a POS, the question is rarely “what changed” but “what have I not booked yet”. That is exactly what GET /orders?acknowledged=false returns. After booking, you mark the order as taken over with POST /orders/{id}/acknowledge, with your receipt number as external_id; after that it drops out of the list.
acknowledged=false has no time limit: the list holds every order your app never took over, including those from before the connection, completed and cancelled ones. So always limit it with created_since, for example with the connection's created_at from GET /me.The pattern is crash-tolerant: anything not taken over comes back on the next run. For that, your booking has to be idempotent per order. Take over every order you handled, even a cancelled one you do not book: otherwise it stays in the list and comes back on every run.
# The orders your app has not taken over yet, since the connection was made
# (created_at from GET /me). Without created_since the list has no time limit.
curl "https://api.flavoso.com/v1/orders?acknowledged=false&created_since=2026-10-04T17:40:00.000Z&limit=50" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Booked into your system as receipt R-2026-000123: acknowledge it
curl -X POST https://api.flavoso.com/v1/orders/ORDER_ID/acknowledge \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ack-ORDER_ID" \
-d '{"external_id": "R-2026-000123"}'
# Not booked, for example because it was cancelled already: acknowledge it all the same,
# otherwise it stays in the list
curl -X POST https://api.flavoso.com/v1/orders/OTHER_ORDER_ID/acknowledge \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: ack-OTHER_ORDER_ID"Time ranges
created_since and created_until limit orders by when they came in, for example for a daily export; starts_from and starts_until limit reservations by their start, for example for an evening's reservation book. Both are timestamps in UTC: the restaurant's day starts at midnight in its time zone, in Berlin in summer at 22:00:00Z of the previous day. The start counts, the end does not: created_since and starts_from include the instant, created_until and starts_until exclude it. So one day joins the next without a gap.
What is never in a list
- Unpaid online orders. An order paid online exists for the API only once the payment is confirmed, exactly as in the dashboard.
- Deleted reservations. Their deletion is reported by a final
reservation.updated.
Still unclear? Write to support@flavoso.com and include the id from X-Request-Id. It lets us find your request in the log.