{"openapi":"3.1.0","info":{"title":"ZiroWait API","version":"1.1.0","summary":"Read and manage your queue from your own software.","description":"A server-to-server REST API for a ZiroWait business: read queues, entries, services and appointments, and create or cancel queue tokens.\n\n**Authentication:** send your key as `Authorization: Bearer zwk_live_...`. Keys belong on servers only; the API sends no CORS headers.\n**Access:** the Developer API is switched on per business. The business owner creates keys in Dashboard > Settings > Developer API.\n**Documentation:** https://www.zirowait.com/developers/docs","contact":{"name":"ZiroWait developer support","url":"https://www.zirowait.com/developers/docs#support"}},"servers":[{"url":"https://api.zirowait.com/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Account","description":"Check your key and see its limits."},{"name":"Queues","description":"Queues, their live summary and the entries in them."},{"name":"Entries","description":"One queue token: read it, create it, cancel it."},{"name":"Services","description":"What customers can queue for."},{"name":"Appointments","description":"Booked appointments (read only)."}],"paths":{"/me":{"get":{"tags":["Account"],"operationId":"getMe","summary":"Check your key","description":"Works with any valid key. Shows the business, the key's scopes and expiry, and the rate limits.","responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Me"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/services":{"get":{"tags":["Services"],"operationId":"listServices","summary":"List services","description":"Active services of the business. Requires `queue:read`.","responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Service"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/queues":{"get":{"tags":["Queues"],"operationId":"listQueues","summary":"List queues","description":"Requires `queue:read`.","responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Queue"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/queues/{queueId}":{"get":{"tags":["Queues"],"operationId":"getQueue","summary":"Get a queue with today's counts","description":"The queue plus how many entries are waiting, in service, completed, canceled or no-show for the day. Good for a lobby display. Requires `queue:read`.","parameters":[{"name":"queueId","in":"path","required":true,"description":"The id of the queue.","schema":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."}},{"name":"date","in":"query","description":"The day to count. Defaults to today in the business's timezone.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/QueueSummary"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/queues/{queueId}/entries":{"get":{"tags":["Queues"],"operationId":"listEntries","summary":"List entries in a queue","description":"The day's entries in token order (today by default). Requires `queue:read`. Paginated with a cursor.","parameters":[{"name":"queueId","in":"path","required":true,"description":"The id of the queue.","schema":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."}},{"name":"status","in":"query","schema":{"type":"string","enum":["WAITING","IN_SERVICE","COMPLETED","CANCELED","NO_SHOW"]},"description":"Only entries with this status."},{"name":"date","in":"query","description":"The day to list. Defaults to today in the business's timezone.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"limit","in":"query","description":"Page size, 1 to 100 (default 50).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","description":"The nextCursor from the previous page.","schema":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Entries"],"operationId":"createEntry","summary":"Create a queue token","description":"Adds a customer to the queue and returns the token. The token appears on the business's dashboard at once. Requires `queue:write`. This never sends a WhatsApp message. Send an `Idempotency-Key` so a retry cannot create a second token.","parameters":[{"name":"queueId","in":"path","required":true,"description":"The id of the queue.","schema":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."}},{"name":"Idempotency-Key","in":"header","required":false,"description":"8 to 64 characters: letters, digits, underscore or dash. A retry with the same key and body returns the first result.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,64}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEntryRequest"}}}},"responses":{"201":{"description":"Created.","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Location":{"description":"The URL of the new entry.","schema":{"type":"string"}},"Idempotent-Replay":{"description":"true when this is the stored result of an earlier identical request.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/EntryWithPosition"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"queue_paused, queue_unavailable or request_in_progress.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Content-Type must be application/json.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"idempotency_key_reuse: that key was already used with a different request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/entries/{entryId}":{"get":{"tags":["Entries"],"operationId":"getEntry","summary":"Get an entry","description":"One entry with its live position while it is waiting. Requires `queue:read`.","parameters":[{"name":"entryId","in":"path","required":true,"description":"The id of the entry.","schema":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/EntryWithPosition"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/entries/{entryId}/cancel":{"post":{"tags":["Entries"],"operationId":"cancelEntry","summary":"Cancel a waiting entry","description":"Only a WAITING entry can be canceled (otherwise 409 invalid_state). Requires `queue:write`.","parameters":[{"name":"entryId","in":"path","required":true,"description":"The id of the entry.","schema":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Entry"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"invalid_state: the entry is not waiting.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/appointments":{"get":{"tags":["Appointments"],"operationId":"listAppointments","summary":"List appointments","description":"Appointments for one day. Requires `appointments:read`. Paginated with a cursor.","parameters":[{"name":"date","in":"query","description":"The day to list. Defaults to today in the business's timezone.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"limit","in":"query","description":"Page size, 1 to 100 (default 50).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","description":"The nextCursor from the previous page.","schema":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/appointments/{appointmentId}":{"get":{"tags":["Appointments"],"operationId":"getAppointment","summary":"Get an appointment","description":"Requires `appointments:read`. Notes are never returned.","parameters":[{"name":"appointmentId","in":"path","required":true,"description":"The id of the appointment.","schema":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Unique id of this request.","schema":{"type":"string","format":"uuid"}},"API-Version":{"description":"The major version that served the request.","schema":{"type":"string","example":"v1"}},"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Appointment"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"zwk_live_<id>_<secret>","description":"Your API key. Send it in the Authorization header only, never in a URL."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","requestId","docUrl"],"properties":{"code":{"type":"string","description":"A stable, machine-readable code. Branch on this, not on the message."},"message":{"type":"string","description":"A human-readable explanation. Do not parse it."},"requestId":{"type":"string","format":"uuid","description":"Quote this when you contact support."},"docUrl":{"type":"string","format":"uri","description":"A link to the documentation for errors."},"details":{"type":"array","description":"Present on validation errors (invalid_request): which fields were wrong and why.","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}},"required":{"type":"array","items":{"type":"string"},"description":"Present on insufficient_scope: the scopes the endpoint needs."}}}}},"Customer":{"type":"object","required":["name","phone"],"properties":{"name":{"type":["string","null"]},"phone":{"type":["string","null"],"description":"Digits with the country code, for example 919876500001."}}},"Entry":{"type":"object","required":["id","token","tokenSeries","tokenNumber","status","priority","serviceId","customer","issuedAt","startedAt","completedAt","canceledAt","predictedWaitMinutes"],"properties":{"id":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."},"token":{"type":"string","description":"The label the customer sees, for example A12."},"tokenSeries":{"type":"string"},"tokenNumber":{"type":"integer"},"status":{"type":"string","enum":["WAITING","IN_SERVICE","COMPLETED","CANCELED","NO_SHOW"]},"priority":{"type":"boolean"},"serviceId":{"type":["string","null"]},"customer":{"$ref":"#/components/schemas/Customer"},"issuedAt":{"type":"string","format":"date-time"},"startedAt":{"type":["string","null"],"format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"},"canceledAt":{"type":["string","null"],"format":"date-time"},"predictedWaitMinutes":{"type":["integer","null"],"description":"Estimated minutes until this customer is served; null when unknown."}}},"EntryWithPosition":{"allOf":[{"$ref":"#/components/schemas/Entry"},{"type":"object","required":["position"],"properties":{"position":{"type":["integer","null"],"description":"1 means next. Null unless the entry is WAITING."}}}]},"Queue":{"type":"object","required":["id","name","isActive","isTokenCreationPaused"],"properties":{"id":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."},"name":{"type":"string"},"isActive":{"type":"boolean"},"isTokenCreationPaused":{"type":"boolean"}}},"QueueSummary":{"type":"object","required":["id","name","isActive","isTokenCreationPaused","date","counts","averageWaitMinutes"],"properties":{"id":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."},"name":{"type":"string"},"isActive":{"type":"boolean"},"isTokenCreationPaused":{"type":"boolean"},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A calendar day, YYYY-MM-DD, in the business's timezone."},"counts":{"type":"object","required":["waiting","inService","completed","canceled","noShow"],"properties":{"waiting":{"type":"integer"},"inService":{"type":"integer"},"completed":{"type":"integer"},"canceled":{"type":"integer"},"noShow":{"type":"integer"}}},"averageWaitMinutes":{"type":["integer","null"],"description":"Average estimated wait of the people waiting now; null when nobody is waiting or it is unknown."}}},"Service":{"type":"object","required":["id","name","price","baseTimeMinutes"],"properties":{"id":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."},"name":{"type":"string"},"price":{"type":["integer","null"],"description":"Whole rupees."},"baseTimeMinutes":{"type":["integer","null"]}}},"Appointment":{"type":"object","required":["id","date","slotTime","durationMinutes","status","serviceId","customer"],"properties":{"id":{"type":"string","pattern":"^[a-zA-Z0-9]{20,32}$","description":"Opaque identifier."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A calendar day, YYYY-MM-DD, in the business's timezone."},"slotTime":{"type":"string","pattern":"^\\d{2}:\\d{2}$","description":"24-hour time in the business's timezone."},"durationMinutes":{"type":"integer"},"status":{"type":"string","enum":["CONFIRMED","CHECKED_IN","IN_SERVICE","COMPLETED","NO_SHOW","CANCELLED"]},"serviceId":{"type":["string","null"]},"customer":{"$ref":"#/components/schemas/Customer"}}},"Me":{"type":"object","required":["business","key","limits"],"properties":{"business":{"type":"object","required":["name","slug","category","timezone"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"category":{"type":["string","null"]},"timezone":{"type":["string","null"],"description":"An IANA timezone such as Asia/Kolkata."}}},"key":{"type":"object","required":["id","name","scopes","expiresAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["queue:read","queue:write","appointments:read"]}},"expiresAt":{"type":["string","null"],"format":"date-time"}}},"limits":{"type":"object","required":["requestsPerMinute","writesPerMinute","maxBodyBytes"],"properties":{"requestsPerMinute":{"type":"integer"},"writesPerMinute":{"type":"integer"},"maxBodyBytes":{"type":"integer"}}}}},"CreateEntryRequest":{"type":"object","required":["name","phone"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"phone":{"type":"string","pattern":"^\\+?[0-9 ()-]{8,20}$","description":"8 to 20 digits. Spaces, dashes, brackets and a leading + are allowed."},"serviceId":{"type":"string","description":"Optional. Must be an active service of your business."}}},"EntryList":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Entry"}},"nextCursor":{"type":["string","null"],"description":"Pass as the cursor parameter to get the next page. Null means this is the last page."}}},"AppointmentList":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Appointment"}},"nextCursor":{"type":["string","null"],"description":"Pass as the cursor parameter to get the next page. Null means this is the last page."}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key. Every kind of key failure returns this same response.","headers":{"WWW-Authenticate":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key is valid but not allowed: insufficient_scope, api_access_disabled or ip_not_allowed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No such resource in your business.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"BadRequest":{"description":"A field, query parameter or header is invalid or unknown (see error.details), or the body is not valid JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests. Wait for the Retry-After seconds.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}