queue node or a DID’s routing config; this page picks up where that traversal ends.
Base path: /api/v1/voice
Authentication: Clerk session (Authorization: Bearer <token>) or API key (X-API-Key).
Scope: voice write for management; voice read for monitoring.
1. Create the queue
POST /api/v1/voice/queues creates the queue and returns its id (an opaque queue_* string every subsequent call uses). Every queue setting is tenant-owned: you choose the SLA target, the overflow behavior, hold-music and announcements, the skills a caller must match, and the routing strategy.
cURL
name; defaults noted):
skills— the skill tags the queue requires. A call’srequiredSkills(set at enqueue) only dispatches to members whose own skills cover them; leave empty to accept any member.overflowAction— what happens when a caller exceedsmaxWaitSeconds(default 300s, bounds 30–3600). Choices:voicemail(default),childQueue(fails over to a designated queue), orhangup.targetServiceLevelSeconds— SLA numerator for the live dashboard’s Service Level metric (default 20s, bounds 5–300).announcePosition/announceWaitTime— play queue position or estimated wait time to waiting callers (both defaulttrue;announceIntervalSecondscontrols the spacing, default 30s, bounds 15–180).routingStrategy— member selection preference at dispatch time (defaultlongest-idle).welcomePromptUrl/periodicPromptUrl/holdMusicUrl— the queue’s own playback prompts. A malformed URL returns422before persistence.rnaTimeoutSeconds— ring-no-answer timeout before the platform re-dispatches to the next member (default 30s, bounds 5–120).- Callback tune-ups —
callbackMaxAttemptsandcallbackRetryIntervalsdrive the abandoned-callback rescue schedule whenabandonedCallbackRescueEnabledis on. - Dispatch tune-ups —
maxHoldSeconds,skillPriorities,minSkillLevel, andmaxOccupancyPctare optional dispatch-level edits.
PUT /api/v1/voice/queues/{id} accepts the same body as a partial update — omitted fields keep their stored value. DELETE /api/v1/voice/queues/{id} removes the queue; its waiting callers are terminated and its active calls route through the overflow fallback.
2. Enroll members
Agents become eligible the moment they appear on the queue’s member list. Membership carries the per-member dispatch order, the member’s own skill tags (intersected with the queue’s requirements), optional proficiency levels, and the initial state.cURL
agentUserId— the agent’s user id; either the Clerk-managed id or a platform-mintedagent_<hex>id works.priority— dispatch preference within the queue; lower wins (a VIP responder tier picks 1–10, a fallback tier picks 200+). Defaults to 100.skills— the member’s skill list. An empty array means the member is eligible for every call on the queue regardless of a call’srequiredSkills; a non-empty list intersects with the queue’sskillsand the call’srequiredSkillsat dispatch. Use it when a bilingual agent should only take Spanish calls or a senior agent should only take escalations.skillLevels— proficiency per skill (1–5), intersected with the queue’sminSkillLeveland composite weighting at dispatch.state— initial state while you wire the roster; the agent later flips themselvesavailableviaPOST /api/v1/voice/agents/{id}/status. The queue-safe default isoffline, so you can enroll the whole roster before anyone logs in.
PATCH /api/v1/voice/queues/{id}/members/{memberId} with any subset of priority, skills, state, skillLevels; DELETE removes the membership. List the roster with GET /api/v1/voice/queues/{id}/members (keyset-paginated, ?limit=50&cursor=...).
3. Priority queueing
Enqueue a caller when your routing logic parks the call on the queue (e.g. IVRqueue node outbound, or a manual dispatch). Lower priority numbers win; a caller bumped by a supervisor lands at priority 0.
cURL
callControlId— the voice leg’s platform call id. The queue’s FIFO, max-wait, and overflow semantics anchor on this id; once a call is enqueued, every subsequent queue endpoint keys on it.priority— initial ranking; smaller numbers pass earlier (0–99, default 10). Use supervisor-set business rules: a callback reservation comes in with an explicit priority, a VIP bump pushes priority to 0, a partners-tier queue assigns 5.requiredSkills— the caller’s own skill tags (e.g. a speech intent resolved upstream, or the contact’s account attributes) that intersect with member eligibility.
cURL
PATCH /api/v1/voice/queues/{id}/entries/{entryId} using a priority from 0–99 (0 is the queue head; the original wait clock is preserved, so a bump is a re-score, not a re-join).
4. Check membership before staffing
Before you trust the floor, the platform gives a tenant-wide head count of agents whose queue-membership plus skills make them dispatchable:cURL
stats.agentsAvailable. An agent who is a member of two queues (and whose skills satisfy both) is counted once — summing the per-queue figures double-counts bilingual agents and skews the staffing decision. Use available-agents in any capacity planner.
5. Watch queue health
Loop every supervisor aggregation in as often as the board refreshes. Live snapshot:GET /api/v1/voice/queues/{id}/live is an SSE stream, not a plain snapshot — the endpoint keeps the connection open and publishes, on each tick, the named metrics plus any alert rules that fire. If you only need one tick, poll the aggregate routes below; live is the continuous feed that powers the in-app wallboard.
cURL
GET /api/v1/voice/queues/{id}/analytics?from=...&to=...&interval=30m|1h|1d (30-minute default; optional fcr_window_hours tunes the First-Call-Resolution heuristic past the default-24h definition) returns per-interval sla_pct, aht_seconds, asa_seconds, abandon_pct, occupancy_pct, plus a fcr_pct (heuristic resolved against call logs) with the echoed window so you can label the column “FCR-24h”. ASA here is answered-queue-wait only; abandoned calls are excluded.
Hour-of-week heatmap: GET /api/v1/voice/queues/{id}/heatmap normalises into a 7×24 grid (missing cells are zero) so a wallboard can show when the queue’s SLA band saturates each week.
Queue comparison: GET /api/v1/voice/queues/comparison ranks queues side by side.
Hangup distribution: GET /api/v1/voice/queues/{id}/hangup-breakdown answers which overflow disposition (voicemail, child queue, hangup) takes the terminal volume.
Per-member leaderboard: GET /api/v1/voice/queues/{id}/agent-leaderboard ranks members on a chosen metric across the same supervisor visibility rules as the platform-wide wallboard.
Skill-by-window channeling: GET /api/v1/voice/queues/{id}/skill-breakdown collapses the [from,to] window into one row per skill (no interval bucketing) for a per-skill staffing check.
6. Emergency mode
Flip the queue straight to an off-queue destination when the floor takes an outage — fire drill, all-offline, an upstream carrier cutover. Arming requires a destination (E.164); the controller refuses anactive: true arm with no landing, and disarm leaves the queue’s normal overflow behavior intact.
cURL
emergencyActive flag on every ring, so a flip takes effect on the next call. Disarm by POST’ing active: false (destination optional, destination: null explicitly clears). Every queue.emergency_toggled event lands in the audit log so post-incident review correlates the cutover to a named supervisor.
7. Wrap-up and dispositions
Per-queue wrap-up codes let a finished agent record the outcome. The catalog is administered onGET/POST/PATCH/DELETE /api/v1/voice/queues/{queueId}/dispositions, with two guards built into disposition recording — only the assigned agent records the outcome, and free-text outcomes are rejected. A finished conversation posts its disposition with POST /api/v1/voice/queues/{queueId}/calls/{callId}/disposition:
(queueId, callId). Setting requireDisposition on a queue blocks the busy → available flip while the agent’s most recent finished call carries no recorded disposition, and the queue’s AI suggestion endpoint GET /api/v1/voice/queues/{queueId}/calls/{callId}/disposition/suggestion pre-fills a hypothesis to speed up the manual pick. The full lifecycle — enforcement gate, AI suggestion, outlier-flag analytics — lives on the wrap-up codes reference.
8. Wire queue alert rules
A supervisor defines thresholds the in-app live feed and the outbound webhook/email surfaces fire on. Alert rules bind to a queue, pick a metric, operator, and threshold, and become real when enabled.cURL
metricchoices:queue_depth,asa_seconds,abandon_rate,sla_pct,aht_seconds,occupancy_pct,agents_available. The canonical per-queue SLA breach alert issla_pctwithop = ltand a threshold like0.8.action—ssefor an in-dashboard banner (default),webhookto fan out a tenant webhook event of your choosing (thequeue.alert_rule_firedslug is the default; PagerDuty/Opsgenie/custom may subscribe), oremailto notify org admins.delivery_configtunes the override slug or the subject prefix for email.cooldown_seconds(0–86400; 300 default) suppresses re-fire; a rule that just fired is silenced across every delivery surface until its cooldown elapses.0restores legacy fire-every-tick.- Update with
PATCH /api/v1/voice/queues/{id}/alert-rules/{ruleId}— the patch needs at least one ofname,metric,op,threshold,action,delivery_config,enabled,cooldown_seconds;DELETEon a rule flips every dispatch surface off. List active rules withGET /api/v1/voice/queues/{id}/alert-rules.
9. Define the per-queue SLA breach policy
Alert rules cover ad-hoc thresholds; the SLA breach policy is the queue’s persistent service-level objective — the “80% of calls answered within 30 seconds over a 15-minute window” contract a queue breaches. You set it once per queue; every breach against it is logged and routed to the alert surfaces you choose.cURL
targetPercentage(1–100) is the service-level percent the queue must hold;thresholdSecondsis the answer-within bound a call must beat to count, andevaluationWindowMinutesis the rolling window the service level is measured over. The queue’s reported service level compares against the window’s offered-minus-short-abandon denominator — the same convention the analytics endpoint reports.breachActionis the one-shot response when no escalation ladder is set:open_ticket(notify org admins in-app and by email),page_supervisor(publish thequeue.alert_rule_firedtenant webhook — the payload a PagerDuty or Opsgenie subscription pages on),reroute_to_overflow_queue(both),enqueue_callback(webhook, so downstream automation queues a callback), ornone(log the breach, alert nobody). Read the current policy withGET; remove it withDELETE— a queue with no policy logs nothing and alerts nothing.escalationStepsis the per-queue ladder. When any step is set, the ladder replaces the one-shotbreachAction: step 1 notifies the duty supervisors immediately on breach, step 2 pages the escalation channel if nobody has fixed the queue 15 minutes later. Steps without a value fordelayMinutesAfterBreachof0are scheduled responses — they fire when a downstream executor reads the logged breach, not in the scan request itself. Each step’sactionTypeuses the same notify/reassign/slack/webhook vocabulary as inbox SLA policies.breachCooldownSeconds(0–86400) dedupes repeated breach alerts: a queue scanned every few seconds still pages at most once per cooldown window (floored at 60 seconds).
POST /api/v1/voice/queues/{id}/sla-breach/scan takes a window sample (offeredCalls, answeredWithinSla, optional shortAbandons, windowStart), compares the observed service level against the queue’s stored policy, and on a breach whose cooldown is clear: appends the breach event, fires the routing the policy selected, and returns the verdict (breached, alert_fired, observed_service_level). A queue with no policy answers policy_configured: false and does nothing.
Audit the breach history — GET /api/v1/voice/queues/{id}/sla-breach/events returns the queue’s newest-first breach log (up to 200 entries), each stamped with the observed service level, the policy in force, and the surfaces that actually fired. The supervisor wallboard’s breach-log tab reads this same endpoint.
10. Troubleshooting
- Queue is full of callers, but
agentsAvailablereads zero: those agents aren’t members of this queue, or their memberskillsdon’t match the queue’s requirements. RunGET /api/v1/voice/queues/{id}/membersto inspect the roster; an agent who exists on paper but has no member record is an empty pool until you enroll them with a POST. - A queue is stuck (longest wait explodes, ASA overflows, agents never pick): confirm the caller’s
requiredSkillsintersects at least one member’sskills. A badrequiredSkillsvalue dispatches nowhere and waits forever — flip it at enqueue or enrol a broader-skilled member. - Emergencies left on: a queue that still bypasses its agents after you disarm keeps a destination on file. Run
GET /api/v1/voice/queues/{id}and inspectemergencyActiveplusemergencyDestinationNumberbefore blaming the audit — the controller acceptsactive: falsewith any supplied destination. - The
available-agentsfigure says N but queues each show a higheragentsAvailable:available-agentscounts DISTINCT members once; the per-queue stats multiply agents whose skills satisfy more than one queue. The sum always over-reads; never tier-right on the per-queue number.
See also
- Build and route an IVR flow — the
queuenode that feeds this ACD surface - Wallboard — the TV-mounted display that renders this queue’s live tiles
- Wrap-up codes — the per-queue dispositions and enforcement gate
- Voice queues API reference — parameter and response detail for every queue endpoint