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

# Tutorial: the IVR-to-agent escalation ladder, validated on real caller audio

> Compose the classic escalation ladder — DTMF menu for the common paths, NLU catch for the rest, queue with announced wait, AI agent on hold and after hours — collect slot-filled intake before escalation, validate the speech layer with ten real utterances in the STT playground, and read VAQI after launch.

The pieces of a production IVR each ship with their own guide: the visual builder, NLU routing, slot-filling, AI handoff, and the STT playground. This tutorial composes them into the one pattern most support lines actually run, in the order that keeps callers off hold: a DTMF menu for the common paths, an NLU catch for everything else, a human queue with an honest wait estimate, and an AI agent that picks up when the wait grows or the office closes. The last step before launch is the one demos skip: running your real callers' audio through the STT playground and picking the engine and model preset on measured evidence.

## 1. Draw the ladder

The ladder has four rungs, and every caller falls to the cheapest rung that can handle them:

```text theme={null}
Inbound call
  └─ Rung 1: DTMF menu (Start Gather)     billing = 1, orders = 2, everything else = 0
       ├─ 1 → billing queue
       ├─ 2 → orders queue
       └─ 0 / no match
  └─ Rung 2: NLU catch (open speech)     routes what the menu could not
       ├─ matched intent → owning queue
       └─ low confidence
  └─ Rung 3: human queue                announcePosition + announceWaitTime on
       ├─ agent frees up → warm bridge
       └─ wait crosses your ceiling
  └─ Rung 4: AI agent                   on long wait and after hours
```

