{"openapi":"3.1.0","jsonSchemaDialect":"https://spec.openapis.org/oas/3.1/dialect/base","info":{"title":"Smart Pager POS API","version":"1.0.0","summary":"Link invoices to QR pager cards, alert customers and close orders from your POS.","description":"Smart Pager replaces buzzer pagers at 99Grill and Chicken Dip with printed QR cards. This API lets a point-of-sale system do the cashier's part: link an invoice to a pager card, mark it ready (the customer's phone rings), ring again, and close it when collected so the card can be reused safely.\n\n**Authentication**: `Authorization: Bearer pgr_<prefix>_<secret>`. Keys are scoped to one branch or a whole brand; other branches answer 404.\n**Idempotency**: send `Idempotency-Key` on POST requests (required to create orders). Same key + same request replays the stored successful response for 7 days; failed requests are not stored.\n**Concurrency**: single-order responses carry `ETag: \"<version>\"`; send `If-Match` on commands to get 412 instead of acting on a changed order.\n**Rate limit**: 600 requests per minute per integration.\n**Errors**: `application/problem+json` (RFC 9457) with a stable `code`.\n**Webhooks**: signed with HMAC-SHA256; see the webhooks section. Reconcile with `GET /events`.\n\nFull guide: https://smart-pager-production.up.railway.app/docs/api"},"externalDocs":{"description":"Developer guide","url":"https://smart-pager-production.up.railway.app/docs/api"},"servers":[{"url":"https://smart-pager-production.up.railway.app/api/v1","description":"Smart Pager"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Meta","description":"Discovery, the OpenAPI document and the calling key."},{"name":"Branches","description":"Branches this key can access."},{"name":"Pagers","description":"Printed QR pager cards and their live status."},{"name":"Orders","description":"Create, read and list orders (one order = one invoice on one pager card)."},{"name":"Order commands","description":"Lifecycle commands addressed by order id."},{"name":"Invoice commands","description":"The same commands addressed by branch + invoice number, for POS systems that only know the invoice."},{"name":"Events","description":"Ordered, replayable feed of order events (webhook reconciliation)."},{"name":"Webhooks","description":"Events Smart Pager POSTs to your endpoint."}],"paths":{"/":{"get":{"operationId":"getApiIndex","tags":["Meta"],"summary":"API index","description":"Entry point with links to the documentation, the OpenAPI document and the main collections. No authentication.","security":[],"responses":{"200":{"description":"Links","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiIndex"},"example":{"name":"Smart Pager POS API","version":"1.0.0","documentation":"https://smart-pager-production.up.railway.app/docs/api","openapi":"https://smart-pager-production.up.railway.app/api/v1/openapi.json","authentication":"Authorization: Bearer pgr_<prefix>_<secret>","links":{"me":"https://smart-pager-production.up.railway.app/api/v1/me","branches":"https://smart-pager-production.up.railway.app/api/v1/branches","events":"https://smart-pager-production.up.railway.app/api/v1/events"}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1\""}]}},"/openapi.json":{"get":{"operationId":"getOpenApiDocument","tags":["Meta"],"summary":"OpenAPI document","description":"This API described as OpenAPI 3.1, including the webhooks. No authentication; CORS enabled.","security":[],"responses":{"200":{"description":"OpenAPI 3.1 document","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"},"example":{"openapi":"3.1.0","info":{"title":"Smart Pager POS API","version":"1.0.0"}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1/openapi.json\""}]}},"/me":{"get":{"operationId":"getMe","tags":["Meta"],"summary":"Calling key","description":"Returns the integration behind the API key, what it can access and its scopes. Use it to verify a new key.","responses":{"200":{"description":"The calling integration","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"},"example":{"integration":{"id":"c4a1e7d2-8b3f-4a6e-9c5d-0e1f2a3b4c5d","name":"Foodics bridge (7th Circle)"},"scope":{"type":"branch","brand_id":"5d2e9f0a-7c1b-4e3d-8a6f-1b2c3d4e5f60","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50"},"scopes":["branches:read","pagers:read","orders:read","orders:create","orders:ready","orders:ring","orders:collect","orders:cancel","events:read"],"rate_limit":{"limit":600,"window_seconds":60}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1/me\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\""}]}},"/branches":{"get":{"operationId":"listBranches","tags":["Branches"],"summary":"List branches","description":"Branches this key can access: one for a branch key, every branch of the brand for a brand key.\n\nRequired scope: `branches:read`.","x-required-scope":"branches:read","responses":{"200":{"description":"Accessible branches, ordered by code","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchList"},"example":{"data":[{"id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","code":"jo-7th-circle","brand":{"slug":"99grill","name_en":"99Grill","name_ar":"99 جريل"},"name_en":"7th Circle","name_ar":"الدوار السابع","country_code":"JO","timezone":"Asia/Amman","enabled":true}]}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1/branches\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\""}]}},"/branches/{branch}":{"get":{"operationId":"getBranch","tags":["Branches"],"summary":"Get a branch","description":"One branch by code or UUID.\n\nRequired scope: `branches:read`.","x-required-scope":"branches:read","parameters":[{"$ref":"#/components/parameters/Branch"}],"responses":{"200":{"description":"The branch","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Branch"},"example":{"id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","code":"jo-7th-circle","brand":{"slug":"99grill","name_en":"99Grill","name_ar":"99 جريل"},"name_en":"7th Circle","name_ar":"الدوار السابع","country_code":"JO","timezone":"Asia/Amman","enabled":true}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1/branches/jo-7th-circle\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\""}]}},"/branches/{branch}/pagers":{"get":{"operationId":"listPagers","tags":["Pagers"],"summary":"List pager cards","description":"Every pager card of the branch with its live status: free, preparing, ready or disabled. Use it to offer only free cards in your POS. QR tokens are never exposed.\n\nRequired scope: `pagers:read`.","x-required-scope":"pagers:read","parameters":[{"$ref":"#/components/parameters/Branch"}],"responses":{"200":{"description":"Pager cards ordered by number","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagerList"},"example":{"branch":{"id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","code":"jo-7th-circle"},"data":[{"number":1,"label":null,"enabled":true,"status":"free","order_id":null},{"number":7,"label":null,"enabled":true,"status":"preparing","order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"},{"number":8,"label":"Terrace","enabled":false,"status":"disabled","order_id":null}]}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1/branches/jo-7th-circle/pagers\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\""}]}},"/branches/{branch}/orders":{"post":{"operationId":"createOrder","tags":["Orders"],"summary":"Link an invoice to a pager","description":"Creates an order: links the invoice to the pager card the cashier hands to the customer. The customer who scans that card follows this order. Requires an Idempotency-Key. Attaching customer.phone requires the contacts:write scope and the customer's consent; the number is encrypted at rest and never returned. pickup_code is only present when the branch requires customers to enter a code; print it on the receipt.\n\nRequired scope: `orders:create`.","x-required-scope":"orders:create","parameters":[{"$ref":"#/components/parameters/Branch"},{"$ref":"#/components/parameters/IdempotencyKeyRequired"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderRequest"},"example":{"pager_number":7,"invoice_number":"A-1042","external_id":"pos-88231"}}}},"responses":{"201":{"description":"Order created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Location":{"$ref":"#/components/headers/Location"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"preparing","version":1,"ring_count":0,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":null,"acknowledged_at":null,"last_ring_at":null,"closed_at":null,"close_reason":null,"expires_at":"2026-10-18T00:04:11.512Z","has_phone":false,"customer":{"linked_devices":0,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, idempotency_key_required, invalid_idempotency_key","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_key_required":{"summary":"Creating an order requires an Idempotency-Key header.","value":{"type":"about:blank#idempotency_key_required","title":"This request requires an Idempotency-Key header","status":400,"code":"idempotency_key_required","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: pager_busy, invoice_active, pager_disabled, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"pager_busy":{"summary":"The pager card already has an active order. Collect or cancel that order first, or use another card.","value":{"type":"about:blank#pager_busy","title":"This pager is already assigned to an active order","status":409,"code":"pager_busy","retryable":false,"details":{"pager_number":7,"invoice_number":"A-1039"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invoice_active":{"summary":"The invoice (or your external_id) already has an active order in this branch. details.pager_number shows which card holds it.","value":{"type":"about:blank#invoice_active","title":"This invoice is already linked to an active pager","status":409,"code":"invoice_active","retryable":false,"details":{"invoice_number":"A-1042","pager_number":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"pager_disabled":{"summary":"The pager card was disabled by an admin (lost or damaged). Use another card.","value":{"type":"about:blank#pager_disabled","title":"This pager is disabled","status":409,"code":"pager_disabled","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/branches/jo-7th-circle/orders\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: 0b5e3a0c-6f1d-4d8e-9a77-2c1f3e4d5b6a\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"pager_number\":7,\"invoice_number\":\"A-1042\",\"external_id\":\"pos-88231\"}'"}]},"get":{"operationId":"listOrders","tags":["Orders"],"summary":"List orders","description":"Orders of a branch, newest first, with cursor pagination. status=active (default) returns orders on a pager right now; closed returns collected, cancelled and expired ones.\n\nRequired scope: `orders:read`.","x-required-scope":"orders:read","parameters":[{"$ref":"#/components/parameters/Branch"},{"$ref":"#/components/parameters/OrderStatusFilter"},{"$ref":"#/components/parameters/InvoiceFilter"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of orders","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderList"},"example":{"data":[{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"preparing","version":1,"ring_count":0,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":null,"acknowledged_at":null,"last_ring_at":null,"closed_at":null,"close_reason":null,"expires_at":"2026-10-18T00:04:11.512Z","has_phone":false,"customer":{"linked_devices":0,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}],"next_cursor":null,"has_more":false}}}},"400":{"description":"Bad request: invalid_cursor","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_cursor":{"summary":"The pagination cursor was altered or truncated. Pass next_cursor back exactly as received.","value":{"type":"about:blank#invalid_cursor","title":"Malformed cursor; pass next_cursor back unchanged","status":400,"code":"invalid_cursor","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1/branches/jo-7th-circle/orders?status=active&limit=20\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\""}]}},"/orders/{id}":{"get":{"operationId":"getOrder","tags":["Orders"],"summary":"Get an order","description":"One order by id. The ETag header carries its version for If-Match.\n\nRequired scope: `orders:read`.","x-required-scope":"orders:read","parameters":[{"$ref":"#/components/parameters/OrderId"}],"responses":{"200":{"description":"The order","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"ready","version":2,"ring_count":1,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":"2026-10-17T18:11:42.020Z","acknowledged_at":null,"last_ring_at":"2026-10-17T18:11:42.020Z","closed_at":null,"close_reason":null,"expires_at":"2026-10-17T20:11:42.020Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\""}]}},"/orders/{id}/ready":{"post":{"operationId":"readyOrder","tags":["Order commands"],"summary":"Mark ready","description":"Marks the order ready and alerts every device following it (the open order page rings). When the order has a phone number (customer.phone) and the branch uses phone alerts, the customer also gets an automated voice call right away (or one SMS on SMS branches), even with the page closed; no tap is needed. Idempotent: calling it on an order that is already ready returns 200 with the unchanged order and never alerts again. Use ring for that.\n\nRequired scope: `orders:ready`.","x-required-scope":"orders:ready","parameters":[{"$ref":"#/components/parameters/OrderId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/IfMatch"}],"responses":{"200":{"description":"The order after the command","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"ready","version":2,"ring_count":1,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":"2026-10-17T18:11:42.020Z","acknowledged_at":null,"last_ring_at":"2026-10-17T18:11:42.020Z","closed_at":null,"close_reason":null,"expires_at":"2026-10-17T20:11:42.020Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, invalid_idempotency_key, invalid_precondition","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_precondition":{"summary":"If-Match is not a single entity tag. Send the ETag you received, e.g. \"3\".","value":{"type":"about:blank#invalid_precondition","title":"If-Match must be a single entity tag such as \"3\"","status":400,"code":"invalid_precondition","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: invalid_transition, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_transition":{"summary":"The command does not apply to the order's current status, for example ringing an order that is still preparing or marking a collected order ready.","value":{"type":"about:blank#invalid_transition","title":"Cannot ring an order that is preparing","status":409,"code":"invalid_transition","retryable":false,"details":{"status":"preparing","action":"ring"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"412":{"description":"Precondition failed: version_conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"version_conflict":{"summary":"If-Match did not match the order's current version. details.current_version holds the latest version; re-read the order and decide again.","value":{"type":"about:blank#version_conflict","title":"The order changed since you last loaded it","status":412,"code":"version_conflict","retryable":false,"details":{"current_version":3},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10/ready\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: 3c9e1f7a-52d4-4b8e-a1f0-6d2b7c8e9a41\""}]}},"/orders/{id}/ring":{"post":{"operationId":"ringOrder","tags":["Order commands"],"summary":"Ring again","description":"Alerts the customer again while the order is ready. Rings must be at least 30 s apart (429 ring_too_soon with retry_after) and an order alerts at most 6 times in total, automatic reminders included (409 ring_limit). On branches that call, each ring also places one more voice call to the order's phone number (not while the previous call may still be ringing or talking), at most 3 calls per order including the automatic one.\n\nRequired scope: `orders:ring`.","x-required-scope":"orders:ring","parameters":[{"$ref":"#/components/parameters/OrderId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/IfMatch"}],"responses":{"200":{"description":"The order after the command","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"ready","version":2,"ring_count":1,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":"2026-10-17T18:11:42.020Z","acknowledged_at":null,"last_ring_at":"2026-10-17T18:11:42.020Z","closed_at":null,"close_reason":null,"expires_at":"2026-10-17T20:11:42.020Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, invalid_idempotency_key, invalid_precondition","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_precondition":{"summary":"If-Match is not a single entity tag. Send the ETag you received, e.g. \"3\".","value":{"type":"about:blank#invalid_precondition","title":"If-Match must be a single entity tag such as \"3\"","status":400,"code":"invalid_precondition","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: invalid_transition, ring_limit, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_transition":{"summary":"The command does not apply to the order's current status, for example ringing an order that is still preparing or marking a collected order ready.","value":{"type":"about:blank#invalid_transition","title":"Cannot ring an order that is preparing","status":409,"code":"invalid_transition","retryable":false,"details":{"status":"preparing","action":"ring"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"ring_limit":{"summary":"An order can alert the customer at most 6 times, automatic reminders included.","value":{"type":"about:blank#ring_limit","title":"Maximum number of rings reached for this order","status":409,"code":"ring_limit","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"412":{"description":"Precondition failed: version_conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"version_conflict":{"summary":"If-Match did not match the order's current version. details.current_version holds the latest version; re-read the order and decide again.","value":{"type":"about:blank#version_conflict","title":"The order changed since you last loaded it","status":412,"code":"version_conflict","retryable":false,"details":{"current_version":3},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: ring_too_soon, rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ring_too_soon":{"summary":"Rings must be at least 30 seconds apart. Retry after details.retry_after seconds (also in Retry-After).","value":{"type":"about:blank#ring_too_soon","title":"Please wait before ringing again","status":429,"code":"ring_too_soon","retryable":true,"details":{"retry_after":18},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10/ring\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: a8d4c2e6-1b3f-4f7a-9c5e-0d2e4f6a8b13\""}]}},"/orders/{id}/collect":{"post":{"operationId":"collectOrder","tags":["Order commands"],"summary":"Collect","description":"Closes a ready order as handed over and frees the pager card; pending alerts stop (a call that may still be ringing is hung up), so the next customer of this card is never confused with this one. Send {\"direct\": true} to close an order that is still preparing (handed over at the counter without paging). Collecting an already collected order returns 200.\n\nRequired scope: `orders:collect`.","x-required-scope":"orders:collect","parameters":[{"$ref":"#/components/parameters/OrderId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/IfMatch"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectOrderRequest"},"example":{"direct":false}}}},"responses":{"200":{"description":"The order after the command","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"collected","version":3,"ring_count":1,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":"2026-10-17T18:11:42.020Z","acknowledged_at":null,"last_ring_at":"2026-10-17T18:11:42.020Z","closed_at":"2026-10-17T18:13:05.877Z","close_reason":"collected","expires_at":"2026-10-17T20:11:42.020Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, invalid_idempotency_key, invalid_precondition","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_precondition":{"summary":"If-Match is not a single entity tag. Send the ETag you received, e.g. \"3\".","value":{"type":"about:blank#invalid_precondition","title":"If-Match must be a single entity tag such as \"3\"","status":400,"code":"invalid_precondition","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: invalid_transition, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_transition":{"summary":"The command does not apply to the order's current status, for example ringing an order that is still preparing or marking a collected order ready.","value":{"type":"about:blank#invalid_transition","title":"Cannot ring an order that is preparing","status":409,"code":"invalid_transition","retryable":false,"details":{"status":"preparing","action":"ring"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"412":{"description":"Precondition failed: version_conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"version_conflict":{"summary":"If-Match did not match the order's current version. details.current_version holds the latest version; re-read the order and decide again.","value":{"type":"about:blank#version_conflict","title":"The order changed since you last loaded it","status":412,"code":"version_conflict","retryable":false,"details":{"current_version":3},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10/collect\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: 5f7b9d1c-3e5a-4c2b-8d6f-1a3c5e7f9b25\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"direct\":false}'"}]}},"/orders/{id}/cancel":{"post":{"operationId":"cancelOrder","tags":["Order commands"],"summary":"Cancel","description":"Closes an active order without handover (voided invoice, customer left). Frees the pager card, stops pending alerts and hangs up a call to the customer that may still be ringing. Cancelling an already cancelled order returns 200.\n\nRequired scope: `orders:cancel`.","x-required-scope":"orders:cancel","parameters":[{"$ref":"#/components/parameters/OrderId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/IfMatch"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelOrderRequest"},"example":{"reason":"customer_left"}}}},"responses":{"200":{"description":"The order after the command","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"cancelled","version":2,"ring_count":0,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":null,"acknowledged_at":null,"last_ring_at":null,"closed_at":"2026-10-17T18:06:40.004Z","close_reason":"customer_left","expires_at":"2026-10-18T00:04:11.512Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, invalid_idempotency_key, invalid_precondition","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_precondition":{"summary":"If-Match is not a single entity tag. Send the ETag you received, e.g. \"3\".","value":{"type":"about:blank#invalid_precondition","title":"If-Match must be a single entity tag such as \"3\"","status":400,"code":"invalid_precondition","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: invalid_transition, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_transition":{"summary":"The command does not apply to the order's current status, for example ringing an order that is still preparing or marking a collected order ready.","value":{"type":"about:blank#invalid_transition","title":"Cannot ring an order that is preparing","status":409,"code":"invalid_transition","retryable":false,"details":{"status":"preparing","action":"ring"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"412":{"description":"Precondition failed: version_conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"version_conflict":{"summary":"If-Match did not match the order's current version. details.current_version holds the latest version; re-read the order and decide again.","value":{"type":"about:blank#version_conflict","title":"The order changed since you last loaded it","status":412,"code":"version_conflict","retryable":false,"details":{"current_version":3},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10/cancel\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: e2a4c6e8-7f1b-4d3a-b5c7-9e1f3a5c7d37\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"reason\":\"customer_left\"}'"}]}},"/branches/{branch}/invoices/{invoice}/ready":{"post":{"operationId":"readyByInvoice","tags":["Invoice commands"],"summary":"Mark ready by invoice","description":"Marks the order ready and alerts every device following it (the open order page rings). When the order has a phone number (customer.phone) and the branch uses phone alerts, the customer also gets an automated voice call right away (or one SMS on SMS branches), even with the page closed; no tap is needed. Idempotent: calling it on an order that is already ready returns 200 with the unchanged order and never alerts again. Use ring for that. The order is the active order of the invoice in this branch; when there is none you get 404 no_active_order with the latest order's status in details.last_status.\n\nRequired scope: `orders:ready`.","x-required-scope":"orders:ready","parameters":[{"$ref":"#/components/parameters/Branch"},{"$ref":"#/components/parameters/Invoice"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/IfMatch"}],"responses":{"200":{"description":"The order after the command","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"ready","version":2,"ring_count":1,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":"2026-10-17T18:11:42.020Z","acknowledged_at":null,"last_ring_at":"2026-10-17T18:11:42.020Z","closed_at":null,"close_reason":null,"expires_at":"2026-10-17T20:11:42.020Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, invalid_idempotency_key, invalid_precondition","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_precondition":{"summary":"If-Match is not a single entity tag. Send the ETag you received, e.g. \"3\".","value":{"type":"about:blank#invalid_precondition","title":"If-Match must be a single entity tag such as \"3\"","status":400,"code":"invalid_precondition","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: no_active_order, not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"no_active_order":{"summary":"Invoice commands only: the invoice has no active order in this branch. details.last_status tells you what happened to its latest order (for example collected). If it is the state you wanted, treat it as success.","value":{"type":"about:blank#no_active_order","title":"This invoice has no active order","status":404,"code":"no_active_order","retryable":false,"details":{"invoice_number":"A-1042","last_status":"collected","last_order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","last_closed_at":"2026-10-17T18:13:05.877Z"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: invalid_transition, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_transition":{"summary":"The command does not apply to the order's current status, for example ringing an order that is still preparing or marking a collected order ready.","value":{"type":"about:blank#invalid_transition","title":"Cannot ring an order that is preparing","status":409,"code":"invalid_transition","retryable":false,"details":{"status":"preparing","action":"ring"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"412":{"description":"Precondition failed: version_conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"version_conflict":{"summary":"If-Match did not match the order's current version. details.current_version holds the latest version; re-read the order and decide again.","value":{"type":"about:blank#version_conflict","title":"The order changed since you last loaded it","status":412,"code":"version_conflict","retryable":false,"details":{"current_version":3},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/branches/jo-7th-circle/invoices/A-1042/ready\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: 3c9e1f7a-52d4-4b8e-a1f0-6d2b7c8e9a41\""}]}},"/branches/{branch}/invoices/{invoice}/ring":{"post":{"operationId":"ringByInvoice","tags":["Invoice commands"],"summary":"Ring again by invoice","description":"Alerts the customer again while the order is ready. Rings must be at least 30 s apart (429 ring_too_soon with retry_after) and an order alerts at most 6 times in total, automatic reminders included (409 ring_limit). On branches that call, each ring also places one more voice call to the order's phone number (not while the previous call may still be ringing or talking), at most 3 calls per order including the automatic one. The order is the active order of the invoice in this branch; when there is none you get 404 no_active_order with the latest order's status in details.last_status.\n\nRequired scope: `orders:ring`.","x-required-scope":"orders:ring","parameters":[{"$ref":"#/components/parameters/Branch"},{"$ref":"#/components/parameters/Invoice"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/IfMatch"}],"responses":{"200":{"description":"The order after the command","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"ready","version":2,"ring_count":1,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":"2026-10-17T18:11:42.020Z","acknowledged_at":null,"last_ring_at":"2026-10-17T18:11:42.020Z","closed_at":null,"close_reason":null,"expires_at":"2026-10-17T20:11:42.020Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, invalid_idempotency_key, invalid_precondition","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_precondition":{"summary":"If-Match is not a single entity tag. Send the ETag you received, e.g. \"3\".","value":{"type":"about:blank#invalid_precondition","title":"If-Match must be a single entity tag such as \"3\"","status":400,"code":"invalid_precondition","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: no_active_order, not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"no_active_order":{"summary":"Invoice commands only: the invoice has no active order in this branch. details.last_status tells you what happened to its latest order (for example collected). If it is the state you wanted, treat it as success.","value":{"type":"about:blank#no_active_order","title":"This invoice has no active order","status":404,"code":"no_active_order","retryable":false,"details":{"invoice_number":"A-1042","last_status":"collected","last_order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","last_closed_at":"2026-10-17T18:13:05.877Z"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: invalid_transition, ring_limit, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_transition":{"summary":"The command does not apply to the order's current status, for example ringing an order that is still preparing or marking a collected order ready.","value":{"type":"about:blank#invalid_transition","title":"Cannot ring an order that is preparing","status":409,"code":"invalid_transition","retryable":false,"details":{"status":"preparing","action":"ring"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"ring_limit":{"summary":"An order can alert the customer at most 6 times, automatic reminders included.","value":{"type":"about:blank#ring_limit","title":"Maximum number of rings reached for this order","status":409,"code":"ring_limit","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"412":{"description":"Precondition failed: version_conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"version_conflict":{"summary":"If-Match did not match the order's current version. details.current_version holds the latest version; re-read the order and decide again.","value":{"type":"about:blank#version_conflict","title":"The order changed since you last loaded it","status":412,"code":"version_conflict","retryable":false,"details":{"current_version":3},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: ring_too_soon, rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ring_too_soon":{"summary":"Rings must be at least 30 seconds apart. Retry after details.retry_after seconds (also in Retry-After).","value":{"type":"about:blank#ring_too_soon","title":"Please wait before ringing again","status":429,"code":"ring_too_soon","retryable":true,"details":{"retry_after":18},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/branches/jo-7th-circle/invoices/A-1042/ring\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: a8d4c2e6-1b3f-4f7a-9c5e-0d2e4f6a8b13\""}]}},"/branches/{branch}/invoices/{invoice}/collect":{"post":{"operationId":"collectByInvoice","tags":["Invoice commands"],"summary":"Collect by invoice","description":"Closes a ready order as handed over and frees the pager card; pending alerts stop (a call that may still be ringing is hung up), so the next customer of this card is never confused with this one. Send {\"direct\": true} to close an order that is still preparing (handed over at the counter without paging). Collecting an already collected order returns 200. The order is the active order of the invoice in this branch; when there is none you get 404 no_active_order with the latest order's status in details.last_status.\n\nRequired scope: `orders:collect`.","x-required-scope":"orders:collect","parameters":[{"$ref":"#/components/parameters/Branch"},{"$ref":"#/components/parameters/Invoice"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/IfMatch"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectOrderRequest"},"example":{"direct":false}}}},"responses":{"200":{"description":"The order after the command","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"collected","version":3,"ring_count":1,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":"2026-10-17T18:11:42.020Z","acknowledged_at":null,"last_ring_at":"2026-10-17T18:11:42.020Z","closed_at":"2026-10-17T18:13:05.877Z","close_reason":"collected","expires_at":"2026-10-17T20:11:42.020Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, invalid_idempotency_key, invalid_precondition","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_precondition":{"summary":"If-Match is not a single entity tag. Send the ETag you received, e.g. \"3\".","value":{"type":"about:blank#invalid_precondition","title":"If-Match must be a single entity tag such as \"3\"","status":400,"code":"invalid_precondition","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: no_active_order, not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"no_active_order":{"summary":"Invoice commands only: the invoice has no active order in this branch. details.last_status tells you what happened to its latest order (for example collected). If it is the state you wanted, treat it as success.","value":{"type":"about:blank#no_active_order","title":"This invoice has no active order","status":404,"code":"no_active_order","retryable":false,"details":{"invoice_number":"A-1042","last_status":"collected","last_order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","last_closed_at":"2026-10-17T18:13:05.877Z"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: invalid_transition, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_transition":{"summary":"The command does not apply to the order's current status, for example ringing an order that is still preparing or marking a collected order ready.","value":{"type":"about:blank#invalid_transition","title":"Cannot ring an order that is preparing","status":409,"code":"invalid_transition","retryable":false,"details":{"status":"preparing","action":"ring"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"412":{"description":"Precondition failed: version_conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"version_conflict":{"summary":"If-Match did not match the order's current version. details.current_version holds the latest version; re-read the order and decide again.","value":{"type":"about:blank#version_conflict","title":"The order changed since you last loaded it","status":412,"code":"version_conflict","retryable":false,"details":{"current_version":3},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/branches/jo-7th-circle/invoices/A-1042/collect\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: 5f7b9d1c-3e5a-4c2b-8d6f-1a3c5e7f9b25\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"direct\":false}'"}]}},"/branches/{branch}/invoices/{invoice}/cancel":{"post":{"operationId":"cancelByInvoice","tags":["Invoice commands"],"summary":"Cancel by invoice","description":"Closes an active order without handover (voided invoice, customer left). Frees the pager card, stops pending alerts and hangs up a call to the customer that may still be ringing. Cancelling an already cancelled order returns 200. The order is the active order of the invoice in this branch; when there is none you get 404 no_active_order with the latest order's status in details.last_status.\n\nRequired scope: `orders:cancel`.","x-required-scope":"orders:cancel","parameters":[{"$ref":"#/components/parameters/Branch"},{"$ref":"#/components/parameters/Invoice"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/IfMatch"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelOrderRequest"},"example":{"reason":"customer_left"}}}},"responses":{"200":{"description":"The order after the command","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotency-Replayed":{"$ref":"#/components/headers/Idempotency-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","branch_code":"jo-7th-circle","pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","status":"cancelled","version":2,"ring_count":0,"external_id":"pos-88231","source":"api","created_at":"2026-10-17T18:04:11.512Z","ready_at":null,"acknowledged_at":null,"last_ring_at":null,"closed_at":"2026-10-17T18:06:40.004Z","close_reason":"customer_left","expires_at":"2026-10-18T00:04:11.512Z","has_phone":false,"customer":{"linked_devices":1,"notifications_enabled_devices":0},"links":{"self":"https://smart-pager-production.up.railway.app/api/v1/orders/6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"}}}}},"400":{"description":"Bad request: invalid_json, invalid_idempotency_key, invalid_precondition","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_json":{"summary":"The body could not be parsed as JSON.","value":{"type":"about:blank#invalid_json","title":"Request body must be valid JSON","status":400,"code":"invalid_json","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_idempotency_key":{"summary":"The Idempotency-Key header is empty, too long or contains spaces or non-ASCII characters.","value":{"type":"about:blank#invalid_idempotency_key","title":"Idempotency-Key must be 1-128 visible ASCII characters","status":400,"code":"invalid_idempotency_key","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"invalid_precondition":{"summary":"If-Match is not a single entity tag. Send the ETag you received, e.g. \"3\".","value":{"type":"about:blank#invalid_precondition","title":"If-Match must be a single entity tag such as \"3\"","status":400,"code":"invalid_precondition","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: no_active_order, not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"no_active_order":{"summary":"Invoice commands only: the invoice has no active order in this branch. details.last_status tells you what happened to its latest order (for example collected). If it is the state you wanted, treat it as success.","value":{"type":"about:blank#no_active_order","title":"This invoice has no active order","status":404,"code":"no_active_order","retryable":false,"details":{"invoice_number":"A-1042","last_status":"collected","last_order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","last_closed_at":"2026-10-17T18:13:05.877Z"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"409":{"description":"Conflict: invalid_transition, idempotency_conflict, idempotency_in_progress","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid_transition":{"summary":"The command does not apply to the order's current status, for example ringing an order that is still preparing or marking a collected order ready.","value":{"type":"about:blank#invalid_transition","title":"Cannot ring an order that is preparing","status":409,"code":"invalid_transition","retryable":false,"details":{"status":"preparing","action":"ring"},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_conflict":{"summary":"The Idempotency-Key already belongs to a different request (method, path or body) that succeeded or is still running. Use a new key for a new operation.","value":{"type":"about:blank#idempotency_conflict","title":"This Idempotency-Key was already used with a different request","status":409,"code":"idempotency_conflict","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}},"idempotency_in_progress":{"summary":"The first request with this key has not finished yet. Retry after Retry-After seconds with the same key.","value":{"type":"about:blank#idempotency_in_progress","title":"A request with this Idempotency-Key is still in progress","status":409,"code":"idempotency_in_progress","retryable":true,"details":{"retry_after":2},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"412":{"description":"Precondition failed: version_conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"version_conflict":{"summary":"If-Match did not match the order's current version. details.current_version holds the latest version; re-read the order and decide again.","value":{"type":"about:blank#version_conflict","title":"The order changed since you last loaded it","status":412,"code":"version_conflict","retryable":false,"details":{"current_version":3},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"413":{"description":"Payload too large: payload_too_large","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payload_too_large":{"summary":"Request bodies are limited to 16 KB.","value":{"type":"about:blank#payload_too_large","title":"Request body must not exceed 16384 bytes","status":413,"code":"payload_too_large","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl -X POST \"https://smart-pager-production.up.railway.app/api/v1/branches/jo-7th-circle/invoices/A-1042/cancel\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\" \\\n  -H \"Idempotency-Key: e2a4c6e8-7f1b-4d3a-b5c7-9e1f3a5c7d37\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"reason\":\"customer_left\"}'"}]}},"/events":{"get":{"operationId":"listEvents","tags":["Events"],"summary":"Order event feed","description":"Every order event of the branches this key can access, oldest first, by ascending id. Event ids are the same evt_ ids your webhooks carry, so you can dedupe across both. Poll with after=<next_cursor> to catch anything a webhook missed. A page never contains an event while an event with a lower id is still being saved, so following next_cursor never skips one; while such a save is unusually slow the page can come back empty with next_cursor unchanged. Ignore event types you do not know.\n\nRequired scope: `events:read`.","x-required-scope":"events:read","parameters":[{"$ref":"#/components/parameters/EventsAfter"},{"$ref":"#/components/parameters/EventsLimit"},{"$ref":"#/components/parameters/EventsBranch"}],"responses":{"200":{"description":"A page of events","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-SmartPager-Api-Version":{"$ref":"#/components/headers/X-SmartPager-Api-Version"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventList"},"example":{"data":[{"id":"evt_1288","type":"order.created","occurred_at":"2026-10-17T18:04:11.512Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","data":{"status":"preparing","pager_number":7,"invoice_number":"A-1042","external_id":"pos-88231","source":"api"}},{"id":"evt_1289","type":"order.ready","occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","data":{"status":"ready","pager_number":7,"invoice_number":"A-1042","external_id":"pos-88231"}}],"next_cursor":"evt_1289","has_more":false}}}},"401":{"description":"Unauthorized: unauthorized","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unauthorized":{"summary":"The API key is missing, malformed, unknown or revoked, or its integration is disabled.","value":{"type":"about:blank#unauthorized","title":"Invalid API key","status":401,"code":"unauthorized","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"403":{"description":"Forbidden: forbidden","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"summary":"The key does not have the scope this endpoint needs (sending `customer` also needs contacts:write), or the branch is disabled.","value":{"type":"about:blank#forbidden","title":"API key lacks scope orders:create","status":403,"code":"forbidden","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"404":{"description":"Not found: not_found","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"not_found":{"summary":"The branch, pager, order or endpoint does not exist, or your key cannot access it. Inaccessible resources always look like missing ones.","value":{"type":"about:blank#not_found","title":"Order not found","status":404,"code":"not_found","retryable":false,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"422":{"description":"Unprocessable content: validation_failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation_failed":{"summary":"A field or query parameter is missing or invalid. details.issues lists each problem with its path.","value":{"type":"about:blank#validation_failed","title":"Invalid request","status":422,"code":"validation_failed","retryable":false,"details":{"issues":[{"path":"pager_number","message":"Too small: expected number to be >=1"}]},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"429":{"description":"Too many requests: rate_limited","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rate_limited":{"summary":"More than 600 requests in one minute for this integration. Retry after Retry-After seconds.","value":{"type":"about:blank#rate_limited","title":"Too many requests","status":429,"code":"rate_limited","retryable":true,"details":{"retry_after":12},"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}},"500":{"description":"Server error: internal_error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"internal_error":{"summary":"Something failed on our side. Retry with backoff and the same Idempotency-Key; read the order first if you are unsure whether the command applied. Quote request_id when reporting it.","value":{"type":"about:blank#internal_error","title":"Unexpected server error","status":500,"code":"internal_error","retryable":true,"request_id":"3f0f4b8e-5a43-4c1e-9d0b-2b8c7e6a1f25"}}}}}}},"x-codeSamples":[{"lang":"Shell","label":"cURL","source":"curl \"https://smart-pager-production.up.railway.app/api/v1/events?after=evt_1287&limit=100\" \\\n  -H \"Authorization: Bearer $SMARTPAGER_API_KEY\""}]}}},"webhooks":{"order.created":{"post":{"operationId":"webhook_order_created","tags":["Webhooks"],"summary":"Invoice linked to a pager","description":"An invoice was linked to a pager card, from this API or from the cashier screen.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.created"},"data":{"$ref":"#/components/schemas/WebhookOrderData"}}}]},"example":{"id":"evt_1289","type":"order.created","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231","status":"preparing","version":1,"pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"order.ready":{"post":{"operationId":"webhook_order_ready","tags":["Webhooks"],"summary":"Order marked ready","description":"The order was marked ready. Every device following it is being alerted.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.ready"},"data":{"$ref":"#/components/schemas/WebhookOrderData"}}}]},"example":{"id":"evt_1289","type":"order.ready","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231","status":"ready","version":2,"pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"order.rang":{"post":{"operationId":"webhook_order_rang","tags":["Webhooks"],"summary":"Customer alerted again","description":"Staff or a POS rang the customer again. data.ring is the alert round number (1 = the ready alert).","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.rang"},"data":{"$ref":"#/components/schemas/WebhookOrderRangData"}}}]},"example":{"id":"evt_1289","type":"order.rang","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231","status":"ready","version":3,"pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17","ring":2}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"order.acknowledged":{"post":{"operationId":"webhook_order_acknowledged","tags":["Webhooks"],"summary":"Customer saw the alert","description":"The customer tapped OK on the ready alarm (optional; most customers never do). Automatic reminders stop. Its absence does not mean the customer missed the alert.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.acknowledged"},"data":{"$ref":"#/components/schemas/WebhookOrderData"}}}]},"example":{"id":"evt_1289","type":"order.acknowledged","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231","status":"ready","version":4,"pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"order.collected":{"post":{"operationId":"webhook_order_collected","tags":["Webhooks"],"summary":"Order handed over","description":"The order was handed over. The pager card is free again.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.collected"},"data":{"$ref":"#/components/schemas/WebhookOrderData"}}}]},"example":{"id":"evt_1289","type":"order.collected","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231","status":"collected","version":5,"pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"order.cancelled":{"post":{"operationId":"webhook_order_cancelled","tags":["Webhooks"],"summary":"Order cancelled","description":"The order was cancelled. The pager card is free and pending alerts were stopped.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.cancelled"},"data":{"$ref":"#/components/schemas/WebhookOrderData"}}}]},"example":{"id":"evt_1289","type":"order.cancelled","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231","status":"cancelled","version":2,"pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"order.expired":{"post":{"operationId":"webhook_order_expired","tags":["Webhooks"],"summary":"Order closed by timeout","description":"The order was closed automatically: 6 h after creation while preparing, or 2 h after it became ready.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.expired"},"data":{"$ref":"#/components/schemas/WebhookOrderData"}}}]},"example":{"id":"evt_1289","type":"order.expired","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231","status":"expired","version":3,"pager_number":7,"invoice_number":"A-1042","business_date":"2026-10-17"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"order.customer_linked":{"post":{"operationId":"webhook_order_customer_linked","tags":["Webhooks"],"summary":"Customer device following","description":"A customer device scanned the pager card (or entered the pickup code) and now follows the order.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.customer_linked"},"data":{"$ref":"#/components/schemas/WebhookCustomerLinkedData"}}}]},"example":{"id":"evt_1289","type":"order.customer_linked","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231","via":"scan"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"order.notifications_enabled":{"post":{"operationId":"webhook_order_notifications_enabled","tags":["Webhooks"],"summary":"Notifications enabled (no longer sent)","description":"No longer sent: push notifications were removed (the open order page rings instead), so this event never fires. The type is still accepted in webhook subscriptions so existing endpoints keep validating; you can stop subscribing to it.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","required":["branch_id"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$"},"type":{"const":"order.notifications_enabled"},"data":{"$ref":"#/components/schemas/WebhookNotificationsEnabledData"}}}]},"example":{"id":"evt_1289","type":"order.notifications_enabled","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","branch_id":"0b8f3c1e-2a44-4d6b-9e1f-5c7a2d3e4f50","data":{"order_id":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10","external_id":"pos-88231"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}},"ping":{"post":{"operationId":"webhook_ping","tags":["Webhooks"],"summary":"Test delivery","description":"Sent when an admin presses “Send test” for your endpoint in the admin console. Its id starts with `evt_test_`, it has no `branch_id`, it never appears in GET /events and it is retried for 1 hour only. Answer with any 2xx.","security":[],"parameters":[{"name":"X-SmartPager-Event-Id","in":"header","required":true,"description":"Same as the body's id. Deliveries can repeat: process each id once.","schema":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$"}},{"name":"X-SmartPager-Timestamp","in":"header","required":true,"description":"Unix time (seconds) when this delivery attempt was signed. Reject it when it is more than 5 minutes away from your clock.","schema":{"type":"string","pattern":"^[0-9]+$"}},{"name":"X-SmartPager-Signature","in":"header","required":true,"description":"`v1=` + lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`. The key is the endpoint's whole signing secret as UTF-8 text, `whsec_` prefix included (do not base64-decode it). Compare in constant time; accept the delivery if any comma-separated v1 value matches.","schema":{"type":"string","pattern":"^v1=[0-9a-f]{64}(,\\s*v1=[0-9a-f]{64})*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","properties":{"id":{"type":"string","pattern":"^evt_test_[A-Za-z0-9_-]+$"},"type":{"const":"ping"},"data":{"$ref":"#/components/schemas/WebhookPingData"}}}]},"example":{"id":"evt_test_Q2x9Lm4TzR7a","type":"ping","schema_version":1,"occurred_at":"2026-10-17T18:11:42.020Z","data":{"message":"Smart Pager webhook test"}}}}},"responses":{"2XX":{"description":"Received. Answer within 10 seconds and do slow work asynchronously."},"default":{"description":"Any other status (redirects are not followed), or no answer within 10 s, is retried with exponential backoff for up to 24 h."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"pgr_<prefix>_<secret>","description":"API key created in the Smart Pager admin console, sent as `Authorization: Bearer pgr_…`. Keys are scoped to one branch or one brand and carry scopes. Keep them server-side."}},"parameters":{"Branch":{"name":"branch","in":"path","required":true,"description":"Branch code (for example `jo-7th-circle`) or branch UUID.","schema":{"type":"string","maxLength":64},"example":"jo-7th-circle"},"OrderId":{"name":"id","in":"path","required":true,"description":"Order id returned when the order was created.","schema":{"type":"string","format":"uuid"},"example":"6f1c2a7e-9d1b-4c55-8a3e-2b7f0e4d9a10"},"Invoice":{"name":"invoice","in":"path","required":true,"description":"Invoice number as printed by the POS, URL-encoded (`/` → `%2F`, `#` → `%23`). Matching ignores case and spaces and accepts Arabic-Indic digits.","schema":{"type":"string","minLength":1,"maxLength":64},"example":"A-1042"},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique key for this operation (a UUID is ideal). Retrying with the same key and the same request replays the first successful response instead of acting twice. Failed requests are not stored. Keys live 7 days per integration.","schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[\\x21-\\x7E]+$"}},"IdempotencyKeyRequired":{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique key for this order creation (a UUID is ideal). Generate it once, store it with the POS order and reuse it on every retry. Only a successful creation is stored, so after an error (for example pager_busy) you may retry with the same key and a corrected body. Keys live 7 days per integration.","schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[\\x21-\\x7E]+$"},"example":"0b5e3a0c-6f1d-4d8e-9a77-2c1f3e4d5b6a"},"IfMatch":{"name":"If-Match","in":"header","required":false,"description":"Apply the command only if the order version still equals this entity tag (the ETag you received, e.g. `\"3\"`). Otherwise 412 version_conflict.","schema":{"type":"string","examples":["\"3\"","W/\"3\""]}},"OrderStatusFilter":{"name":"status","in":"query","required":false,"description":"`active` = preparing or ready; `closed` = collected, cancelled or expired; or a single status.","schema":{"type":"string","enum":["active","closed","all","preparing","ready","collected","cancelled","expired"],"default":"active"}},"InvoiceFilter":{"name":"invoice_number","in":"query","required":false,"description":"Only orders of this invoice (normalized like the invoice field).","schema":{"type":"string","maxLength":64}},"Limit":{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},"Cursor":{"name":"cursor","in":"query","required":false,"description":"Opaque `next_cursor` of the previous page.","schema":{"type":"string","maxLength":200}},"EventsAfter":{"name":"after","in":"query","required":false,"description":"Return events after this event id (`evt_1289` or `1289`). Omit to start from the oldest retained event.","schema":{"type":"string","pattern":"^(evt_)?[0-9]{1,15}$"}},"EventsLimit":{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":100}},"EventsBranch":{"name":"branch","in":"query","required":false,"description":"Only events of this branch (code or UUID). Brand keys see every branch of the brand by default.","schema":{"type":"string","maxLength":64}}},"headers":{"X-Request-Id":{"description":"Unique id of this request. Quote it when reporting a problem.","schema":{"type":"string","format":"uuid"}},"X-SmartPager-Api-Version":{"description":"Revision of API v1 that served the request (additive changes only within v1).","schema":{"type":"string","examples":["1.0.0"]}},"ETag":{"description":"Strong entity tag holding the order version, e.g. `\"3\"`. Send it back in If-Match.","schema":{"type":"string"}},"Location":{"description":"URL of the created order.","schema":{"type":"string","format":"uri"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}},"Idempotency-Replayed":{"description":"Present (`true`) when this response is a stored replay of an earlier request with the same Idempotency-Key.","schema":{"type":"string","enum":["true"]}},"RateLimit-Limit":{"description":"Requests allowed per window for this integration.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}}},"schemas":{"OrderStatus":{"type":"string","enum":["preparing","ready","collected","cancelled","expired"],"description":"preparing → ready → collected; preparing/ready → cancelled or expired. collected, cancelled and expired are final."},"CustomerEngagement":{"type":"object","required":["linked_devices","notifications_enabled_devices"],"properties":{"linked_devices":{"type":"integer","minimum":0,"description":"Customer devices following this order (scanned the card)."},"notifications_enabled_devices":{"type":"integer","minimum":0,"deprecated":true,"description":"Deprecated, always 0: push notifications were removed (the open order page rings instead). Kept so existing integrations keep parsing; use linked_devices."}}},"Order":{"type":"object","required":["id","branch_id","branch_code","pager_number","invoice_number","business_date","status","version","ring_count","external_id","source","created_at","ready_at","acknowledged_at","last_ring_at","closed_at","close_reason","expires_at","has_phone","customer","links"],"properties":{"id":{"type":"string","format":"uuid"},"branch_id":{"type":"string","format":"uuid"},"branch_code":{"type":"string"},"pager_number":{"type":"integer","minimum":1,"maximum":9999},"invoice_number":{"type":["string","null"],"maxLength":64,"description":"Normalized: Arabic-Indic digits converted, spaces removed, upper case. Null for an order the cashier assigned without an invoice (branches that don't require one); orders created through this API always have one."},"business_date":{"type":"string","format":"date","description":"Trading day in the branch's time zone (orders after midnight count for the previous day until the day rolls over)."},"status":{"$ref":"#/components/schemas/OrderStatus"},"version":{"type":"integer","minimum":1,"description":"Increments on every change. Equals the ETag."},"ring_count":{"type":"integer","minimum":0,"description":"Alert rounds so far (ready + rings + automatic reminders)."},"external_id":{"type":["string","null"],"maxLength":128,"description":"Your own reference, as sent on creation."},"source":{"type":"string","enum":["api","dashboard"],"description":"Who created the order."},"created_at":{"type":"string","format":"date-time"},"ready_at":{"type":["string","null"],"format":"date-time"},"acknowledged_at":{"type":["string","null"],"format":"date-time","description":"When the customer tapped OK on the ready alarm (optional; null is normal)."},"last_ring_at":{"type":["string","null"],"format":"date-time"},"closed_at":{"type":["string","null"],"format":"date-time"},"close_reason":{"type":["string","null"],"description":"collected, direct_handover, timeout, or the cancel reason."},"expires_at":{"type":"string","format":"date-time","description":"Automatic cleanup deadline: 6 h after creation while preparing, 2 h after ready."},"has_phone":{"type":"boolean","description":"Whether a phone number is on file. The number itself is never returned."},"customer":{"$ref":"#/components/schemas/CustomerEngagement"},"pickup_code":{"type":"string","pattern":"^[0-9]{4}$","description":"Only in the 201 response of order creation, and only when the branch requires a pickup code to follow an order. Print it on the receipt."},"links":{"type":"object","required":["self"],"properties":{"self":{"type":"string","format":"uri","description":"Absolute URL of this order."}}}}},"OrderList":{"type":"object","required":["data","next_cursor","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean"}}},"CreateOrderRequest":{"type":"object","required":["pager_number","invoice_number"],"properties":{"pager_number":{"type":"integer","minimum":1,"maximum":9999,"description":"Number printed on the pager card handed to the customer."},"invoice_number":{"type":"string","minLength":1,"maxLength":64,"description":"Letters, digits and - _ / . # (numbers are accepted too). Normalized before storage."},"external_id":{"type":["string","null"],"minLength":1,"maxLength":128,"description":"Your own order reference. Must be unique among your active orders."},"customer":{"oneOf":[{"$ref":"#/components/schemas/CustomerContact"},{"type":"null"}]}}},"CustomerContact":{"type":"object","required":["phone","consent"],"description":"Requires the contacts:write scope.","properties":{"phone":{"type":"string","maxLength":32,"description":"International (+962…) or national format; national numbers use `country` or the branch's country."},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2 country for national numbers."},"consent":{"type":"boolean","const":true,"description":"The customer agreed to be called (or texted) about this order when it is ready."}}},"CollectOrderRequest":{"type":"object","properties":{"direct":{"type":"boolean","default":false,"description":"Allow collecting an order that is still preparing (handed over directly without paging)."}}},"CancelOrderRequest":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":200,"description":"Short machine-friendly reason, e.g. `invoice_voided`."}}},"Branch":{"type":"object","required":["id","code","brand","name_en","name_ar","country_code","timezone","enabled"],"properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string"},"brand":{"type":"object","required":["slug","name_en","name_ar"],"properties":{"slug":{"type":"string","examples":["99grill","chickendip"]},"name_en":{"type":"string"},"name_ar":{"type":"string"}}},"name_en":{"type":"string"},"name_ar":{"type":"string"},"country_code":{"type":"string","pattern":"^[A-Z]{2}$"},"timezone":{"type":"string","description":"IANA time zone, e.g. Asia/Amman."},"enabled":{"type":"boolean"}}},"BranchList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Branch"}}}},"Pager":{"type":"object","required":["number","label","enabled","status","order_id"],"properties":{"number":{"type":"integer","minimum":1,"maximum":9999},"label":{"type":["string","null"]},"enabled":{"type":"boolean"},"status":{"type":"string","enum":["free","preparing","ready","disabled"]},"order_id":{"type":["string","null"],"format":"uuid","description":"The active order on this card, if any."}}},"PagerList":{"type":"object","required":["branch","data"],"properties":{"branch":{"type":"object","required":["id","code"],"properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string"}}},"data":{"type":"array","items":{"$ref":"#/components/schemas/Pager"}}}},"Me":{"type":"object","required":["integration","scope","scopes","rate_limit"],"properties":{"integration":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"scope":{"type":"object","required":["type","brand_id","branch_id"],"properties":{"type":{"type":"string","enum":["brand","branch"]},"brand_id":{"type":["string","null"],"format":"uuid"},"branch_id":{"type":["string","null"],"format":"uuid"}}},"scopes":{"type":"array","description":"Granted scopes. New scopes may be added: ignore ones you do not know.","items":{"type":"string","examples":["branches:read","pagers:read","orders:read","orders:create","orders:ready","orders:ring","orders:collect","orders:cancel","contacts:write","events:read"]}},"rate_limit":{"type":"object","required":["limit","window_seconds"],"properties":{"limit":{"type":"integer"},"window_seconds":{"type":"integer"}}}}},"Event":{"type":"object","required":["id","type","occurred_at","branch_id","order_id","data"],"properties":{"id":{"type":"string","pattern":"^evt_[0-9]+$","description":"Same id as the matching webhook delivery."},"type":{"type":"string","description":"order.* event type. Ignore types you do not know."},"occurred_at":{"type":"string","format":"date-time"},"branch_id":{"type":"string","format":"uuid"},"order_id":{"type":["string","null"],"format":"uuid"},"data":{"type":"object","description":"No personal data. Fields depend on the type.","properties":{"status":{"$ref":"#/components/schemas/OrderStatus"},"pager_number":{"type":"integer"},"invoice_number":{"type":["string","null"]},"external_id":{"type":["string","null"]},"source":{"type":"string"},"ring":{"type":"integer"},"round":{"type":"integer"},"reason":{"type":"string"},"from":{"$ref":"#/components/schemas/OrderStatus"},"via":{"type":"string","enum":["scan","code","handoff","counter","invoice"]},"pushes_queued":{"type":"integer","deprecated":true,"description":"Historic events only: push notifications were removed and new events no longer carry it."},"channel":{"type":"string","enum":["sms","call"]},"code":{"type":"string"},"call_status":{"type":"string","enum":["completed","busy","no-answer","failed","canceled"]},"duration_s":{"type":"integer","minimum":0},"sms_backup":{"type":"boolean"}}}}},"EventList":{"type":"object","required":["data","next_cursor","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` next time. Equals your `after` when nothing new is available; null when you sent no `after` and there is nothing to return yet."},"has_more":{"type":"boolean","description":"True when the next page is already available: call again right away."}}},"ApiIndex":{"type":"object","required":["name","version","documentation","openapi","links"],"properties":{"name":{"type":"string"},"version":{"type":"string"},"documentation":{"type":"string","format":"uri"},"openapi":{"type":"string","format":"uri"},"authentication":{"type":"string"},"links":{"type":"object","additionalProperties":{"type":"string","format":"uri"}}}},"OpenApiDocument":{"type":"object","description":"An OpenAPI 3.1 document."},"Problem":{"type":"object","description":"RFC 9457 problem details. Branch on `code`, never on `title`.","required":["type","title","status","code","retryable"],"properties":{"type":{"type":"string","format":"uri-reference","examples":["about:blank#pager_busy"]},"title":{"type":"string","description":"Human-readable summary (English). May change."},"status":{"type":"integer"},"code":{"type":"string","description":"Stable machine-readable error code (see the error table). New codes may be added: treat unknown ones by HTTP status.","examples":["invalid_json","idempotency_key_required","invalid_idempotency_key","invalid_precondition","invalid_cursor","unauthorized","forbidden","not_found","no_active_order","pager_busy","pager_disabled","invoice_active","invalid_transition","ring_limit","idempotency_conflict","idempotency_in_progress","version_conflict","payload_too_large","validation_failed","ring_too_soon","rate_limited","internal_error"]},"retryable":{"type":"boolean","description":"Whether retrying the same request later can succeed."},"details":{"type":"object","additionalProperties":true},"request_id":{"type":"string"}}},"WebhookEnvelope":{"type":"object","required":["id","type","schema_version","occurred_at","data"],"properties":{"id":{"type":"string","pattern":"^evt_[A-Za-z0-9_-]+$","description":"Unique event id; also sent as X-SmartPager-Event-Id. Dedupe on it. `evt_<number>` for order events (the same id as in GET /events), `evt_test_<random>` for test pings."},"type":{"type":"string","description":"Event type. New types may be added: ignore types you do not handle.","examples":["order.created","order.ready","order.rang","order.acknowledged","order.collected","order.cancelled","order.expired","order.customer_linked","order.notifications_enabled","ping"]},"schema_version":{"type":"integer","const":1},"occurred_at":{"type":"string","format":"date-time"},"branch_id":{"type":"string","format":"uuid","description":"Branch of the order. Present on every order event; absent on ping."},"data":{"type":"object"}}},"WebhookOrderData":{"type":"object","required":["order_id","status","version","pager_number","invoice_number","business_date"],"properties":{"order_id":{"type":"string","format":"uuid"},"external_id":{"type":["string","null"],"maxLength":128},"status":{"$ref":"#/components/schemas/OrderStatus"},"version":{"type":"integer","minimum":1,"description":"Order version after the event. Ignore an event older than what you stored."},"pager_number":{"type":"integer"},"invoice_number":{"type":["string","null"],"description":"Null for an order the cashier assigned without an invoice."},"business_date":{"type":"string","format":"date"}}},"WebhookOrderRangData":{"allOf":[{"type":"object","required":["order_id","status","version","pager_number","invoice_number","business_date"],"properties":{"order_id":{"type":"string","format":"uuid"},"external_id":{"type":["string","null"],"maxLength":128},"status":{"$ref":"#/components/schemas/OrderStatus"},"version":{"type":"integer","minimum":1,"description":"Order version after the event. Ignore an event older than what you stored."},"pager_number":{"type":"integer"},"invoice_number":{"type":["string","null"],"description":"Null for an order the cashier assigned without an invoice."},"business_date":{"type":"string","format":"date"}}},{"type":"object","required":["ring"],"properties":{"ring":{"type":"integer","minimum":2}}}]},"WebhookCustomerLinkedData":{"type":"object","required":["order_id","via"],"properties":{"order_id":{"type":"string","format":"uuid"},"external_id":{"type":["string","null"]},"via":{"type":"string","enum":["scan","code","handoff","counter","invoice"],"description":"scan = opened the card's QR; code = entered the pickup code; handoff = installed app; counter = confirmed its number on the branch's counter QR; invoice = joined with the receipt's invoice number."}}},"WebhookNotificationsEnabledData":{"type":"object","description":"order.notifications_enabled is no longer sent; schema kept for existing integrations.","required":["order_id"],"properties":{"order_id":{"type":"string","format":"uuid"},"external_id":{"type":["string","null"]}}},"WebhookPingData":{"type":"object","additionalProperties":true,"description":"Informational only.","properties":{"message":{"type":"string"}}}}}}