> ## 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.

# Digital queues — skill-based ACD for the inbox

> Route inbound email, chat, and social conversations through skill-based digital ACD queues — match to the longest-idle eligible agent, hold on an SLA-timed waiting set, and overflow by policy.

# Digital queues — skill-based ACD for the inbox

Digital queues are the inbox's ACD (automatic call distribution) surface for non-voice channels. Where [routing rules](/inbox/routing-rules) decide *which facets* a new conversation matches, a digital queue decides *which agent* the conversation lands with — the longest-idle operator whose skills cover the queue's requirements — and what happens when no such agent is free. It is the digital counterpart of [voice queues](/guides/voice-queues): same skill-match, SLA, and overflow machinery, applied to conversation threads instead of call legs.

Queues govern inbound routing only. Nothing here changes how outbound messages or calls are placed; a queue never touches provider or carrier signalling.

## Where the page lives

Open **Inbox → Settings → Digital queues** in the dashboard. The page lists every queue you have configured — name, channel, SLA target, required skills, overflow action, and an enabled toggle — and opens a create/edit form for each.

You need an **owner or admin** role to see and manage the queue list. The same gate applies to the API: write endpoints (`POST`, `PATCH`, `DELETE` under `/api/v1/inbox/digital-queues`) reject any other role with `403 INSUFFICIENT_PERMISSIONS`; signed-in members can read the list and the live metrics. A workspace may hold at most 200 queues.

Everything on this page is tenant-scoped: queues live in your workspace's own settings, and a queue in one workspace can never see or route another workspace's conversations.

## Create a digital queue

1. Open **Inbox → Settings → Digital queues** and click **Create queue**.
2. Name the queue for the intent, e.g. "Email support — tier 1".
3. Pick the **channel** the queue serves: `email`, `web_chat`, `whatsapp`, `sms`, `rcs`, `viber`, `instagram`, `messenger`, `line`, `telegram`, `apple_messages`, `wechat`, `kakao`, or `zalo`. The first enabled queue whose channel matches an inbound conversation takes it, so order queues deliberately when several serve the same channel.
4. Set **Required skills** — agent tags from your workspace skill catalog. An agent is eligible only when their skills cover every skill you require; an empty list means any agent is eligible. Optionally set a **Minimum skill level** (1–5) when you track per-skill proficiency.
5. Set the **SLA target** in seconds (up to 86,400 — one day). This is the time-to-assignment promise the queue holds a conversation to; the dashboard defaults to 300.
6. Optionally cap **Max queue depth** (default 500) — the backpressure ceiling on the waiting set. A queue at its depth cap sheds immediately instead of holding.
7. Choose the **Overflow action** — what the queue does when it cannot place a conversation (below). For `overflow_queue`, pick the target queue.
8. Save, then enable the queue (queues are created enabled; toggle one off to pause routing without deleting it).

Equivalently, create over the API:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/inbox/digital-queues" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Email support — tier 1",
    "channel": "email",
    "required_skills": ["billing"],
    "min_skill_level": 2,
    "sla_seconds": 300,
    "max_queue_depth": 500,
    "overflow_action": "overflow_queue",
    "overflow_queue_id": "a1b2c3d4-…-target-queue-id",
    "enabled": true
  }'
