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

# Agent presence and aux-code lifecycle: the five states dispatch checks before it rings

> How login, aux (pause/away) codes, wrap-up windows, and dispatch move an agent through available, busy, wrapup, paused, and offline — and what ACD eligibility, omnichannel capacity, and supervisor surfaces read from each state.

# Agent presence and aux-code lifecycle

An agent's presence is the one fact every routing decision checks first. Voice dispatch looks at it before ringing, the omnichannel capacity ledger folds it into the digital load, and supervisor wallboards tile agents by it. This page defines the five-state machine those readers share, who moves each edge, and how it degrades when the persistence layer blips. It pairs with [Hold and pause reason codes](/voice/hold-reason-codes), which covers the code catalogs themselves, and the [Attendant console](/voice/attendant-console), which covers the live supervisor view.

## The five states

Presence lives on each queue membership — an agent holds one state per queue, and every reader (dispatch, capacity, wallboard) folds the memberships into a single worst-case state by severity: `busy > wrapup > paused > offline > available`.

| State       | Meaning                                                                                                                                                         | Blocks voice claim? | Blocks digital claim?                                                                                    |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------- |
| `available` | Ready for work; dispatch may ring this agent.                                                                                                                   | No                  | No                                                                                                       |
| `busy`      | On a live call.                                                                                                                                                 | Yes                 | Digital assignment still counts as load; the state just caps the voice slot at zero.                     |
| `wrapup`    | Post-call work (ACW). The agent has finished the conversation but stays off the eligible list while the wrap-up window runs or until they submit a disposition. | Yes                 | Voice slot counts as zero; digital weight drops to the smallest nonzero bracket.                         |
| `paused`    | On break, in training, at lunch — stepped away with a reason code.                                                                                              | Yes                 | **No. Digital claim never checks `paused`.** The voice lobby still marks the agent unavailable-by-pause. |
| `offline`   | Logged out.                                                                                                                                                     | Yes                 | Yes — the agent is excluded from any claim pool.                                                         |

The persistence CHECK constraint allows exactly these five values — the softphone toggle writes a four-value shorthand (`available | busy | away | offline`) and the API maps `away → paused` at the storage boundary, so the audit table always carries the full five-state vocabulary.

## Who moves each edge

```mermaid theme={null}
graph LR
  O[offline] -->|login| AV[available]
  AV -->|logout / idle-logout sweep| O
  AV -->|pause + reason code| P[paused]
  P -->|resume| AV
  P -->|logout| O
  AV -->|dispatch assigns a call| B[busy]
  B -->|call ends| W[wrapup]
  W -->|wrap-up timer expires, or agent submits disposition| AV
  B -->|logout mid-call edge| O
```

| Edge                                 | Owner of the transition                                                                                                                                             |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `offline → available`                | Agent login / softphone toggle (`POST /v1/voice/agents/:id/status`).                                                                                                |
| `available → offline`                | Agent logout, or the idle-logout scheduler sweeping agents parked `available` past the configured timeout.                                                          |
| `available` ↔ `paused`               | The agent picks a reason code from the softphone picker; resuming flips back. Optional org settings can auto-flip back on reason-code overrun.                      |
| `available → busy` / `busy → wrapup` | The dispatcher. It owns both edges — no agent action required to be marked busy or to enter wrap-up.                                                                |
| `wrapup → available`                 | The wrap-up expiry scheduler (`acd_queues.wrap_up_seconds`), or the agent submitting a disposition early. A tenant-acquired callback can clear wrap-up on dispatch. |

Every accepted toggle appends a row to the state-history audit with the old state, new state, and (for `paused`) the reason code — supervisors and WFM adherence read live state from the open event row, and reporting reads the closed history.

## Aux / pause reason codes

The platform ships five defaults — `lunch`, `bio`, `training`, `break`, `coaching` — and owners or admins extend the catalog per tenant:

