{"openapi":"3.1.0","info":{"title":"Kueues API","version":"1.0.0","description":"Create a ticket per order, mark it ready by your own invoice number, and receive signed webhooks for every change. JSON over HTTPS, one key per location.","contact":{"email":"developers@kueues.com"},"license":{"name":"Proprietary","url":"https://kueues.com/terms"}},"servers":[{"url":"https://kueues.com/api/v1"}],"tags":[{"name":"Tickets","description":"One ticket per order."},{"name":"Location","description":"The location (shop) behind an API key."},{"name":"Webhooks","description":"Events we POST to your endpoint."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Location API key: `kq_live_…` (live) or `kq_test_…` (test tickets, works without a subscription)."}},"schemas":{"WebhookEvent":{"type":"object","properties":{"id":{"type":"string","example":"evt_3kX9pQ2mW7zR1vB8nC4d"},"type":{"type":"string","enum":["ticket.created","ticket.claimed","ticket.ready","ticket.collected","ticket.cancelled","ticket.expired","webhook.test"]},"created_at":{"type":"string","format":"date-time"},"shop":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}},"required":["code","name"]},"data":{"type":"object","properties":{"ticket":{"$ref":"#/components/schemas/Ticket"},"test":{"type":"boolean"}},"required":["ticket"]}},"required":["id","type","created_at","shop","data"]},"Ticket":{"type":["object","null"],"properties":{"object":{"type":"string","enum":["ticket"]},"id":{"type":"string","example":"q7Rk2LmP9sXc4VbN"},"number":{"type":"integer","example":17,"description":"The number the customer sees. Restarts at 1 every business day, per queue. Not unique within a day: join on `id` or `reference`."},"status":{"$ref":"#/components/schemas/TicketStatus"},"reference":{"type":["string","null"],"example":"INV-1043","description":"Your invoice or order number."},"customer_name":{"type":["string","null"],"example":"Sam"},"note":{"type":["string","null"]},"items":{"type":"array","items":{"$ref":"#/components/schemas/TicketItem"},"description":"What to make. Filled from Square/Toast orders, or sent with POST /tickets."},"source":{"type":"string","enum":["api","counter","scan","board","square","toast"]},"test":{"type":"boolean","description":"Created with a `kq_test_` key or from the dashboard test button."},"claimed":{"type":"boolean","description":"A phone has opened the ticket."},"alerts_on":{"type":"boolean","description":"The customer turned on push or text alerts."},"customer_coming":{"type":"boolean","description":"The customer tapped \"On my way\" after the ring."},"ring_count":{"type":"integer","description":"How many times the phone has been rung since the order went ready."},"claim_url":{"type":"string","format":"uri","example":"https://kueues.com/t/7KQ2MXR9PA"},"qr_url":{"type":"string","format":"uri","example":"https://kueues.com/api/v1/qr/7KQ2MXR9PA"},"business_day":{"type":"string","example":"2026-10-10","description":"YYYY-MM-DD in the location time zone; days start at 05:00."},"queue":{"$ref":"#/components/schemas/QueueRef"},"pos":{"type":["object","null"],"properties":{"provider":{"type":"string","enum":["square","toast"]},"order_id":{"type":["string","null"]},"location_id":{"type":["string","null"]}},"required":["provider","order_id","location_id"],"description":"Set when the ticket came from a connected Square or Toast location."},"created_at":{"type":"string","format":"date-time"},"claimed_at":{"type":["string","null"],"format":"date-time"},"ready_at":{"type":["string","null"],"format":"date-time"},"collected_at":{"type":["string","null"],"format":"date-time"},"cancelled_at":{"type":["string","null"],"format":"date-time"},"expired_at":{"type":["string","null"],"format":"date-time"}},"required":["object","id","number","status","reference","customer_name","note","items","source","test","claimed","alerts_on","customer_coming","ring_count","claim_url","qr_url","business_day","queue","pos","created_at","claimed_at","ready_at","collected_at","cancelled_at","expired_at"]},"TicketStatus":{"type":"string","enum":["preparing","ready","collected","cancelled","expired"],"description":"preparing → ready → collected, or cancelled / expired (open for more than 12 hours)."},"TicketItem":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"example":"Spicy miso ramen"},"qty":{"type":"integer","minimum":1,"maximum":999,"example":2},"mods":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"maxItems":15,"example":["extra egg","no scallions"]},"note":{"type":"string","maxLength":140}},"required":["name","qty"],"description":"A line on the order, shown on the kitchen screen."},"QueueRef":{"type":["object","null"],"properties":{"id":{"type":"string","example":"Mq3vT8kLp2Wd"},"name":{"type":"string","example":"Pickup counter"},"room":{"type":["string","null"],"example":null}},"required":["id","name","room"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_input","invalid_json","bad_request","queue_required","invalid_queue","missing_api_key","invalid_api_key","unauthorized","payment_required","queue_forbidden","forbidden","ticket_not_found","not_found","invalid_transition","idempotency_conflict","ambiguous_reference","conflict","payload_too_large","unsupported_media_type","rate_limited","server_error","pos_unavailable"]},"message":{"type":"string"},"ticket_status":{"$ref":"#/components/schemas/TicketStatus"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"issue":{"type":"string"}},"required":["field","issue"]}}},"required":["code","message"],"additionalProperties":{}}},"required":["error"]},"TicketResponse":{"type":"object","properties":{"ticket":{"$ref":"#/components/schemas/Ticket"}},"required":["ticket"]},"TicketChanged":{"type":"object","properties":{"ticket":{"$ref":"#/components/schemas/Ticket"},"changed":{"type":"boolean"}},"required":["ticket","changed"]},"TicketCreated":{"type":"object","properties":{"ticket":{"$ref":"#/components/schemas/Ticket"},"created":{"type":"boolean"}},"required":["ticket","created"]},"CreateTicket":{"type":"object","properties":{"reference":{"type":"string","pattern":"^[A-Za-z0-9 _\\-./#:]{1,64}$","example":"INV-1043","description":"Invoice or order number from your system. Strongly recommended: it makes creates idempotent and lets you act on the ticket without storing our id."},"customer_name":{"type":"string","maxLength":40},"note":{"type":"string","maxLength":140,"description":"Shown to staff only."},"items":{"type":"array","items":{"$ref":"#/components/schemas/TicketItem"},"maxItems":50,"description":"Order lines for the kitchen screen."},"lang":{"type":"string","enum":["en","es","fr"],"description":"Customer page language. Defaults to the location setting."},"queue":{"type":"string","description":"Queue id from GET /api/v1/shop. Required when the location has several queues and the key is not limited to one."}},"additionalProperties":false},"TicketList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"business_day":{"type":"string"},"tickets":{"type":"array","items":{"$ref":"#/components/schemas/Ticket"}}},"required":["object","business_day","tickets"]},"Shop":{"type":"object","properties":{"shop":{"type":"object","properties":{"code":{"type":"string","example":"H7K2QM"},"name":{"type":"string","example":"Lucky Noodle Bar"},"open":{"type":"boolean"},"timezone":{"type":"string","example":"America/Chicago"},"business_day":{"type":"string"},"subscription_active":{"type":"boolean"}},"required":["code","name","open","timezone","business_day","subscription_active"]},"queues":{"type":"array","items":{"$ref":"#/components/schemas/QueueRef"}},"key":{"type":"object","properties":{"id":{"type":"string"},"test":{"type":"boolean"},"all_queues":{"type":"boolean"}},"required":["id","test","all_queues"]}},"required":["shop","queues","key"]}},"parameters":{}},"paths":{"/qr/{token}":{"get":{"operationId":"getTicketQr","tags":["Tickets"],"summary":"QR image for a claim link","security":[],"description":"PNG by default, SVG with `?format=svg`. No key needed: the token in the URL is itself the printed secret.","parameters":[{"schema":{"type":"string","pattern":"^[2-9A-HJ-NP-Z]{10}$"},"required":true,"name":"token","in":"path"},{"schema":{"type":"string","enum":["png","svg"],"default":"png"},"required":false,"name":"format","in":"query"},{"schema":{"type":"integer","minimum":64,"maximum":1024,"default":320},"required":false,"name":"size","in":"query"}],"responses":{"200":{"description":"QR image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tickets/by-reference/{reference}":{"get":{"operationId":"getTicketByReference","tags":["Tickets"],"summary":"Get a ticket by reference","description":"Prefers an open ticket, then today's, then the most recent.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9 _\\-./#:]{1,64}$","example":"INV-1043"},"required":true,"name":"reference","in":"path","description":"Percent-encode it: `#` → `%23`, `/` → `%2F`."},{"schema":{"type":"string","description":"Disambiguates a reference open in several queues."},"required":false,"description":"Disambiguates a reference open in several queues.","name":"queue","in":"query"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponse"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tickets/by-reference/{reference}/{action}":{"post":{"operationId":"updateTicketStatusByReference","tags":["Tickets"],"summary":"Change ticket status by reference","description":"Lets your POS mark an order ready using only its own invoice number.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9 _\\-./#:]{1,64}$","example":"INV-1043"},"required":true,"name":"reference","in":"path","description":"Percent-encode it: `#` → `%23`, `/` → `%2F`."},{"schema":{"type":"string","enum":["ready","collect","cancel"],"description":"`ready` rings the customer, `collect` marks it picked up (also allowed from preparing), `cancel` cancels it."},"required":true,"description":"`ready` rings the customer, `collect` marks it picked up (also allowed from preparing), `cancel` cancels it.","name":"action","in":"path"},{"schema":{"type":"string","description":"Disambiguates a reference open in several queues."},"required":false,"description":"Disambiguates a reference open in several queues.","name":"queue","in":"query"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketChanged"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tickets":{"post":{"operationId":"createTicket","tags":["Tickets"],"summary":"Create a ticket","description":"Creates a ticket for an order. Re-sending a `reference` that is still open in the queue, or the same `Idempotency-Key` within 24 hours, returns the existing ticket with `created: false`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","maxLength":255,"pattern":"^[\\x21-\\x7e]+$","description":"Up to 255 visible ASCII characters. Same key within 24 hours returns the same ticket."},"required":false,"description":"Up to 255 visible ASCII characters. Same key within 24 hours returns the same ticket.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTicket"}}}},"responses":{"200":{"description":"Already existed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketCreated"}}}},"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketCreated"}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listTickets","tags":["Tickets"],"summary":"List tickets","description":"Today's tickets plus any still open from earlier days, newest first. No pagination; up to 300.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^(preparing|ready|collected|cancelled|expired)(,(preparing|ready|collected|cancelled|expired))*$","example":"preparing,ready"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","pattern":"^[A-Za-z0-9 _\\-./#:]{1,64}$","example":"INV-1043"},"required":false,"name":"reference","in":"query"},{"schema":{"type":"string"},"required":false,"name":"queue","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":300,"default":100},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketList"}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tickets/{id}":{"get":{"operationId":"getTicket","tags":["Tickets"],"summary":"Get a ticket","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"q7Rk2LmP9sXc4VbN"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponse"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tickets/{id}/{action}":{"post":{"operationId":"updateTicketStatus","tags":["Tickets"],"summary":"Change ticket status","description":"Safe to retry: if the ticket is already in the target state the response is 200 with `changed: false`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"q7Rk2LmP9sXc4VbN"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","enum":["ready","collect","cancel"],"description":"`ready` rings the customer, `collect` marks it picked up (also allowed from preparing), `cancel` cancels it."},"required":true,"description":"`ready` rings the customer, `collect` marks it picked up (also allowed from preparing), `cancel` cancels it.","name":"action","in":"path"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketChanged"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/shop":{"get":{"operationId":"getShop","tags":["Location"],"summary":"Get the location for this key","description":"The location and the queues this key may use. Handy as a connection check.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Shop"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"ticket.created":{"post":{"operationId":"webhook_ticket_created","security":[],"tags":["Webhooks"],"summary":"ticket.created","description":"Signed with `Kueues-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">`. Respond 2xx within 10 seconds.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx."}}}},"ticket.claimed":{"post":{"operationId":"webhook_ticket_claimed","security":[],"tags":["Webhooks"],"summary":"ticket.claimed","description":"Signed with `Kueues-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">`. Respond 2xx within 10 seconds.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx."}}}},"ticket.ready":{"post":{"operationId":"webhook_ticket_ready","security":[],"tags":["Webhooks"],"summary":"ticket.ready","description":"Signed with `Kueues-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">`. Respond 2xx within 10 seconds.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx."}}}},"ticket.collected":{"post":{"operationId":"webhook_ticket_collected","security":[],"tags":["Webhooks"],"summary":"ticket.collected","description":"Signed with `Kueues-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">`. Respond 2xx within 10 seconds.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx."}}}},"ticket.cancelled":{"post":{"operationId":"webhook_ticket_cancelled","security":[],"tags":["Webhooks"],"summary":"ticket.cancelled","description":"Signed with `Kueues-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">`. Respond 2xx within 10 seconds.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx."}}}},"ticket.expired":{"post":{"operationId":"webhook_ticket_expired","security":[],"tags":["Webhooks"],"summary":"ticket.expired","description":"Signed with `Kueues-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">`. Respond 2xx within 10 seconds.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx."}}}},"webhook.test":{"post":{"operationId":"webhook_webhook_test","security":[],"tags":["Webhooks"],"summary":"webhook.test","description":"Signed with `Kueues-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">`. Respond 2xx within 10 seconds.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx."}}}}}}