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

# Staff your first support queue end to end

> Walk a new contact-center tenant from empty to a staffed queue answering live calls with SLA alerting, a TV wallboard, and on-call armed — in one end-to-end run.

# Staff your first support queue end to end

A brand-new contact-center tenant starts empty: no queue, no agents, no wallboard, no on-call roster. This tutorial walks you through the full loop in the order you would stand it up on day one — create the queue, staff it, wire wrap-up, mount the wallboard, arm on-call, place the first real call, and settle into a day-one rhythm. Each section is a single task with the concrete API call or dashboard click, the expected result, and a pointer to the deeper reference for that surface.

When you finish, you will have a queue named "Support T1" staffed with one agent, a wallboard alarm firing on queue-depth breach, an on-call rotation that pages a real human, and wrap-up enforcement that holds an agent in after-call work until a disposition is picked.

## Before you start

You need an active tenant and a phone number (DID) whose inbound routing is pointed at a voice queue. If inbound routing is not wired yet, read [Inbound voice routing](/concepts/inbound-voice-routing) and [DNIS pattern routing](/guides/dnis-pattern-routing) first, then come back. The queue you create here will be the routing target.

**Dashboard paths referenced in this walkthrough:**

* **Voice → Queues** (`/voice/queues`) — create and manage queues
* **Organization → Team** (`/organization/team`) — invite and manage team members
* **Voice → Softphone** (`/voice/softphone`) — register a browser softphone
* **Voice → Wallboard** (`/voice/wallboard`) — the wallboard surface
* **Voice → Wallboard → Alarm Rules** — alarm rule CRUD
* **Voice → On-call & escalation** (`/voice/oncall`) — rotations and escalation policies
* **Voice → Monitoring** (`/voice/monitoring`) — live agent monitoring
* **Voice → Quality** (`/voice/quality`) — QA scorecards and evaluations

**API base path:** `/api/v1/voice`

**Authentication:** Clerk session (`Authorization: Bearer <token>`) or API key (`X-API-Key`).

***

## 1. Pick the queue and its SLA

A queue is the ACD target your DID routes to. Create it once; every subsequent operation keys on its `queue_*` id.

`POST /api/v1/voice/queues` takes a name, an SLA target, one overflow rule, and a ring strategy. The `targetServiceLevelSeconds` is the SLA numerator — the answer-within seconds a call must beat to count toward service level.

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/queues" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Support T1",
    "targetServiceLevelSeconds": 30,
    "maxWaitSeconds": 300,
    "overflowAction": "voicemail",
    "routingStrategy": "longest-idle",
    "announcePosition": true,
    "announceWaitTime": true,
    "rnaTimeoutSeconds": 20
  }'
```

**What you set here:**

* **`name`** — "Support T1", the label that shows on every tile, alert, and report.
* **`targetServiceLevelSeconds`** — 30 seconds. Calls answered within 30 seconds count as "met SLA." Pick a number your team can hold at normal staffing; this is the threshold every supervisor dashboard and alert rule reads against.
* **`maxWaitSeconds`** — 300 seconds (5 minutes). A caller waiting longer is sent to `overflowAction` (voicemail in this case).
* **`overflowAction`** — `voicemail` sends the overflowed caller to a voicemail box. Alternatives are `childQueue` (fail over to another queue) and `hangup`.
* **`routingStrategy`** — `longest-idle` gives the call to whichever available agent has been idle longest. Other options: `round-robin`, `fewest-calls`, `top-down`.
* **`rnaTimeoutSeconds`** — 20 seconds. If an agent's softphone rings for 20 seconds with no answer, the platform re-dispatches to the next available member.

The `200 OK` body returns the `id` (a `queue_*` string). Save it — every call below uses it.

**Dashboard check:** Open **Voice → Queues** after the POST. The queue tile for "Support T1" shows the name, the SLA target in seconds, the overflow action as a chip, and the routing strategy. The `stats` call populates the tile's figures (depth, wait, SLA percentage, and agent count) the first time a caller enters.

The full queue CRUD (updating fields, deleting, callbacks, dispatch tune-ups) is [Set up and run voice queues](/guides/voice-queues). That guide covers every field this tutorial skips — skill tags, hold music, periodic prompts, callback rescue, and the `skillLevels` / `minSkillLevel` dispatch layers.

```bash Node theme={null}
const res = await fetch("https://api.orbit.devotel.io/api/v1/voice/queues", {
  method: "POST",
  headers: {
    "X-API-Key": "dv_live_sk_your_key_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Support T1",
    targetServiceLevelSeconds: 30,
    maxWaitSeconds: 300,
    overflowAction: "voicemail",
    routingStrategy: "longest-idle",
    announcePosition: true,
    announceWaitTime: true,
    rnaTimeoutSeconds: 20,
  }),
});
const queue = await res.json();
console.log("Queue id:", queue.data.id);
```

***

## 2. Staff the queue

A queue with no members dispatches nothing. Staff it in three steps: invite a teammate to the organization, attach the right skills, and enroll them on the queue.

### 2.1 Invite a teammate

Open **Organization → Team** and click **Invite member**. Enter their email address and assign a role (agent-level is fine for a responder). The invite lands in their inbox.

Or do it over the API:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/organization/teams/invite" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "agent@example.com",
    "role": "agent",
    "skills": ["voice", "support", "english"]
  }'
```