Build it on the canvas as in [First IVR via the Visual Builder canvas](https://docs.orbit.devotel.io/guides/ivr-visual-builder-first-flow.md): a **Start Gather** node for the menu, an NLU-tagged gather for the catch, a **Queue** node, and the AI agent as the queue's overflow and after-hours target. The same nodes in the same order if you author in the DSL instead — the two doors write one graph, so pick per your team as in [Pick your IVR surface: canvas or DSL](https://docs.orbit.devotel.io/guides/ivr-builder-canvas-vs-dsl-walkthrough.md), and keep the ladder in your repo with [Flows as code](https://docs.orbit.devotel.io/guides/flows-as-code-publish-pipeline.md) if you publish through CI.

Rung 1 stays DTMF on purpose. Callers who know why they are calling press a key in two seconds; spend NLU and STT latency on the callers who do not. Keep the menu to three choices and route the zero key and no-input into the NLU catch rather than repeating the menu.

Rung 2 is the NLU catch from [Build an IVR flow with NLU intent routing](https://docs.orbit.devotel.io/guides/ivr-routing-nlu.md): model one intent per owning queue, test your fixture utterances against the confidence threshold before publish, and let low confidence fall through to Rung 3. A human queue is the correct fallback for an unsure NLU; a wrong queue is not.

Rung 3 is a real queue with an honest wait. Create it with announcements on so callers can make their own escalate-or-hold decision:

```json theme={null}
POST /api/v1/voice/queues
{
  "name": "support-overflow",
  "announcePosition": true,
  "announceWaitTime": true,
  "announceIntervalSeconds": 30,
  "maxWaitSeconds": 240,
  "overflowAction": "ai-agent"
}
```

`maxWaitSeconds` plus `overflowAction` is the ladder's hinge: when the wait crosses your ceiling, the caller escalates to Rung 4 instead of hanging up. The same fields drive the after-hours path when no member is enrolled or logged in. See [Voice queues](https://docs.orbit.devotel.io/guides/voice-queues.md) for the full field contract, including `announceIntervalSeconds` bounds (15–180 s).

## 2. Slot-filling intake before escalation

Collect the top call reason's facts while the caller is still in the IVR, so the eventual human (or AI agent) opens with the answer half-built. Follow [Collect structured intake in an IVR with slot-filling](https://docs.orbit.devotel.io/guides/ivr-slot-filling-intake.md): one intent for the top reason, its required slots, and a prompt-confirm-reprompt loop. For a support line the top reason is usually the outage-or-problem report:

```json theme={null}
POST /api/v1/voice/ivr-intents
{
  "slug": "report_problem",
  "description": "Caller describes something that is broken or not working: no service, failed payment, an error, an outage at their address.",
  "slots": ["account_number", "problem_summary", "callback_ok"],
  "destination": { "type": "queue", "id": "support-overflow" }
}
```

Reuse the sample nodes from the slot-filling guide for the loop itself: prompt for one slot at a time, confirm each value back, and bias recognition with NLU hints for the words your callers actually say (plan names, product models, street names). When the loop completes, each filled slot lands in the flow as a `slot_<name>` variable and travels with the caller into the queue — the receiving agent's screen pop shows the account number and problem summary before the first hello. Cap the loop at two reprompts per slot; a caller who cannot supply a slot in three tries escalates with what you have, not with another apology.

## 3. Validate the speech layer first

This is the difference between a demo and a live IVR. Before you publish any rung that listens, run ten real utterances through the [STT playground](https://docs.orbit.devotel.io/guides/stt-playground.md) and pick the engine on the results, not on the vendor's marketing page.

Record or upload ten clips that match your callers, not a quiet office:

1. A Glaswegian caller saying your product names and a postcode.
2. A caller in a running car.
3. A Lagos English speaker spelling an account number.
4. A caller with a kitchen extractor fan behind them.
5. A short, mumbled "my internet's down again".
6. A Manila English speaker giving a billing address.
7. A caller on a windy sidewalk.
8. An older caller speaking slowly with long pauses.
9. A caller with a baby crying in the background.
10. A terse "press zero did nothing, I need a person".

Run the comparison across the vendors the playground lists and read it as an A/B: same ten clips, side-by-side transcripts, confidence, and latency. Score each vendor on the two failures that matter on an IVR — proper nouns mangled (account numbers, street names, plan names) and digits swapped — and note the p50 latency column separately.

Then pair the winning engine with a model preset. The picker's four presets, with their curated latency/quality tradeoff from [Pick a voice-agent model preset](https://docs.orbit.devotel.io/guides/agents-model-presets.md):

| Preset | Model | Latency (p50) | Cost per min | Quality | Best for |
| - | - | - | - | - | - |
| **Balanced** | Claude Sonnet 4.6 | \~900 ms | \~\$0.09 | 4/5 | General support, sales, scheduling — the default when unsure. |
| **High Intelligence** | Claude Opus 4.7 | \~1,400 ms | \~\$0.22 | 5/5 | Multi-step negotiation, technical troubleshooting, compliance-stakes calls. |
| **Ultra Fast** | Claude Haiku 4.5 (fast lane) | \~450 ms | \~\$0.05 | 3/5 | Sub-second barge-in lines, high-volume triage, short scripted flows. |
| **Cost Saver** | Claude Haiku 4.5 | \~650 ms | \~\$0.03 | 3/5 | Very high volume, simple conversations, margin-first lines. |

The numbers are curated comparison estimates, not per-call SLAs. Apply them to your playground results with two rules:

* If your ten clips carry account numbers, addresses, or plan names and the fast engine mangles them, pay for the better STT tier before you pay for a smarter model. A 5/5 LLM reasoning over a wrong account number is worse than a 3/5 reading the right one.
* If barge-in matters on this line (callers interrupt; most do), keep the whole path to first audio under a second: Ultra Fast exists precisely for that.

The playground comparison is ephemeral by design, so export or note the winning transcript table before you close it — section 7 reuses the same ten clips when you retest after launch.

## 4. Barge-in and prompt delivery on the agent leg

The AI agent that takes Rung 4 speaks to a caller who has already waited. Two settings decide whether that leg feels like rescue or like another menu:

* **Barge-in.** The caller will interrupt the agent's greeting; a caller on hold always does. If your playground latency plus preset p50 sits near or over a second, pick Ultra Fast for this leg so the agent stops talking when the caller starts, instead of finishing yesterday's sentence.
* **Delivery cues.** Write the wait into the prompts with timed pauses, as in [Timed pauses and expressive audio cues in voice prompts](https://docs.orbit.devotel.io/guides/voice-prompt-delivery-cues.md): `I can see you have been holding for a few minutes [pause:1.5s] let's get this sorted.` The pause gives the caller room to jump in, which is the barge-in you want. Check the provider matrix in that guide for how your chosen voice renders each tag, and audition the rendered audio before publish — cues that one voice renders naturally, another reads aloud as brackets.

Apply the same discipline to the queue announcements on Rung 3: a position-and-wait announcement with a natural pause outperforms a breathless one, and `announceIntervalSeconds` at 30 keeps the announcements from becoming the thing callers hold on to hear the end of.

## 5. Handoff semantics when a human frees up

When an agent logs in and the queue dispatches a caller who is mid-conversation with the AI agent, the handoff is warm by contract, as defined in [AI-voice warm handoff to a human agent](https://docs.orbit.devotel.io/guides/voice-ai-handoff-to-human.md): the AI agent calls its `transfer_to_human` tool, the live caller bridges into the queue, and the receiving human's screen pop carries the handoff packet — the AI's summary of the call, the caller's sentiment, and every collected slot from section 2. The human never asks for the account number again; it is the first line of the pop.

Two things to wire on purpose:

* Make `transfer_to_human` available on the Rung 4 agent and instruct it to hand off when the caller asks for a person, by name or by tone. A caller who asked for a human and got a faster robot still asked for a human.
* Turn on whisper coaching for the receiving agents while the ladder is new. A supervisor can whisper guidance into the agent's earpiece without the caller hearing, which is how a fresh queue absorbs its first escalated AI calls; setup is in [Agent assist: whisper coaching](https://docs.orbit.devotel.io/guides/agent-assist-whisper-coaching.md).

## 6. Fallbacks: failure loops, the DTMF escape hatch, callback deflection

Every listening node on the ladder gets the same three exits, configured per node:

1. **Recognition-failure loop count.** Two reprompts after a no-match or no-input, then the caller drops a rung — from NLU catch to human queue, never back to the same menu. A third repetition of the same question is where callers hang up.
2. **The DTMF escape hatch.** "At any time, press 0 for a person" on every gather, including the slot-filling loop. The zero key must route straight to Rung 3. This is the contract that makes the rest of the ladder tolerable: nobody is trapped in it.
3. **Callback deflection.** When the announced wait is long or the call arrives after hours, offer the SMS callback before the AI agent: the **Offer SMS Callback** node from the [First IVR via the Visual Builder canvas](https://docs.orbit.devotel.io/guides/ivr-visual-builder-first-flow.md) tutorial, and the missed-call side of the same coin in [Missed-call → SMS callback recipe](https://docs.orbit.devotel.io/guides/missed-call-sms-callback.md) for callers who abandon the queue or ring out. A caller who accepts a callback leaves the queue, your wait estimate drops, and the next caller's announced wait is honest again.

Check the queue's `callbackMaxAttempts` and `callbackRetryIntervals` if you enable abandoned-callback rescue, so a caller who accepted a callback and missed the first attempt gets the second one on a schedule you chose.

## 7. After launch: VAQI, containment, and the retrain loop

The ladder is live when the DID routes to it; it is *good* when three numbers move the right way:

* **VAQI.** The [VAQI dashboard](https://docs.orbit.devotel.io/voice/vaqi.md) scores your agent leg on live traffic — the measurement the preset table deliberately estimated. Run the before/after comparison the preset guide's VAQI section describes ([Pick a voice-agent model preset](https://docs.orbit.devotel.io/guides/agents-model-presets.md)): after-hours VAQI versus business-hours VAQI tells you whether the AI agent is carrying the load or just answering the phone.
* **Containment.** The [AI Containment and Resolution dashboard](https://docs.orbit.devotel.io/guides/agent-containment-dashboard.md) shows the share of agent conversations resolved without a human. For this ladder, watch it together with the IVR-to-queue volume: containment rising while queue volume falls means Rung 4 is absorbing real work, not just delaying handoff.
* **The retrain loop.** Escalations are your training data. Pull the recorded traces of calls that left the AI agent for a human, promote the instructive ones into an eval dataset with [Promote production traces into eval datasets](https://docs.orbit.devotel.io/guides/agent-trace-to-dataset.md), correct the transcript where STT got a proper noun wrong, and rerun your original ten playground clips through the [STT playground](https://docs.orbit.devotel.io/guides/stt-playground.md) before and after any engine or preset change. Ship the change only when the ten clips still transcribe clean and the eval set scores higher.

Run that loop monthly, or after any change to the menu, the intents, or the prompt copy. The ladder drifts as your callers' language drifts; the playground clips are how you notice.

## See also

* [First IVR via the Visual Builder canvas](https://docs.orbit.devotel.io/guides/ivr-visual-builder-first-flow.md)
* [Build an IVR flow with NLU intent routing](https://docs.orbit.devotel.io/guides/ivr-routing-nlu.md)
* [Collect structured intake in an IVR with slot-filling](https://docs.orbit.devotel.io/guides/ivr-slot-filling-intake.md)
* [STT Playground: compare speech-to-text vendors](https://docs.orbit.devotel.io/guides/stt-playground.md)
* [Pick a voice-agent model preset](https://docs.orbit.devotel.io/guides/agents-model-presets.md)
* [Timed pauses and expressive audio cues in voice prompts](https://docs.orbit.devotel.io/guides/voice-prompt-delivery-cues.md)
* [AI-voice warm handoff to a human agent](https://docs.orbit.devotel.io/guides/voice-ai-handoff-to-human.md)
* [Agent assist: whisper coaching](https://docs.orbit.devotel.io/guides/agent-assist-whisper-coaching.md)
* [Missed-call → SMS callback recipe](https://docs.orbit.devotel.io/guides/missed-call-sms-callback.md)
* [Voice queues](https://docs.orbit.devotel.io/guides/voice-queues.md)
* [Promote production traces into eval datasets](https://docs.orbit.devotel.io/guides/agent-trace-to-dataset.md)
* [Read the AI Containment and Resolution dashboard](https://docs.orbit.devotel.io/guides/agent-containment-dashboard.md)


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