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

# Per-queue SLA breach alerting and escalation policies

> The queue SLA pipeline as one system: define each queue's service-level objective, forecast breaches from real traffic, fire the breach action you own, and run an escalation ladder that pages people before callers overflow — from first concept to a fully wired queue.

# Per-queue SLA breach alerting and escalation policies

An SLA on a voice queue is a promise with a consequence attached. The promise: *80% of callers answered within 30 seconds, measured over a rolling 15-minute window*. The consequence: the moment the queue falls behind that promise, Orbit notifies the person you named, starts the escalation ladder you defined, and — before any of that — offers the waiting callers a callback so nobody accrues hold time on a queue that is already missing its target.

This page is the map of that system. The four pieces each have their own detail page; this is the parent concept that shows how the objective, the forecast, the breach policy, and the caller-relief path connect into one pipeline, and how to wire them together for a real queue.

## Why queues, and why per-queue service levels

Callers queue for two reasons: **fairness** (first caller in is first answered) and **capacity** (the roster is finite, so multi-minute surges have to wait somewhere). Queuing is correct behaviour — the failure mode is queuing **silently**. Two independent things break silence:

* **The queue's service level is per-queue.** A support queue promising "80% in 30s" and a payments queue promising "95% in 20s" cannot share one global target — the payment promise is stricter, breaches sooner, and escalates to a different person. Every surface below reads the queue's own target, so changing the queue changes the whole pipeline at once.
* **A breached target is a routing signal, not a post-mortem stat.** Once the queue's rolling window says "we are missing our own target," three things should happen immediately: the supervisor hears about it, the escalation clock starts, and new or waiting callers get a way out that doesn't cost them their place. The pipeline below makes all three automatic; nothing is a report you read the next morning.

## The pipeline: objective → forecast → breach → escalation

Four pieces, each a queue-scoped configuration you own, each optional on its own, strongest together:

```
1. SLA objective      targetServiceLevelSeconds  — the queue's answer-within promise.
                      ┌─ forecast (same target → pre-breach flag → callback opt-in)
2. Forecast gate      slaCallbackPolicy          — refuse/strike entries on an already-breaching queue.
3. Breach policy      sla-breach/policy          — target % + window + what fires on a measured breach.
4. Escalation ladder  escalationSteps[]          — who hears next, and when, if the breach isn't fixed.
```

1. **The SLA objective** (`targetServiceLevelSeconds`, 5–300s) is the single source three engines share: the wallboard's service-level metric, the pre-breach forecast, and the breach policy's answer-within threshold. Set it once on the queue; every surface adopts it. A queue with no target is opt-out on every surface — nothing evaluates, nothing alerts.
2. **The forecast** runs far enough ahead to matter. The same evaluation wave that ages the queue's live stats projects each waiting head's wait against the target; a head whose projected wait meets or exceeds the target is flagged *before* the breach lands, so the "press 1 for a callback" offer reaches callers while it can still save their wait. The entry gate `slaCallbackPolicy` ('`suggest`' / '`block`') applies the same forecast to new arrivals — `block` refuses entry into an already-breaching queue and routes the caller to a position-saving callback. The forecast is advisory and bounded (at most ten heads per wave, closest-to-breach first); it never blocks a queue that hasn't opted in.
3. **The breach policy** (`/api/v1/voice/queues/{id}/sla-breach/policy`) is the persistent contract: `targetPercentage` of calls answered within `thresholdSeconds` over a rolling `evaluationWindowMinutes`. When a measured window misses the objective, `POST .../sla-breach/scan` appends the breach to the queue's event log once per window and fans out to the surfaces you picked. With no ladder, `breachAction` is the one-shot response: `open_ticket` (org-admin inbox item), `page_supervisor` (outbound tenant webhook your paging tool subscribes to), `reroute_to_overflow_queue` (both), `enqueue_callback` (webhook so downstream automation queues a callback), or `none` (log only).
4. **The escalation ladder** (`escalationSteps[]`) supersedes the one-shot action when any step is configured. Step 1 fires at breach + 0 minutes; later steps are delayed rungs a follow-up executor fires if the queue hasn't recovered — the breach log records the ladder as the effective route. Step actions reuse the inbox-SLA vocabulary (`notify`, `slack_alert`, `slack_webhook`, `teams_webhook`, `webhook`, `reassign`, `none`), so a supervisor who already runs inbox SLA policies is composing the same building blocks against a different clock. `breachCooldownSeconds` (default 300) dedupes repeated scans of the same window so one breach alerts once.