**Skills matter.** When the queue has a `skills` field (it is empty in this tutorial, meaning any member is eligible), the call's `requiredSkills` intersect with the member's skills at dispatch time. For your first queue, leave both empty so every member is eligible. Add skill gates later as your roster grows — the mechanics are covered in [Set up and run voice queues](/guides/voice-queues).

### 2.2 Enroll the member on the queue

`POST /api/v1/voice/queues/{queueId}/members` adds the agent to the queue roster:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp/members" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "agentUserId": "user_01HJ...",
    "priority": 100,
    "skills": [],
    "state": "offline"
  }'
```

* **`agentUserId`** — the user id from the invite or the team list. Use the `user_*` or `agent_*` id.
* **`priority`** — dispatch preference (lower wins). Default 100 is fine for a single-queue roster. Set 1–10 for a VIP tier, 200+ for a fallback tier.
* **`skills`** — an empty array means "eligible for every call on this queue." Fill it when you want this agent to take only calls matching certain tags.
* **`state`** — `offline` is the safe initial state. The agent flips themselves to `available` from their softphone.

Repeat for each agent you need. List the roster with `GET /api/v1/voice/queues/{queueId}/members`.

### 2.3 Confirm the softphone registers

The agent opens **Voice → Softphone** (`/voice/softphone`) in their browser. The device status chip at the top reads one of three states:

* **Registered** — the WebRTC softphone is connected to the media edge. The agent can make and receive calls.
* **Unregistered** — the browser has not registered yet. Click the **Register** button; if the button is a toggle already showing as registered, check the browser console for WebSocket errors.
* **Error** — a SIP credential or network issue. Re-provision SIP credentials under **Voice → Extensions**, or check the troubleshooting path at [Voice call failure triage](/guides/voice-call-failure-triage).

When the status reads **Registered**, the agent flips their state to **Available** from the softphone panel. That flip is the step that makes them dispatchable.

The full softphone lifecycle (browser calling, desktop setup, companion apps) is covered in [Voice softphone and browser calling](/guides/voice-softphone-browser-calling).

***

## 3. Wire wrap-up

Wrap-up (after-call work, ACW) is the period after a call ends when the agent records the outcome before they can take another call. Two controls wire it:

### 3.1 Define the wrap-up code catalog

Create the codes the agent picks from on `POST /api/v1/voice/queues/{queueId}/dispositions`:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp/dispositions" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "resolved",
    "label": "Resolved",
    "sortOrder": 10
  }'
```

Add the codes your team needs:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp/dispositions" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"code": "escalated", "label": "Escalated to T2", "sortOrder": 20}'
```

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp/dispositions" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"code": "follow_up", "label": "Follow-up needed", "sortOrder": 30}'
```

### 3.2 Enable disposition enforcement

On the queue's update endpoint, flip `requireDisposition`:

```bash cURL theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"requireDisposition": true}'
```

With this on, the agent's `busy → available` flip is blocked until the most recent finished call has a recorded disposition code. The agent stays in wrap-up state until a code is picked. This is the enforcement gate — an agent who hangs up without recording an outcome cannot take the next call.

**What an agent sees during wrap-up:** after a call ends, their softphone panel shows the disposition picker with the codes you created. They select one and click **Submit**. The `busy → available` flip then proceeds automatically.

