Troubleshooting: queue booking failed
A caller — or an agent-driven widget — submits the public queue self-booking form and thePOST /api/v1/public/queues/{tenantId}/{queueId}/appointments
call comes back 500 with BOOKING_FAILED. The code is the route’s generic
wrap for a booking attempt that failed below the HTTP layer, so it is a
transient server-side failure until proven otherwise — but it occasionally
hides an already-taken slot that raced availability. This page separates the
two, gets the booking through when a retry is safe, and builds the support
bundle when it is not. Only the BOOKING_FAILED 500 lives here: a taken slot
usually rejects cleanly with 409 (SLOT_ALREADY_BOOKED /
SLOT_NOT_AVAILABLE) and a queue closed to public booking rejects with
422 (INVALID_TENANT or NO_BOOKABLE_SCHEDULE) — those codes are working
as designed, not failures.
Recognize the signal
The booking POST rejects with a 500 and this envelope shape:error.code—BOOKING_FAILED, one refusal for every server-side failure on the booking attempt. It does not name the underlying cause.meta.request_id— the one handle that ties this response to the server log line; keep it for every retry and every escalation.
409 or 422 instead
of a 500, the slot or the queue gate decided — the booking never reached
the write path, and this page is the wrong runbook.
Cause table
Fixes
1. Retry once with the same payload
BOOKING_FAILED is deliberately retriable — the booking either persisted or
it did not, and a failed attempt never creates a partial slot hold. Send the
identical body once:
2. Poll the availability GET and re-pick if the slot went
When the retry also 500s, re-read the published slots before picking again:slot_start is no longer listed as available, a concurrent caller
took it and the conflict surfaced as the generic 500 — book a slot the fresh
read still shows. If the slot still reads as available and the POST still
500s, the failure is server-side and deterministic; move to escalation.
3. Open the ticket with the narrowing bundle
On the second consecutiveBOOKING_FAILED, stop and page support with:
- the
meta.request_idfrom the last failing response envelope, - the queue id and the slot interval you attempted
(
slot_start+slot_minutes), and - the availability snapshot — whether the slot still read as available after the failure.
What not to do
- Do not hammer the endpoint in a retry-loop. The public booking surface sits behind anti-bot token checks and a brutal per-IP rate limit — a tight retry loop burns the allowance the hosted booking page shares with every other caller, and legitimate bookings start refusing behind you.
- Do not treat
BOOKING_FAILEDas “the slot is taken.” A taken slot gets its own409codes; the 500 means the write itself failed. Re-read availability before re-picking so you do not abandon a slot that was never taken. - Do not retry a queue where every slot fails the same way. Uniform failure across every slot is deterministic, not transient — escalate with the bundle instead of sampling more slots and tripping the rate limit.
- Do not book on behalf of a caller through a script. The booking is the caller’s consent to be called back at that slot; scripted bulk booking stores consent records nobody gave and hits the same anti-bot gate.
Escalate
If the retry fails and the availability read still lists the slot:- capture the
meta.request_idfrom the failing response envelope, - include the queue id, the slot interval (
slot_startandslot_minutes), and the caller’s phone in E.164, - attach the availability response showing the slot still listed.
See also
- Public queue self-booking — the guide that opts a queue into public booking, publishes its bookable window, and composes the hosted booking page URL.
- Queue capacity gates — the
sibling queue refusals (
QUEUE_DEPTH_CAP_REACHED) on inbound call entry, a different surface from self-booking. - Queue SLA forecast callback gate —
the
503+slaCallbackBlockedentry refusal and the callback-dispatcher wiring that also dials your booked appointments. - Voice queues guide — queue membership, schedules, and the callback dispatcher the booked appointment rides on.