Skip to main content

Disposition and ACW model

When an inbound ACD call ends, the agent moves from busy to wrapup and the queue stops dispatching new calls to them until after-call work (ACW) closes. Everything in this page is the machinery that fills that window: picking (or confirming) a wrap-up reason, tagging the call, extending the timer when the work runs long, and — for operators — the catalogs, callback rules, suggestion ranking, and analytics that keep the data clean. Every control named here is tenant-owned; none of it touches carrier-side or provider-side signalling. Read the ACD queue model and agent presence lifecycle first — they own the five-state machine this window sits inside. The softphone procedure surfaces live on the voice queues guide; this page describes what the underlying system guarantees.

1. Reason-code families: what each one describes

“Disposition codes” is not one catalog. Five different families answer five different questions, and they live on separate axes on purpose — analytics joins them only at read time. The distinction that matters operationally: only the explicit disposition gates the busy → available flip on a queue with requireDisposition = true; the other four families are pure reporting and labeling. An agent can tag a call, or the queue can carry aux/pause/hold catalogs, and none of that satisfies a required disposition — only a recorded per-call disposition row does. One naming choice to be aware of: the ACD wrapup presence state is one of the aux adherence states too (available / on_call / wrap_up / break / lunch / training / unavailable / logged_out) — aux codes map onto that vocabulary so shift-level away time categories the same way default codes do. Every family is tenant-owned configuration; Orbit prescribes the shape (slug, label, ordering) and the tenant fills the vocabulary that fits their operation.

2. Wrap-up timers: extend, SLA, and when ACW closes

The wrap-up clock starts when call termination flips the agent to wrapup. Two things can close ACW: the agent completes the disposition screen, or the queue’s base wrap-up budget expires and the dispatcher flips the agent back to available itself (a flip that the disposition-required gate then keeps blocked on queues that require a code).

Extend-wrapup — bounded self-service runtime

An agent who needs more time — multi-level disposition pick, long note, CRM entry, or a consult — posts POST /api/v1/voice/agents/me/extend-wrapup with { delta_seconds, reason_code }. The delta is additive (an extension budget, not a new total) and cumulative extensions saturate at 600 extra seconds per window. Without it agents flipped themselves to away to buy time, which skewed adherence reports. One of five reason codes is required on every extension so the wallboard shows why the window grew: disposition, notes, crm_entry, consult, other. The call errors with a 409 when the agent is not currently in wrapup, so the softphone should only surface the button inside the window.

SLA clocks and disposition-required queues

Queue SLA reporting (the sla_seconds target and the escalation pipeline covered in queue SLA escalation policies) runs independently of wrap-up; wrap-up affects the agent’s availability for the next dispatch, not the caller’s wait. The ACW window closes, and the agent returns to the dispatch pool, only when either of these happens:
  • The agent records a disposition (or, on queues without the gate, simply closes the disposition screen).
  • The base budget plus any extension budget expire — and on a requireDisposition queue the agent then stays blocked away from available until a disposition exists.

3. Disposition callbacks and rules

A callback rule ties a chosen wrap-up code to a scheduled return call into the queue’s virtual-hold callback pipeline. Operators manage rules per queue: POST/GET/PATCH/DELETE /api/v1/voice/queues/{queueId}/disposition-callback-rules — each rule names a dispositionCode, a delayMinutes displacement, and an optional caller-id override. When the agent records that code on a call, the dispositions record path enqueues one callback_requests row with next_attempt_at = now + delayMinutes, and the shared dispatch scheduler picks it up — the same FIFO the caller-opted virtual-hold callbacks use (queue callback model); outbound still exits only via the Devotel softswitch. Rules are looked up on every disposition record (no cache), so an operator toggle takes effect immediately. When the queue has no active rule for the chosen code, or the caller’s number can’t be resolved from the inbound call log, the enqueue is skipped by design — the recorded wrap-up is durable either way, and the POST returns 201 with a no-op summary. Scheduled redial belongs in the same dialer pipeline from there: everything the dispatch does elects the same measured pacing and settled-cost accounting every callback uses.

4. Suggestion ranking: confidence and the override flow

GET /api/v1/voice/queues/{queueId}/calls/{callId}/disposition/suggestion reads the call transcript once the call ends and returns a non-authoritative pick — { dispositionId, dispositionCode, label, confidence, reasoning, needsReview, model } — against the queue’s active catalog, ordered the way the picker renders (root codes before their single-level sub-codes). Ranking is a recommendation, never a write: the softphone can pre-select the suggested code, but the agent’s POST .../disposition confirm is the sole source of truth for what gets recorded, and under the owning-agent gate only the assigned agent (or an owner/admin) records it. Four miss classes return 200 { suggestion: null, reason } and the picker falls back to manual selection: no_transcript (no usable transcript yet), no_catalog (queue has no active codes), low_signal (the ranking step produced something off-catalog or unusable), unavailable (the ranking dependency is down). needsReview = true marks a pick below the review-confidence threshold so the softphone can render it as “confirm” rather than “pre-selected”. A suggestion never overrides an explicit pick — the explicit write wins every time, and the gate that checks busy → available never consults rankings. The agent confirms, overrides, or ignores the suggestion; the ranking pipeline never mutates the disposition record.

5. Analytics: the disposition-mix funnel

Because the disposition gate guarantees a recorded per-call row exists, GET /api/v1/voice/dispositions/analytics aggregates those rows into the supervisor wrap-up insight funnel over a window (default trailing 30 days, hard-capped at 92):
  1. Fleet-wide distribution — per-code counts with each code’s share of all recordings.
  2. Per-agent distribution — the same mix broken out per agent (busiest first).
  3. Outliers — agents whose per-code share deviates from the fleet baseline, flagged warning/critical with the deviation direction.
Query parameters scope the funnel: ?from&to (ISO instants), ?queueId (one queue), ?minSample (minimum recordings before an agent is eligible for outlier flagging). Owner, admin, and supervisor roles read it; an agent never sees cross-agent aggregates. Human-name resolution degrades to a null agentName for deactivated users; the funnel keys on the stable persisted agent id instead. Treat the ranking surface’s model field and the suggestion hit/miss outcomes the same way you’d treat QA on manual picks: they tell the supervisor how often the picker actually accepted a suggestion, which closes the loop on whether the queue’s catalog labels are specific enough for ranking to help at all. Outbound MT voice and SMS exit only via the Devotel wholesale softswitch — every surface on this page is inbound, tenant-owned configuration on /voice/queues and /voice/agents, never a provider-side or carrier-side signalling change.