Skip to content

POS order integration

Pull webshop, kiosk and QR orders into your own POS or kitchen system, acknowledge them and report kitchen progress.

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

  1. Poll. GET /orders returns every order that is waiting for the POS.

  2. Acknowledge. Once an order is stored on your side, POST /orders/{id} with {"status": "SYNCED"}. From then on the poll no longer returns it.

  3. 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_id field 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: status is PLACED, CHEF_STARTED or CHEF_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 429 costs 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 4xx unchanged 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 integer value; every other option has type: "BOOLEAN" and a boolean value.
  • Discounts are lines. discount_lines (on lines and on options) carry the discount as Unipage calculated it (source, amount, vat_rate and 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.

Type to search…

↑↓ navigate↵ selectEsc close