Skip to content

Orders

Orders are created on Quiqqy and pushed to you; you report progress back. Quiqqy owns the customer, payment and (for delivery) the courier — your POS owns the kitchen. The four calls below are everything you send.

StepOrder statusMoved byYour POS action
CreatedpendingQuiqqy — you receive order.createdAccept or deny within the SLA
AcceptedconfirmedYou — POST /pos/orders/:orderId/acceptOptionally send estimated_prep_time_minutes
PreparingpreparingYou — POST /pos/orders/:orderId/statusWhen the kitchen starts
ReadyreadyYou — POST /pos/orders/:orderId/readyFood is ready for pickup / courier handoff
Out for deliveryout_for_deliveryQuiqqy (courier flows) or you (self-delivery, via status)Delivery orders only; pickup ends at ready
CompleteddeliveredQuiqqy — you receive order.deliveredClose the ticket
CancelledcancelledEither side — you via cancel, Quiqqy via order.cancelledVoid the ticket, release stock
FailedfailedQuiqqyInjection or payment failure; nothing to do

Transitions only move down the ladder. Skipping a rung (confirmed straight to ready) is allowed; moving backwards returns 409 order.invalid_transition.

  • Acknowledge the webhook in under 10 seconds — that is the delivery timeout, and slow acknowledgements cause duplicate deliveries.
  • Accept or deny within 5 minutes of order.created. Past that, the customer sees a delay warning and Quiqqy support may cancel on your behalf. Both outcomes count against your quality metrics.
  • Send prep time when the POS knows it. estimated_prep_time_minutes drives the customer’s ETA and courier dispatch timing. An accurate 25 beats a silent default.

If the integration has auto_accept_orders: true, Quiqqy confirms each order the moment it is created — you still receive order.created and drive the rest of the ladder.

Terminal window
curl -s https://auth.quiqqy.ai/api/v2/pos/orders/ord_9d31f2/accept \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "estimated_prep_time_minutes": 25 }'
200 OK
{
"status": "success",
"order_id": "ord_9d31f2",
"order_status": "confirmed",
"estimated_prep_time_minutes": 25
}

POST /pos/orders/:orderId/status with the new status and an optional customer-visible message:

{ "status": "preparing", "message": "In the oven" }

status accepts pending, confirmed, preparing, ready, out_for_delivery, delivered, cancelled, failed — in practice you send preparing, and out_for_delivery/delivered only for self-delivery.

POST /pos/orders/:orderId/ready is the no-body shortcut for the most common transition — the KDS bump:

Terminal window
curl -s -X POST https://auth.quiqqy.ai/api/v2/pos/orders/ord_9d31f2/ready \
-H "Authorization: Bearer $ACCESS_TOKEN"

When the order cannot be fulfilled, cancel it with a free-text reason (the customer sees it) and a structured reason_code from the denial enumITEM_OUT_OF_STOCK, STORE_CLOSED, POS_OFFLINE, CAPACITY, PRICE_MISMATCH, OTHER:

Terminal window
curl -s https://auth.quiqqy.ai/api/v2/pos/orders/ord_9d31f2/cancel \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"reason": "Burrata is finished for the day",
"reason_code": "ITEM_OUT_OF_STOCK"
}'

The customer is refunded automatically, and a structured reason_code lets Quiqqy remediate — ITEM_OUT_OF_STOCK prompts an availability resync so the next customer never sees the dead items. The best denial, though, is the one that never happens: keep availability current.

Each line in an order payload carries the external_id you pushed at menu sync (and variant_external_id for SKU lines, and external_id per selected option). Ring up orders off those ids — never off product_name or Quiqqy’s internal product_id. Ids are scoped to your app: lines synced by another integration, or never pushed from your system, arrive with external_id: null — fall back to product_name for those. Full payloads: Webhook events and Sample payloads.