The full lifecycle — enforcement gate, AI suggestion endpoint, outlier-flag analytics, and the distinction between disposition tags (multi-select, tenant-wide) and wrap-up codes (single-select, per-queue, gate-enforced) — is on [Define and use disposition tags](/guides/voice-disposition-tags) and the [Wrap-up codes reference](/voice/wrap-up-codes).

***

## 4. Mount the wallboard

The wallboard is a full-screen supervisor surface designed for a shared display. Mount it once and it auto-cycles KPI tiles, queue health, agent states, SLA warnings, and the top-performer leaderboard.

### 4.1 Set up the display

Follow the [Wallboard TV setup runbook](/guides/wallboard-tv-setup): create a dedicated browser profile, sign in with a supervisor-level account, open **Voice → Wallboard** (`/voice/wallboard`), and full-screen the browser. The board auto-rotates tiles; the default cycle is tuned for a 30–60 second cadence per page.

The cross-channel board at **Wallboard** (`/wallboard`, top nav) is the companion surface for the whole ops floor — messaging KPIs, the omnichannel queue panel, and the live operations band. This tutorial wires the voice-specific board; the cross-channel board is documented in [the wallboard guide](/guides/wallboard).

### 4.2 Wire an alarm rule

Alarm rules tell the wallboard when to escalate a metric from a stat into an alarm. Create one rule for queue-depth breach — fire a banner when "Support T1" has more than 10 callers waiting:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/wallboard/alarm-rules" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Support T1 queue too deep",
    "queue_id": "queue_supp",
    "metric": "waiting",
    "comparator": "gte",
    "threshold": 10,
    "duration_seconds": 0,
    "channel": "sse",
    "enabled": true
  }'
```

* **`metric`** — `waiting` means current callers in queue. Other options: `longest_wait`, `avg_wait`, `predicted_wait`, `agents_available`, `agents_total`, `service_level`, `abandoned_rate`.
* **`comparator`** — `gte` with `threshold: 10` means "fire when waiting count is 10 or greater."
* **`duration_seconds`** — `0` fires on the first breaching tick. Set a higher value (e.g. 60) to require the breach to persist before alarming.
* **`channel`** — `sse` delivers the alarm over the wallboard's live event stream, which the display renders as a colored banner. Other options: `sse+notification`, `webhook`, `email`.

Rules are evaluated every five seconds. When the waiting count drops below 10, the alarm clears automatically — the banner disappears from the display.

**What the room sees when it fires:** the wallboard's "Support T1" tile flips from its normal KPI state to a warning banner (amber if the metric is between the threshold and 2×, red beyond that) with the rule name, the current value, and the comparator. The banner stays until the metric recovers. A second, tenant-wide SLA alarm (e.g. `service_level` `<` 0.8) layers on top of the per-queue banner so the room sees queue-depth breach AND SLA breach at the same time without toggling.

The full rule shape, all eight metrics, delivery channels, and the recovery lifecycle are in [Wallboard alarm rules](/guides/wallboard-alarm-rules).

***

## 5. Arm on-call

On-call connects a queue to a human who gets paged when an incident fires. The surface lives at **Voice → On-call & escalation** and is backed by the `/api/v1/oncall` route group.

### 5.1 Create a rotation

A rotation defines a named shift schedule with an ordered member list. The endpoint resolves who holds the pager at any instant:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/oncall/resolve" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "rotation": {
      "name": "Support T1 Weekday",
      "members": ["user_01AA...", "user_01BB..."],
      "cadence": "weekly",
      "anchor": "2026-10-12T08:00:00Z",
      "handoff_day": "monday",
      "handoff_time": "08:00"
    }
  }'
```

* **`members`** — ordered list of user ids. The first member holds the pager from the anchor; after one cadence period, the second member takes over.
* **`cadence`** — `weekly` rotates every week. Other options: `daily`, `custom` (supply `shift_duration_hours`).
* **`anchor`** — the instant the first shift starts. Every subsequent shift is exactly one cadence period later — no timezone math to tune because each shift is the same duration added to the anchor.

### 5.2 Preview the escalation timeline

