> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# The ACD queue model: presence, skills, dispatch, and overflow

> How an inbound call or digital conversation moves through an ACD queue — what a queue entry is, the five-state agent presence machine, step-by-step FIFO dispatch, SLA timers and overflow actions, and the monitoring surfaces to read queue state.

# 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](/guides/voice-queues) and the [omnichannel queue routing guide](/guides/omnichannel-queue-routing); 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](/voice/queue-sla-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":

| Mechanism                                                        | What it decides                                                     | Where the config lives                                                      |
| ---------------------------------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| **Voice queue** (`/api/v1/voice/queues`)                         | Which agent takes an inbound call leg                               | one row per queue in the tenant's ACD tables                                |
| **Digital queue** (`/api/v1/inbox/digital-queues`)               | Which agent takes an inbound chat/email/social conversation         | a JSONB array in org settings (`organizations.settings.digital_acd_queues`) |
| **Inbox routing rules** (org-level rules, evaluated per channel) | Which queue (or user-fallback) an inbound conversation even targets | the same inbox surface the admin UI edits                                   |

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](/guides/omnichannel-queue-routing) 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:

| Transition                       | Actor                                                                                                      |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `offline → available`            | The agent's login / `POST /api/v1/voice/agents/{id}/status`                                                |
| `available → busy`               | The dispatcher, at assignment                                                                              |
| `busy → wrapup`                  | The call end (hangup by either side)                                                                       |
| `wrapup → available`             | The agent finishing the disposition screen, or `extend-wrapup` when the floor supervisor extends the timer |
| `available → paused → available` | An AUX code the agent picks from the tenant's AUX taxonomy                                                 |
| `available → offline`            | Logout, or a deliberate status flip                                                                        |
| anything → `paused`              | The agent's `POST /api/v1/voice/agents/{id}/status` call choosing an auxiliary reason                      |

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:

| Voice (`overflowAction`)       | Digital (`overflowAction`)                                                             |
| ------------------------------ | -------------------------------------------------------------------------------------- |
| `voicemail` (default on voice) | `routing_rules` — fall back to the org's inbox routing-rules engine, not the queue set |
| `childQueue`                   | `overflow_queue` — chain into a different digital queue's waiting list                 |
| `hangup`                       | `auto_responder` — answer the conversation automatically                               |
| —                              | `hold` — stay in queue with an audible "we're still working on it" banner              |

The `emergencyActive` bypass (voice queue, per [voice queues guide](/guides/voice-queues)) 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](/voice/queue-sla-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 queue** — `GET /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 analytics** — `GET /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 audit** — `GET /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](/guides/voice-queues) 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](/guides/voice-queues) walks the full setup sequence and the [omnichannel queue routing guide](/guides/omnichannel-queue-routing) covers the digital-queue/digital-ACD side without re-teaching the state machine.
