A third-party POS or kitchen system can take the restaurant’s online orders (webshop, app, QR table orders, kiosk and accepted delivery-platform orders) from an order queue, mark them as received and report back when the kitchen starts, finishes or runs late. This is the same queue the Unipage till (Unipos PLUS) reads.
All calls use the restaurant’s Core API key in the
X-API-Key header. Paths are relative to
https://api.unipage.eu/{business id}/generic_polling.
How the queue works
Poll.
GET /ordersreturns every order that is waiting for the POS.Acknowledge. Once an order is stored on your side,
POST /orders/{id}with{"status": "SYNCED"}. From then on the poll no longer returns it.Report progress (optional). Tell Unipage when the kitchen starts or finishes, or when an order runs late.
- Served until acknowledged. Every poll returns every waiting order
again, without a time window or a limit, until it is acknowledged. Do not
rely on seeing an order only once: deduplicate on the order
id. - An acknowledged order does not come back by itself. Only Unipage support can put an order back in the queue (for example after a POS was replaced).
- Group-wide. For a restaurant group whose locations share one catalog,
the poll returns the waiting orders of every location of the group. The
business_idfield in an order is not the location id: do not build on it.
GET /orders
The orders waiting for the POS, as a plain JSON array (no data wrapper).
An order is in it while it:
- is placed and not finished:
statusisPLACED,CHEF_STARTEDorCHEF_COMPLETED(an unpaid online payment, a declined or a cancelled order never appears), - is a real order (top-ups and other payment-only orders are left out),
- has not been acknowledged yet.
Delivery-platform orders (Uber Eats, Deliveroo) only appear after the restaurant has accepted them.
curl https://api.unipage.eu/x94d3/generic_polling/orders \
-H "X-API-Key: $UNIPAGE_CORE_API_KEY"Polling rules
- Poll every 10 to 30 seconds, not faster. The poll has its own limit of
120 calls per minute per restaurant and IP on top of the
key limits; a
429costs you one cycle and the orders stay in the queue. - Acknowledge right after storing. Until you post
SYNCED, the order is in every response. - Never retry a
4xxunchanged in a loop. See Errors and limits.
GET /orders/{id}
One order, by its id, in the same shape as the poll, plus the payment
block. An order of another restaurant group answers 404.
The order fields
The fields an integration needs most:
| Field | Meaning |
|---|---|
id |
the order id (short hash id); use it for every call on the order |
status |
PLACED, CHEF_STARTED or CHEF_COMPLETED |
order_type, order_source |
how it is fulfilled (takeout, delivery, …) and which channel placed it |
is_paid, payment_method |
whether it is paid online already, or still has to be paid at pickup or delivery |
order_number_for_company |
the short order number shown to the customer |
takeout_delivery_timestamp |
when the customer expects the order (Unix seconds) |
delay_time_in_minutes |
the delay reported so far |
total_price, delivery_cost, service_cost |
amounts including VAT |
coupon_reduction, coupon_string |
the coupon discount and its code; a code starting with LOYALTY: is a loyalty reward |
wallet_amount |
the part paid with the customer’s wallet |
order_notes |
the customer’s note on the order |
user_firstname, user_lastname, user_email, user_phone |
the customer |
delivery_* |
the delivery address (delivery orders) |
table_hashid |
the QR table the order was placed at, if any |
is_kiosk_order, is_digital_menu_order |
placed at a kiosk, or from a QR menu at the table |
display_id, delivery_type, dropoff_notes |
delivery-platform details (Uber Eats, Deliveroo) |
created_at, updated_at |
Unix seconds |
orderItems[] |
the lines, see below |
Each line in orderItems carries item_id and the full item (the product
as in the catalog), reference (the product name),
amount, item_price, total_price, vat_rate, notes (the customer’s
remark on the line), ordered_for (in a group order: the person the line is
for), orderItemAddons (the chosen options per option group) and
discount_lines.
- Options. An option of a quantity group has
type: "AMOUNT"and an integervalue; every other option hastype: "BOOLEAN"and a booleanvalue. - Discounts are lines.
discount_lines(on lines and on options) carry the discount as Unipage calculated it (source,amount,vat_rateand the totals). Ring them as they are; do not recalculate them.
Ignore fields you do not know: fields are added over time.
Acknowledge: POST /orders/{id}
curl -X POST https://api.unipage.eu/x94d3/generic_polling/orders/k2f9a \
-H "X-API-Key: $UNIPAGE_CORE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "SYNCED"}'| Body field | Meaning |
|---|---|
status |
SYNCED (stored, take it out of the queue) or SYNCING (you are still processing it). Any other value is a 422. |
The answer is {"success": true}.
Kitchen progress: POST /orders/{id}/fulfilment
Moves the order through the kitchen statuses the restaurant also sees in Unipage:
{ "order": { "status": "CHEF_STARTED" } }Send CHEF_STARTED when the kitchen starts and CHEF_COMPLETED when the
order is ready. Only send these statuses: the value is stored as sent.
When the status becomes CHEF_STARTED, Unipage tells the customer the
kitchen has started (mail, and SMS where the restaurant has it), if the
restaurant has customer communication switched on. The answer is
{"success": true}.
Running late: POST /orders/{id}/delay
{ "minutes": 15 }minutes is a whole number from 1 to 480 (otherwise 422). Unipage stores
the delay on the order and mails the customer that the order is late. The
restaurant must have order delays enabled, otherwise the answer is 403.
The catalog
To map order lines to your own articles, read the products of the restaurant. These paths are relative to the same base URL:
| Call | Returns |
|---|---|
GET /products |
the restaurant’s products with category, prices, translations and tags. Optional updated_after (Unix seconds: only products changed since then) and category_id. |
GET /products/{id} |
one product with its option groups and options |
GET /products/info |
{"products_last_updated_at_timestamp": ...}: when a product last changed, a cheap check before you fetch |
GET /categories |
the categories, optional updated_after |
updated_after overlaps one second with the previous answer, so a product
changed in the same second as your last sync is never missed: expect to see
a product twice and upsert on its id.