```

The response returns the queue with its assigned `id`, which you pass to `PATCH /api/v1/inbox/digital-queues/:id` for updates (PATCH only the fields you send; explicit `null` clears `min_skill_level` and `overflow_queue_id`) and `DELETE /api/v1/inbox/digital-queues/:id` to retire it. A malformed body gets `422` with the failing field named; the 200-queue ceiling returns `409 LIMIT_EXCEEDED`.

## How routing behaves

A digital queue evaluates each inbound conversation on its channel in three steps:

1. **Assign** — if an eligible agent is available and has room under their per-channel cap, the conversation assigns immediately to the **longest-idle** such agent (ties break by lowest current open-conversation count). The agent gets a notification that the queue auto-assigned them.
2. **Wait** — if no eligible agent is free right now, the conversation joins the queue's waiting set with an SLA deadline stamped on it (`now + sla_seconds`). A scheduled sweep re-evaluates the set continuously: a conversation past its deadline assigns the moment an agent frees up, and only overflows when nobody is available at all.
3. **Overflow** — the queue sheds the conversation per its action. Overflow fires for one of three reasons: `queue_full` (the depth cap), `sla_breached` (waited past the SLA target with still no eligible agent), or `no_skilled_agents` (nobody in the workspace holds the required skills — waiting is pointless, so it sheds immediately).

The four overflow actions:

| Action           | Effect                                                                                                                                             |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `routing_rules`  | Defer to your [inbox routing rules](/inbox/routing-rules) — the universal fallback, and the default                                                |
| `overflow_queue` | Chain the conversation into another digital queue, up to 5 hops (a cycle falls back to routing rules)                                              |
| `auto_responder` | Mark the conversation for a canned auto-reply instead of holding it                                                                                |
| `hold`           | Never overflow on SLA expiry — re-arm the deadline and keep waiting (the depth cap still applies; a capped `hold` queue sheds via `routing_rules`) |

Use `hold` for asynchronous email queues where an indefinite wait is acceptable. Use `overflow_queue` for tiered escalation (tier 1 → tier 2). Leave the default `routing_rules` when your rules engine already encodes the fallback you want.

A conversation a routing rule already claimed never enters a queue — the queue engine only picks up conversations still unassigned, so the two never fight over an item.

## Composing queues with routing rules

Queues and rules are complementary, and the overflow handoff between them is explicit: `overflow_action: "routing_rules"` drops the conversation back to the same rules engine [Routing rules](/inbox/routing-rules) manages, so an unplaceable conversation is never dropped or hijacked — it falls back to the universal evaluator. Rules decide *who a conversation should route to*; queues apply skill-match, SLA, and backpressure on top. For the full operator loop (attribute routing, affinity policies, and SLA forecasting before conversations arrive), see [Omnichannel queue routing](/guides/omnichannel-queue-routing).

## Live metrics

Two read-only endpoints expose each queue's live state, and any signed-in workspace member can read them (metrics are deliberately wider than the admin-only write gate):

* **`GET /api/v1/inbox/digital-queues/stats`** — one row per configured queue plus a workspace rollup: `backlog` (conversations waiting), `oldest_wait` (age of the longest-waiting conversation, in seconds), `sla_breach_count` (conversations past their SLA deadline), `agents_available` (available, skill-eligible operators — distinct operators in the rollup, not a per-queue sum), and `virtual_holds` (customers who asked to be messaged back).
* **`GET /api/v1/inbox/digital-queues/:id/stats`** — the same snapshot for one queue; `404` when the id is not a configured queue.

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/inbox/digital-queues/stats" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

```json theme={null}
{
  "data": {
    "queues": [
      {
        "queue_id": "a1b2c3d4-…",
        "channel": "email",
        "backlog": 6,
        "oldest_wait": 242,
        "sla_breach_count": 1,
        "agents_available": 3,
        "virtual_holds": 0
      }
    ],
    "summary": {
      "backlog": 6,
      "oldest_wait": 242,
      "sla_breach_count": 1,
      "agents_available": 3,
      "virtual_holds": 0
    }
  },
  "meta": { "request_id": "req_01J…", "timestamp": "2026-09-12T08:31:04.118Z" }
}
```

The supervisor wallboard polls these on the same cadence as the voice board, so the digital floor and the voice floor read off consistent numbers. A transient backend issue degrades the board to zeros rather than an error.

## Auditability

Every applied routing decision is recorded — arrival → wait → SLA breach → overflow or assign — with the queue, the decision kind, the reason an overflow fired, and the agent an assignment chose. Two read-only trails answer "why did this conversation land where it did":

* **`GET /api/v1/inbox/digital-queues/:id/decisions`** — the queue's most recent decisions, newest first (up to 1,000; `?limit=` defaults to 100), for distribution debugging and SLA attribution.
* **`GET /api/v1/inbox/routing-decisions/:conversationId`** — one conversation's chronological trail across every queue it passed through.

Queue configuration itself is auditable too: create, update, and delete each write to your workspace [audit log](/guides/audit-log) with the acting user, the queue id, and the fields changed, so an owner can trace who retargeted a channel or relaxed a skill requirement.

## Troubleshooting

**Everything overflows immediately.** The queue carries a skill requirement no agent in the workspace holds — fix it by adding the skill to an agent's profile, or removing it from the queue (`no_skilled_agents` sheds without waiting). Check the workspace's skill vocabulary first.

**Conversations wait but never assign.** The eligible agents are present but at their per-channel conversation cap — the queue assigns only agents with headroom. Raise the cap, broaden the required-skills list, or add agents.

**A queue seems to do nothing.** Two checks: it is enabled (a disabled queue stays in your list but never routes), and the inbound conversations' channel slug matches the queue's channel exactly. If a routing rule already assigned the conversation, the queue engine intentionally leaves it alone.
