Voice queue callbacks with SLA policies and scheduling
A voice queue callback lets a waiting caller swap hold time for a dial-back: the platform remembers their request, calls them when an agent frees up (or at a time they picked), and hands them a tracking link they can use to cancel or reschedule without ever calling you back. On top of that, a per-queue callback SLA policy turns “how old may the oldest pending callback get before someone is paged” into a stored objective with automated breach alerts — so an aging callback never silently expires. Callbacks in Orbit come in two complementary flavors:- Overflow (time-driven) callbacks — offered after the caller has waited past the queue’s overflow threshold. The dispatcher retries on a backoff ladder until the callback connects or exhausts the queue’s retry budget. These rows surface under
GET /api/v1/voice/callbacksin the dashboard’s Voice → Callbacks page. - In-queue (position-saving) callbacks — offered while the caller is still holding, sometimes before the breach (the pre-suggest SLA forecast can raise the offer early). The dispatcher waits for agent availability rather than a timer, so the caller keeps an implicit place in line. These rows surface under
GET /api/v1/voice/callback-in-queue.
/api/v1/voice
Authentication: Clerk session or API key with the voice scope (voice:write for mutations, voice:read for monitoring).
1. In-queue callback options, public tokens, and opt-out
A caller consents to a callback inside the queue’s IVR (press 1 when the offer plays), and that consent lands in one of two stores depending on which flavor offered it:- the overflow store, or
- the in-queue, position-saving store.
- the queue the caller was holding on,
- the masked + full E.164 caller id,
- the offer-time estimated wait (used to compare the promise against actual dispatch latency),
- the caller’s preferred callback channel (
voicedefault, orsmsfor an async text-back preference — the SMS hookup still exits over the Devotel softswitch like every other outbound leg), - and, for scheduled callbacks, an explicit appointment window or single target time (ISO 8601 with timezone).
Opting callers out
There are three distinct opt-outs, each tenant-owned:- The caller cancels from the public link (next section).
- An operator cancels from the dashboard — the Voice → Callbacks page lists every pending row with a Cancel action (
DELETE /api/v1/voice/callbacks/:idorDELETE /api/v1/voice/callback-in-queue/:id). Canceling an already-connected or already-terminal row returns 204 and is audit-logged as a no-op, so a dispute can still prove the cancel attempt was made. - A queue stops offering callbacks entirely — the offer lives in the queue’s IVR/routing config, so removing the offer prompt from the IVR branch stops new consents without touching any pending rows.
Public self-service tokens
A caller cannot be expected to hold a Clerk session, so the tracking link they receive uses a signed token instead of a login. When the dispatcher starts dialing, the caller gets a “your callback is on its way” SMS containing a link of the form…/api/v1/public/callbacks/<token>. The token is an HMAC-SHA256 envelope carrying the callback id and owning tenant schema — no session, no signed-in user, and no way to pivot across tenants by editing the URL (any tamper fails the constant-time compare).
The token is valid for 7 days, comfortably longer than any live callback’s dispatch envelope. It opens a self-service surface:
Every mutation is guarded so a row that already left the
pending state (dialing, connected, or terminal) is never altered — a re-tap returns “already canceled” rather than an error, so the caller’s Second tap never breaks anything. These endpoints are rate-limited per IP like every other public surface.
2. Configure the callback-in-queue surface
Dashboard. Open Voice → Queues, pick the queue, and confirm the queue actually voices the in-queue offer (press 1) to a waiting caller — the offer prompt is part of the queue’s IVR path. The list view at Voice → Callbacks then starts streaming rows for that queue. API. Three surfaces make up the operator workflow:cURL
?queue_id, ?status (pending | dialing | connected | failed | abandoned | canceled), cursor pagination (?page_cursor, ?limit up to 100), and the overflow list additionally accepts ?channel=voice|sms. The response returns items[], a next_cursor, and a bounded summary (total / successful / failed / pending / avg_wait_seconds) computed over the most recent slice so a 24/7 queue never pushes an unbounded aggregate into a wallboard poll.
Two operator-control mutations exist on the overflow surface (PATCH /api/v1/voice/callbacks/:id):
{ "action": "retry_now" }— re-enqueue the row for immediate dispatch (the retry ladder restarts on the current tick). Returns 409 if the row is already dialing or terminal.{ "action": "reprioritize", "new_position": 1 }— pull the row ahead of every other pending FIFO entry. The position number is the requested rank; the server clamps it to the current front of the queue.
voice:write plus an owner/admin/developer role — a voice:read key cannot replay or cancel a callback.
Scheduled callbacks (appointment slots and windows)
The consent request accepts three scheduling shapes, all ISO 8601 with timezone offset:
The two window fields must be set together or both omitted — a single-sided window is a 400. The self-book surface lives at
GET /api/v1/voice/queues/:queueId/availability (published slots derived from the queue’s business-hours schedule minus already-booked slots) plus POST /api/v1/voice/queues/:queueId/appointments, and it persists as a scheduled callback row on the same callback_requests store the rest of this page covers — no second dispatcher to learn.
3. SLA policies and escalation
Before the SLA policy surface existed, a wallboard could only flag an aging callback by passing threshold query params on every poll. The per-queue callback SLA policy turns that into a persisted objective:cURL
The counter-posed read is the ad-hoc snapshot, useful when you want a one-off verdict without persisting a policy:
cURL
queue.callback_sla_breach frame when the supervisor passes thresholds on the stream’s query.
Breach-scan escalation
With a persisted policy, a supervisor stops polling and lets the server drive the fan-out:cURL
notifyEnabled — routes to the surface(s) named in notifyKind:
- bell — org-admin in-app bell + email via the registered
voice_queue_alert_rule_firednotification kind, - webhook — an outbound
queue.callback_sla_breachtenant webhook (registered under your webhook subscriptions), - both — the two above.
DELETE …/callback-sla/policy clears a queue’s policy and the queue goes quiet. The org-level rollup at GET /api/v1/voice/sla-hub aggregates every policy-bearing queue’s callback SLA policy plus the newest-first queue breach history in one response.
4. PSAP and AI callbacks
Two adjacent callback surfaces address the lifecycles the queue core doesn’t.PSAP emergency-callback routing
When a device dials an emergency code and the call drops, the incoming PSAP dispatcher’s callback must reach the exact extension that called — not the IVR, not the ACD queue. The per-DID emergency-call log records who called against the DID that called back, and the inbound router consults the resolver first:
Org ownership is enforced per DID so a sibling sub-org cannot read or mutate another sub-org’s emergency-call log. This is inbound routing metadata only — it never places or terminates a call.
AI voicemail / missed-call callbacks
An inbound route can opt into an AI-agent auto-callback: the moment a voicemail is captured (or a genuine missed call terminates with no voicemail left), the platform places the callback through the same AI-agent outbound service a human click-to-call uses — no operator click required. The per-routeaiCallbackAgentId field on the inbound-route config carries the opt-in, and every existing outbound guard (quiet-hours, DNC, frequency caps, balance, per-agent outbound enablement) applies unchanged. Failures never block voicemail capture — the auto-callback is fail-soft by design and degrades to a log line.
A supervisor can also rescue an abandoned queue call directly from the wallboard: POST /api/v1/voice/supervisor/callbacks with { "abandoned_call_id": "…" } reads the caller’s ANI and inserts a pending callback row the existing dispatcher picks up on the next tick — the TCPA federal calling window is respected and the row’s first attempt defers if the recipient is currently outside it. Supervisor-role users may only rescue calls in queues they supervise; owner/admin surfaces bypass that gate.
5. Verification sequence
Run this in order on a fresh queue to prove the whole chain:- Configure the offer. On Voice → Queues, confirm the queue voices the in-queue press-1 offer and that
targetServiceLevelSecondsis set so the SLA forecast/gate can flag heads nearing the breach (see the SLA forecast guide). - Consent while holding. Place a test call, let it wait, press 1 when the offer plays, hang up. A row should appear under
GET /api/v1/voice/callback-in-queue?queue_id=…with statuspendingand a masked caller id. - Consent after overflow. Place a second test call, let it blow past the queue’s overflow threshold, consent, hang up. A row appears under
GET /api/v1/voice/callbacks?queue_id=…— and the dashboard’s Voice → Callbacks page shows both queues’ lists. - Exercise the public token link. When the dispatcher dials, the delivered SMS link resolves
GET /api/v1/public/callbacks/<token>— confirm the status page reflects the row, and?action=canceltransitions it tocanceled. - Exercise the operator mutations.
PATCH /api/v1/voice/callbacks/:idwith{ "action": "retry_now" }returns 200 immediately after a fresh consent; a secondretry_nowon adialingrow returns 409. - Persist an SLA policy + scan. Run the
PUT …/callback-sla/policycall from section 3, thenPOST …/callback-sla/breach-scan; the response names which notify surface fired, and the org-admin bell shows the alert.GET /api/v1/voice/sla-hubrolls the result up with every other queue’s policy. - Rescue an abandoned call. Place a call, hang up before an agent picks up (so the queue logs it
abandoned), thenPOST /api/v1/voice/supervisor/callbackswith that abandoned call id — the row appears in the same pending list the rest of the dispatcher drains.
Related
- Inbound queue SLA forecast: pre-suggest callback before breach — the advisory wave that flags heads for the press-1 offer before the queue’s SLA actually misses.
- Inbound queue SLA forecast + virtual callback gate — the queue-entry gate that blocks entries outright on an already-breaching queue and steers them to the virtual callback.
- Set up and run voice queues — create the queue, set the SLA target, and wire the alert rules the callback SLA breach rides on.
- Wallboard alarm rules — the supervisor alert surface that complements the callback SLA policy’s bell/webhook fan-out.