Wire the rotation into an escalation policy. This is the plan that answers "who gets paged at what offset when nobody acknowledges":

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/oncall/escalation/plan" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Support T1 Escalation",
    "steps": [
      {
        "stepIndex": 1,
        "target": { "type": "rotation", "name": "Support T1 Weekday" },
        "channels": ["sms", "email"],
        "acknowledge_after_seconds": 300
      },
      {
        "stepIndex": 2,
        "target": {
          "type": "users",
          "userIds": ["user_01CC..."]
        },
        "channels": ["sms", "voice"],
        "acknowledge_after_seconds": 0
      }
    ],
    "repeat": 2,
    "oncall_group_id": "group_fallback"
  }'
```

**How this plays out:**

* Step 1 pages the two members of "Support T1 Weekday" via SMS and email with a 5-minute (300-second) acknowledge window. If nobody acknowledges within 5 minutes, the timeline advances to step 2.
* Step 2 pages the on-call manager (`user_01CC...`) via SMS and voice call with no acknowledge window (fires immediately).
* `repeat: 2` means the whole ladder repeats twice before stopping. After two full repeats with no acknowledgement, the incident sits in the `timed_out` state.

The plan response returns absolute `fire_at` offsets you can schedule against. Store it and drive the incident with the `tick` endpoint.

### 5.3 Rehearse with the test incident driver

The incident driver at `POST /api/v1/oncall/incident/tick` advances a live test incident on your own timer. Start one in the dashboard at **Voice → On-call & escalation → Test Incident**, or call the API directly:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/oncall/incident/tick" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "plan_name": "Support T1 Escalation",
    "pages_fired": 0,
    "status": "open",
    "last_tick_at": "2026-10-12T10:00:00Z"
  }'
```

The response lists the pages due now, the new `pages_fired` high-water mark to persist, and `next_tick_at`. Transition the incident with `POST /api/v1/oncall/incident/transition` using `ack`, `resolve`, or `reassign`. The full tick/transition loop, the `409` guard on invalid state changes, and the per-endpoint field tables are in [On-call escalation runbook](/guides/oncall-escalation-runbook).

***

## 6. First-call gate

Now the queue is staffed and supervised. Place a real outside call to the DID and watch the full loop execute.

### 6.1 Place the call

From a real phone (not the softphone), dial the DID you routed to the "Support T1" queue. The inbound routing bridge lands the call on the queue, and the dispatch engine finds the staffed agent.

### 6.2 Watch the wallboard

On the wallboard display (step 4), watch these events in order:

1. The "Support T1" queue tile updates — the **In Queue** count ticks from 0 to 1, then **Longest Wait** starts climbing from 00:00.
2. The **Live operations band** (if you mounted the cross-channel board) shows one live call with the queue name.
3. The **Agent state strip** shows the agent's state flip from **Available** to **On Call** when the dispatch lands.

### 6.3 Watch dispatch land on the agent

On the agent's softphone panel at **Voice → Softphone** (`/voice/softphone`):

1. An incoming call notification pops — the caller number and the queue name appear.
2. The agent clicks **Accept**. The call connects; the wallboard's **Agents Available** count drops by 1, and the agent state reads **On Call**.
3. The agent and caller talk. The wallboard's **In Queue** count drops to 0 because the call is now being handled.

### 6.4 Watch wrap-up enforcement

When the agent hangs up:

1. The agent's softphone state flips to **Wrap-up** — not yet **Available**.
2. The disposition picker appears with the three codes you created in step 3.
3. The agent picks **Resolved** and clicks **Submit**.
4. The agent's state flips from **Wrap-up** to **Available**, and the wallboard's **Agents Available** count increments by 1.

If the agent tries to flip to **Available** without picking a code, the softphone blocks the flip — the enforcement gate you turned on with `requireDisposition: true`.

***

## 7. Day-one rhythm

After the first call, settle into a 30-second supervisor loop:

### The 30-second glance

Open **Voice → Contact Center** (`/voice/contact-center`) — the composite supervisor floor. Scan these three tiles in order:

1. **Queue pulse** — the six KPI cards across the top. Read left to right: In Queue (how backed up), Longest Wait (worst-off head), Service Level (against the 30-second target), Abandon Rate, Avg Handle Time, and Occupancy. The direction chips give first-sorting information — a green "down" chip on Abandon Rate and a green "up" chip on Service Level are the signal the floor is healthy.
2. **Alerts & Callbacks** card — the right rail's middle card. Red (**Breaching**) first, amber (**At risk**) second. Each row links through to the owning surface.
3. **Agent status board** — the roster filtered to **Available** and **On Call**. A long time in **On Call** with a short queue is normal; a long **Available** time with callers waiting means dispatch is not reaching that agent (check membership or skills).

