Skip to main content

The ACD queue model

Inbound voice and digital conversations reach a human through the same machinery: an ACD (Automatic Call Distribution) queue. A queue is a named pool of waiting work items — PSTN calls in a voice queue (/api/v1/voice/queues), chat/email/social conversations in a digital queue (/api/v1/inbox/digital-queues) — and a membership roster of the agents allowed to take them. Every tenant-owned control on a queue — SLA target, overflow action, skill requirements, routing strategy — is part of the same small model. This page explains that model once so the voice and digital operator guides are thin procedure surfaces on top of it. Read this before you wire a flow queue node, a DID’s routing config, or an inbox queue into production. The step-by-step setup lives on the voice queues guide and the omnichannel queue routing guide; this page covers what the underlying machine guarantees, not which buttons to click. The SLA-breach and escalation pipeline (the queue’s service-level objective) is a sibling concept page — read Per-queue SLA breach alerting and escalation policies after this one. Inbound routing decides where a conversation lands — a flow node, a DID config, or the inbox routing-rule evaluator. ACD queue routing decides who answers it, exhausted from a FIFO waiting list plus a member-eligibility filter. Outbound MT voice and SMS exit only through the Devotel wholesale softswitch — queue controls are inbound, tenant-owned configuration on /voice/queues and /inbox/digital-queues, never a provider-side or carrier-side signalling change.

1. What an ACD queue is — voice vs. digital vs. inbox routing rules

Three systems share the word “queue”: The voice queue covers PSTN and in-app call legs. The digital queue covers every inbox channel (chat, email, WhatsApp, SMS, RCS, social, the APAC OTT channels). The inbox routing-rule evaluator sits in front of both and decides which digital queue — or, if no queue matches, which direct-assigned user — a conversation even enters. Both voice and digital queues share the same five-state presence model and the same dispatch machinery, so one blended agent handles both channels; for a comparison column-by-column, the omnichannel queue routing guide spells out where the two shapes differ and where they converge on one supervisor surface.

2. The agent presence state machine

An agent’s membership row on a queue carries acd_queue_members.state — five values, one at a time:
  • available — eligible for dispatch right now
  • busy — on a live assignment
  • wrapup — post-call window; protected from new dispatch while the disposition screen stays open
  • paused — an auxiliary (AUX) code hold, “be back in 10 minutes”
  • offline — not on shift
Exactly one of four actors flips the state, so a member cannot strand outside the flow: Dispatch eligibility at scan time is a hard gate: state='available' and nothing else. A busy agent is mid-assignment; a wrapup agent is in their post-call window (the dispatcher skips them on purpose, so a waiting caller cannot interrupt the disposition screen); a paused agent has said “hold off”; an offline agent is not on shift. “Eligible” means available + a member of the queue + the member’s skills cover the queue’s requirements. POST /api/v1/voice/agents/{id}/status is the toggle surface the agent UI uses; an agent who needs more post-call time extends their own wrap-up window with POST /api/v1/voice/agents/me/extend-wrapup (bounded per window, audit-logged per extension). Omnichannel-capacity scoring blends in beside the gate: an agent available on voice but saturated on open digital conversations gets skipped by the blended loadScore that voice-queue routing, digital-queue routing, and the omnichannel work-item router all consume read-only. The capacity picture is a suggestion the dispatcher reads; the state gate is the rule.

3. Queue entry lifecycle — enqueue, dispatch scan, overflow

A work item enters a queue at enqueue and leaves either successfully (an eligible agent took it) or at an overflow action (its SLA window expired). Voice queue entry. POST /api/v1/voice/queues/{id}/enqueue creates a row in acd_call_queue_entries with a FIFO position and an optional call-level requiredSkills. Lower priority wins; a supervisor-set bump to priority=0 re-scores the caller’s spot without resetting the wait clock. Digital queue entry. Inbox routing rules (or a direct-assigned fallback) nominate the queue; the conversation is stamped onto a Redis waiting set, oldest first. Digital queue entries carry the conversation’s contact attributes and the channel’s identity, not a telephony id. FIFO dispatch walk. On every tick the dispatcher scans one queue:
  1. Filter members by state='available', queue skills, and the queue’s minSkillLevel requirement (next section).
  2. For a digital item, also subtract saturated agents by the blended loadScore; a candidate walk that finds nobody eligible stops and the item keeps waiting.
  3. Walk waiting entries in FIFO order, attempt the same eligibility filter per entry on its per-item requiredSkills.
  4. Assign the earliest entry that passes — a dispatched voice entry moves the member to busy, a dispatched digital entry does the same with the conversation reserved.
  5. If a member ignores the ring within the queue’s rnaTimeoutSeconds (default 30s), the dispatcher re-dispatches to the next eligible member.