## Configure one queue

Everything below is per queue and takes effect on the next evaluation tick. The dashboard surfaces these same fields under **Voice → Queues → ‹queue› → SLA**, and the same queue feed powers the breach-log tab there.

```bash theme={null}
# 1. The objective — one field the whole pipeline shares
curl -X PUT "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 '{ "targetServiceLevelSeconds": 30, "slaCallbackPolicy": "suggest" }'

# 2. The breach policy — the promise plus the one-shot response
curl -X PUT "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp/sla-breach/policy" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "targetPercentage": 80,
    "thresholdSeconds": 30,
    "evaluationWindowMinutes": 15,
    "breachAction": "page_supervisor",
    "breachCooldownSeconds": 300
  }'

# 3. The escalation ladder — replaces the one-shot action once any step exists
curl -X PUT "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp/sla-breach/policy" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "targetPercentage": 80,
    "thresholdSeconds": 30,
    "evaluationWindowMinutes": 15,
    "escalationSteps": [
      { "stepIndex": 1, "delayMinutesAfterBreach": 0,
        "actionType": "notify", "actionConfig": {} },
      { "stepIndex": 2, "delayMinutesAfterBreach": 15,
        "actionType": "slack_webhook",
        "actionConfig": { "webhook_url": "https://hooks.slack.com/services/T000/B000/XXXX" } },
      { "stepIndex": 3, "delayMinutesAfterBreach": 30,
        "actionType": "teams_webhook",
        "actionConfig": { "webhook_url": "https://example.webhook.office.com/..." } }
    ]
  }'
```

Read the current policy with `GET .../sla-breach/policy`; remove the whole policy with `DELETE` — a queue with no policy logs nothing, gates nothing, and alerts nothing.