| Endpoint                                         | Purpose                                                                                                                                                    |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /v1/voice/agents/pause-reason-codes`        | List active codes (`?include_inactive=true` shows retired ones). The list response also echoes the built-in defaults.                                      |
| `POST /v1/voice/agents/pause-reason-codes`       | Create a code (`owner`/`admin`). Codes that shadow a default are rejected with `422`.                                                                      |
| `PATCH /v1/voice/agents/pause-reason-codes/:id`  | Rename the label, set/clear the duration ceiling, or disable. The `code` itself is immutable so historical audit rows keep dereferencing to the same slug. |
| `DELETE /v1/voice/agents/pause-reason-codes/:id` | Soft-activate `false` — audit history stays resolvable while the picker stops offering the code.                                                           |

Codes are lowercase slugs matching `^[a-z0-9_-]+$`, up to 64 characters, with an optional `max_seconds` ceiling (1–86400). Setting a ceiling gives the overrun check something to fire on: when an agent sits in `paused` past the code's ceiling, a `state_reason.overrun` alert raises, and tenants that enable auto-available-on-overrun flip the agent back to `available` automatically. Codes with no ceiling alert manually — the supervisor nudges, the platform never assumes a duration it has not been given. For WFM reporting, `lunch`, `break`, and `training` are first-class adherence states; other codes roll into the generic unavailable bucket.

`paused` only gates voice. A digital-channel claim (chat, email, tickets) never checks it — the lobby excludes paused agents from the voice eligible list, and that is all the pause does to routing.

## Wrap-up window (ACW)

When a call ends, dispatch flags the membership `wrapup` and starts the queue's wrap-up timer. While it runs:

* The agent is excluded from the voice eligible list — no queue ring finds them.
* The window ends either when the scheduler's expiry fires (per queue, with a platform maximum on the queue's wrap-up setting) or when the agent posts a disposition early — a callback writeback also clears the state immediately so a taken callback does not idle behind the timer.

If an agent never submits and the timer expires while the queue is still dispatching, the membership flips back to `available` and the wallboard's wrap-up counter decrements. Design queue wrap-up durations to cover the longest disposition form your agents actually fill — the firing is a straight <code>elapsed > limit</code> check with no grace window.

## How dispatch consults presence

Two readers consume the same state, with different scopes:

* **Voice ACD.** When a call enters a queue, the eligible list is the members whose worst-case membership state is `available`. Ring order, skills, and offers are moot for a membership that is not eligible — so membership flips are never half-applied.
* **Omnichannel capacity.** For blended agents the capacity ledger gives each state a numeric voice bracket — `available` scores its full bracket, `busy` and `wrapup` score near zero, `paused` and `offline` score zero — and adds it to the digital conversation load to compute one saturation number per agent. The supervisor wallboard and the digital router sort on that number when deciding who should get the next conversation. Only `available` agents are dispatch candidates for either channel; the numeric bracket just orders them.

Both readers treat `offline` as empty-set — a logged-out agent disappears from the claim pool entirely, and the idle-logout sweep enforces that rather than leaving phantom-available rows.

## Where agents and supervisors read and write state

* **Softphone** (agent): the status toggle and the aux/pause picker. The toggle accepts `available | busy | away | offline`; `away` requires a reason code that must resolve against the defaults plus your tenant's active catalog, otherwise you get a `422`.
* **Attendant console** (supervisor): the live grid, staffed by the open-event reader, plus state-filter chips and per-agent drill-down. Full details in [Attendant console](/voice/attendant-console).
* **State history**: every accepted transition lands in the audit log with the reason code when paused; supervisors use it for adherence, and the soft-delete semantics of the reason catalog keep retired codes readable in that history for as long as the rows exist.

## Failure postures

Live routing treats the in-memory agent registry as the source of truth; the persistence write-through that mirrors states to the audit tables is best-effort. Concretely:

* When the audit write fails, the transition still happened — dispatch keeps working on the live registry and the missed history row just shows a gap in adherence reporting. The write failure is logged and counted, not raised to the client.
* When the queue's pause-catalog read hits a blip, the picker degrades to the platform defaults and the validator accepts the defaults-only set — no toggle is blocked for a tenant whose extension catalog is temporarily unreadable.
* When applying a softphone toggle and the catalog is down, an unknown code against a degraded catalog still `422`s — agents never invent a slug by mistake.

Both directions keep the same rule: reading a degraded view returns fewer options, writing with partial data never silently invents options.

## Owning your taxonomy

The default five codes are a starting vocabulary, not a mandate. Add tenant codes for the reasons your operation actually reports on (`hipaa_training`, `qa_review`, `team_standup`), give each a label agents read, and set a ceiling when you want overrun alerts. Codes stay tenant-owned and tenant-visible end to end — nothing here routes through platform-global gates, and the eligibility rules on this page are the same deterministic state checks dispatch runs, not predictive scoring.

## Cross-links

* [Hold and pause reason codes](/voice/hold-reason-codes) — the two catalogs (per-call hold vs. availability pause) and each endpoint field in full.
* [Attendant console](/voice/attendant-console) — the supervisor live grid consuming the states.
* [Wrap-up codes](/voice/wrap-up-codes) — the disposition codes submitted to close the ACW window.
* [Call disposition tags](/voice/call-disposition-tags) — taxonomy for the dispose-and-clear step.