The full floor walkthrough — what every panel means, the click-through destinations, and the common first-week supervisor patterns — is documented in [Contact Center live operations floor](/guides/contact-center-live-floor).

### Weekly audits

Run these once a week to keep the queue healthy:

| Audit | Where | What to check |
| - | - | - |
| Roster accuracy | `GET /api/v1/voice/queues/{id}/members` | Every member on the list is still active. Remove departed agents. |
| SLA policy | `GET /api/v1/voice/queues/{id}/sla-breach/policy` | The target is still realistic at current volume. Adjust `targetPercentage` and `thresholdSeconds` if your call mix changed. |
| Alarm rule noise | **Voice → Wallboard → Alarm Rules** | Delete rules that never fire (wrong threshold) or always fire (threshold too tight). A rule that fires every cycle trains the room to ignore it. |
| Wrap-up catalog hygiene | `GET /api/v1/voice/queues/{id}/dispositions` | Remove codes agents never pick; add ones that match new call types. Five to ten codes is the sweet spot — fewer and the data is too coarse, more and agents take too long choosing. |
| QA sample rate | **Quality → Evaluations → Scorecards** | Confirm the `sample_rate_pct` is still right for your weekly call volume. A 10% sample rate on 200 calls/week gives 20 evaluations — enough to spot a trend. |

***

## What good looks like on hour 3

At three hours in, a new tenant should have:

* [ ] A queue named "Support T1" exists at **Voice → Queues** with `targetServiceLevelSeconds: 30` and `overflowAction: voicemail`.
* [ ] At least one agent is enrolled on the queue (`GET /api/v1/voice/queues/{id}/members` returns a non-empty list).
* [ ] That agent's softphone reads **Registered** at **Voice → Softphone**, and their state is **Available**.
* [ ] The queue's `requireDisposition` is `true` (`GET /api/v1/voice/queues/{id}` — look for `requireDisposition` in the response).
* [ ] Three wrap-up codes are defined on the queue (`GET /api/v1/voice/queues/{id}/dispositions` returns at least three entries).
* [ ] One wallboard alarm rule fires on `waiting >= 10` and is `enabled: true`.
* [ ] The wallboard at **Voice → Wallboard** is rendering on a display with the "Support T1" tile visible and the alarm rule listed.
* [ ] One on-call rotation with two named members exists, and the escalation plan preview returns a valid timeline.
* [ ] One real outside call has flowed through the queue: the wallboard showed it arrive, dispatch landed it on the agent, and wrap-up enforcement held the agent in ACW until a code was picked.
* [ ] **Voice → Contact Center** opens with live figures on the queue pulse cards (not the sample-data placeholder — real numbers from your queue's live feed).

***

## See also

* [Set up and run voice queues](/guides/voice-queues) — the full queue CRUD and operations guide.
* [Wallboard: supervisor real-time tiles](/guides/wallboard) — the per-chip data provenance and time-window tuning.
* [Wallboard TV setup runbook](/guides/wallboard-tv-setup) — mount, rotate, and retire a shared display.
* [Wallboard alarm rules](/guides/wallboard-alarm-rules) — every metric, comparator, and delivery channel.
* [On-call deep dive](/guides/oncall-deep-dive) — the consolidated operator walkthrough for rotations and escalation policies.
* [On-call escalation runbook](/guides/oncall-escalation-runbook) — the tick/transition loop and timeout tuning.
* [Define and use disposition tags](/guides/voice-disposition-tags) — the full tag taxonomy, stamping, and reporting.
* [Build a contact-center QA program](/guides/quality-management-program) — scorecards, calibration, and the leaderboard.
* [Supervisor coaching](/guides/supervisor-coaching) — the follow-up after the floor flags a pattern.
* [Contact Center live operations floor](/guides/contact-center-live-floor) — the composite supervisor floor walkthrough.
* [Voice queues API reference](/api-reference/endpoints/voice) — parameter and response detail for every queue endpoint.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.