RustPBX Basics: IVR — Menus, Schedules, and When to Go External

M
Miuda Team
Building conversational AI tooling

Every PBX has an IVR. The differences that matter: how flows are authored, how they branch on time and data, and how easy it is to hand a call to an external brain when menus stop being enough. Here’s the RustPBX toolbox, inside-out.

Layer 1: Built-in IVR Flows

Flows live as TOML/JSON files under config/ivr/, or authored visually with the IVR Editor addon (drag-and-drop menus, business-hours control, TTS synthesis, multi-level menus — publish straight into the PBX).

IVR editor console

Inside the editor, each menu has its greeting (audio or TTS), timeout/retry behavior, and one card per DTMF key with its label and action — queue, transfer, sub-menu, voicemail, webhook, or hangup:

IVR editor — root menu with DTMF keys and per-key actions

Nodes cover the classics: play prompt, collect digits, menu branching, route to extension/queue/trunk, voicemail, and record. TTS prompts synthesize through the configured engine, with PBX-wide prompt aliases so third-party trees don’t hard-code engine-specific strings.

Layer 2: Schedules Inside the Flow

Flows branch on business hours, holidays, and night mode — the same schedule model as queues:

  • Business hours with timezone
  • A holiday map, each with its own action
  • Night mode for the daily cycle

One flow serves day and night, and the holiday map means February 17th doesn’t play your January greeting.

Layer 3: Step IVR — Your Code Decides

When menus aren’t enough — CRM lookups, AI decisions, anything dynamic — Step IVR externalizes the flow: each call step POSTs to your provider API, and your code answers with the next action (play, collect, bridge, transfer, hangup):

[ivr.provider]
url = "http://10.0.0.50:8080/ivr/step"
timeout_secs = 10

The protocol handles the hard parts: DTMF with timeouts, voice recognition results, recording completion, and a resume event so a flow suspended by a consult transfer continues exactly where it stopped — no menu replay.

Layer 4: The Safety Net

External providers fail. [proxy.ivr_fallback] routes the call into a local IVR when the provider can’t continue — rules matched with dialplan semantics, first match wins:

[proxy.ivr_fallback]
default = "default"

[[proxy.ivr_fallback.rules]]
name = "vip"
priority = 100
match = { "from.user" = "^9" }
target = "builtin_vip_step"

Callers never hear a failure; they hear a menu.

Layer 5: Full AI

Beyond step-by-step external logic, the realtime AI-voice bridge connects LLM agents to calls as a peer participant — see AI voice bots with human handoff for that pattern.

Guides: Step IVR and the IVR Editor.

Get new posts by email

Deep dives on Rust telephony, contact centers and wholesale voice. No spam.

Thanks — you're on the list.

We use cookies for anonymous analytics to improve the site. Nothing is loaded until you accept. Privacy Policy