Overflow actions are the terminal route for the item that ran out of time: The emergencyActive bypass (voice queue, per voice queues guide) skips the queue’s whole model: new callers route to a fixed E.164 destination on the next ring, independent of state or FIFO.

4. SLA and overflow — max_wait_seconds vs sla_seconds

Two different deadlines get conflated:
  • maxWaitSeconds (voice queues, default 300s, bounds 30–3600) — the caller-visible deadline. At expiry the caller is removed from FIFO and routed through the queue’s overflowAction. The queue’s targetServiceLevelSeconds is a separate reporting number the queue uses to compare its SLA % against — the SLA forecast, on the queue-sla-forecast-callback surface, pairs both against real traffic.
  • sla_seconds (digital queues) — the service-level deadline each waiting conversation is scored against on the queue’s waiting set. A scheduler pass walks the waiting set for items whose deadline has passed and re-routes each: assign if an agent freed up, otherwise apply the queue’s overflow action (routing_rules, overflow_queue, auto_responder, hold). The queue’s per-deadline SLA breach policy is a sibling set of configuration — read Per-queue SLA breach alerting and escalation policies for the full ladder (objective → forecast → breach → escalation) and how the breach policy chains with the queue’s overflow.
What happens at breach depends on which of those the queue is running — on voice, the caller’s own wait clock ends the FIFO wait; on digital, the sweep pass past the deadline decides whether the queue’s overflow action fires now or next sweep.

5. Skills and eligibility filtering

Skills are queue-scoped minimum plus member-scoped coverage:
  • queue.skills — the tags the queue as a whole wants (e.g. ["english", "billing"]). A member with any skill tag is eligible only if the member’s own list intersects — or the member carries an empty skill list, which is the wildcard “any skill” membership.
  • queue.minSkillLevel / per-call requiredSkills — the per-call filter the dispatcher intersects at scan time. A bilingual queue can require spanish on the queue’s skills without restricting member coverage; an escalation queue can require a senior support tag at enqueue without re-writing the queue.
  • member.skillLevels (1–5 per skill) — intersects the queue’s minSkillLevel requirement. A senior agent who needs billing rated 3+ matches; the same agent who’s a wildcard member does not have to be rated.
The dispatcher picks the earliest entry the filter passes — it does not pick the member. A wrong requiredSkills value (too narrow, or misspelled) blocks all eligible members from picking the oldest entry; the dispatcher keeps walking FIFO. Verify the filter is the gate by reading queue entry attributes, not by summing member availability.

6. Reading queue state

Three surfaces, hundreds of times a day:
  • Live snapshot per queueGET /api/v1/voice/queues/{id}/stats (voice) and GET /api/v1/inbox/digital-queues/stats / GET /api/v1/inbox/digital-queues/{queueId}/stats (digital). Current depth, longest-wait, available/busy, occupancy, plus the queue’s overflow counters on digital. The live SSE variant on voice keeps a supervisor’s wallboard in sync tick-by-tick; the digital queue stats are the tenant-wide read surface.
  • Windowed analyticsGET /api/v1/voice/queues/{id}/analytics?from=...&to=...&interval=30m|1h|1d (voice) returns per-bucket sla_pct, aht_seconds, asa_seconds, abandon_pct, occupancy_pct plus a First-Call-Resolution heuristic. The response is volume-weighted on the backend — read the returned summary, do not average buckets. Two sibling surfaces cover routing decisions and skill breakdown: GET /voice/queues/{id}/comparison and GET /digital-queues/{queueId}/decisions.
  • Routing decision auditGET /api/v1/inbox/digital-queues/{queueId}/decisions (and per-conversation GET /api/v1/inbox/routing-decisions/{conversationId}) is the “why did it land here” read. Every decision the dispatcher made — skills-filter reason, blended-load score, the queue entry it routed — is persisted in the audit trail; trace a stuck conversation from the queue or from the conversation id, not from member availability counts.
The full operator surface list (alert rules, per-member leaderboard, hangup breakdown, available-agents COUNT DISTINCT) is where the voice queues guide keeps its monitoring section. The omnichannel supervisor view (GET /api/v1/voice/supervisor/omnichannel-queue) blends both queue shapes into one position-ordered list — the same ordering the dispatcher assigns by. Once the model is clear, the voice queues guide walks the full setup sequence and the omnichannel queue routing guide covers the digital-queue/digital-ACD side without re-teaching the state machine.