The scan is the trigger your monitoring loop drives. Feed it a window you've measured (from the queue stats endpoints or your own aggregation) and it returns the verdict:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp/sla-breach/scan" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "offeredCalls": 120, "answeredWithinSla": 87, "windowStart": "2026-08-25T14:00:00Z" }'
# -> { "breached": true, "alert_fired": true, "observed_service_level": 72.5, ... }
```

## How the forecast and callback close the loop

Alerts tell humans; the forecast tells callers. Without the callback leg, a breach queue only gets worse — every new arrival accrues hold the queue already can't afford, and every waiting caller ages past the objective while the escalation ladder climbs.

* **Pre-breach (the forecast wave):** callers whose projected wait is about to cross the target are flagged for the press-1 callback opt-in *before* the breach — the closest-to-breach heads first, bounded per wave. A consenting caller hangs up, keeps their position, and the callback-in-queue dispatcher dials them back over Orbit's voice trunk when they reach the front. See [Inbound queue SLA forecast: pre-suggest callback before breach](/voice/sla-breach-forecast-callbacks).
* **At entry (the forecast gate):** `slaCallbackPolicy: "block"` applies the same forecast to arrivals — the queue refuses the enqueue while breaching and routes the caller to the callback consent instead. `suggest` marks the callback as advised without refusing entry. See [Inbound queue SLA forecast + virtual callback gate](/voice/queue-sla-forecast-callback).
* **On a measured breach (the policy):** `enqueue_callback` as the breach action (or as a ladder rung's downstream automation) pushes the same relief into your own orchestration: your webhook consumer receives the breach event and queues callbacks for the waiting list.

All three legs terminate in the same callback dispatcher, so the safety gates are identical regardless of which one fired: emergency numbers can never be callback-dialed, outbound dialing respects the federal calling window for US numbers, and dialbacks place over the platform's standard outbound voice path.

## Observe the system

* **Wallboard.** The queue's service-level metric, the alarm rules you set on `service_level`, and the breach-log tab all read the same per-queue target and the same event log — one number, three renderings. Alarm rules cover ad-hoc thresholds ("service level below 80% anywhere"); the breach policy is the persistent objective. Wire both: [wallboard alarm rules](/guides/wallboard-alarm-rules).
* **Breach history.** `GET /api/v1/voice/queues/{id}/sla-breach/events` returns the newest-first log (up to 200 entries): the observed service level, the policy in force, and the surfaces that actually fired. That last field is your audit trail — it records what the ladder *did*, not what it was configured to do.
* **Live feed.** `GET /api/v1/voice/queues/{id}/live` streams the same metrics plus any fired alert rules over SSE; the supervisor flag for forecast-flagged heads surfaces there too.
* **Escalation audit.** Every policy write is audit-logged, and each escalation step that fires lands on the same surfaces the inbox SLA engine uses — query them the same way you audit inbox timers.

## End to end: one queue, one objective, one ladder

The support queue, doing the work: objective **80% in 30s over 15 minutes**, forecast gate on `suggest`, a three-rung ladder, and a wallboard alarm as the ad-hoc backstop.

1. **Steady state.** The queue answers 88% within 30s. The forecast wave projects head waits under target; the supervisor advisory stays `no_action`; the wallboard renders green against the same `targetServiceLevelSeconds: 30`.
2. **The surge starts.** A marketing send lands and the queue deepens. The forecast wave flags the head: projected wait 34s against the 30s target. The in-queue surface offers press-1 callback; three callers consent and keep their positions. New arrivals still enter (the gate is `suggest`, not `block`), each seeing the callback marked advised.
3. **The window turns.** Your monitoring loop posts the 15-minute window to `.../sla-breach/scan`: 120 offered, 87 within SLA → 72.5% vs the 80% objective. The cooldown is clear, so the scan appends the breach and fires rung 1 (`notify`) immediately — the duty supervisors see it in-app. The event log records `escalation_ladder` as the route.
4. **Nobody fixes it in 15 minutes.** The queue is still deep, so the follow-up executor fires rung 2: the Slack webhook posts the breach card to `#support-overflow`. A supervisor reassigns two agents from the payments queue.
5. **Recovery.** The window clears; the wallboard alarm (a tenant-wide `service_level < 0.8` rule) auto-clears with it. Rung 3 never fires. The breach log holds the full record — observed level, surfaces fired, and which rungs ran — for the QA review.

Each piece is optional and the queue is safe without any of them: an unconfigured queue queues callers and answers them, exactly as before. Configuring the whole pipeline turns "we missed our target" from a report into a route.

## Related pages

* [Set up and run voice queues](/guides/voice-queues) — create the queue, staff it, and define the per-queue SLA breach policy (section 9 covers the five `sla-breach` endpoints field by field).
* [Inbound queue SLA forecast: pre-suggest callback before breach](/voice/sla-breach-forecast-callbacks) — the forecast wave's flag math, bounds, and supervisor advisory.
* [Inbound queue SLA forecast + virtual callback gate](/voice/queue-sla-forecast-callback) — the entry gate's `suggest`/`block` verdicts and dispatch safety gates.
* [Wallboard alarm rules](/guides/wallboard-alarm-rules) — the ad-hoc alarm surface that complements the persistent breach policy.
* [Inbox SLA timers](/guides/inbox-sla-timers) — the same policy-plus-ladder pattern over messaging clocks; the escalation-action vocabulary is shared.
