Prompt
How do I build an IVR that plays prompts, collects keypad input, and transfers calls?
Latest observation
To build an IVR (Interactive Voice Response) system that plays prompts, collects keypad input, and transfers calls, you typically need 5 pieces:
-
Telephony provider
A service that can answer calls and send you events for digits pressed.- Examples: Twilio, Vonage, Plivo, SignalWire, Amazon Connect
- Or a PBX/VoIP stack like Asterisk/FreeSWITCH
-
Call flow logic Decide what happens at each step:
- greet caller
- ask for input
- validate digits
- route/transfer based on input
- handle invalid input / timeout / repeat menu
-
A web server / app Your app returns instructions to the telephony provider:
- play audio prompts
- gather DTMF keypad input
- connect/transfer the call
-
Audio prompts Pre-recorded prompts or text-to-speech:
- “Press 1 for sales, 2 for support…”
- “Please enter your account number…”
-
Call routing/transfer targets Phone numbers, SIP endpoints, queues, or internal extensions.
Basic IVR flow
Example menu:
- “Welcome to Acme.”
- “Press 1 for Sales”
- “Press 2 for Support”
- “Press 3 to leave voicemail”
- If caller presses 1 → transfer to sales
- If caller presses 2 → transfer to support
- If no input → repeat prompt or send to operator
Example architecture
Option A: Hosted CPaaS (simpler)
- Incoming call hits Twilio/Vonage/etc.
- Provider sends webhook to your app
- Your app returns XML/JSON instructions
- Provider plays prompt, gathers digits, transfers the call
Option B: Self-hosted PBX (more control)
- Incoming call hits Asterisk/FreeSWITCH
- Dialplan answers call, plays prompts, collects digits
- Routes to SIP trunk, extension, or PSTN number
Simple implementation pattern
1) Answer the call
When a call comes in, your provider sends a webhook to your backend.
2) Play a prompt and collect input
Use a “gather” or “menu” action with:
- timeout
- number of digits
- terminator key (
#) - retries
3) Route based on input
If digit is:
1→ transfer to sales number2→ transfer to support number3→ voicemail or operator
4) Handle edge cases
- invalid digit
- no digit entered
- caller hangs up
- transfer fails
- after-hours routing
Example with Twilio (very common)
Twilio uses TwiML to control calls.
Step 1: Webhook endpoint returns a menu
Node.js example
const express = require("express");
const app = express();
app.post("/voice", (req, res) => {
res.type("text/xml");
res.send(`
<Response>
<Gather numDigits="1" action="/menu" method="POST" timeout="5">
<Say voice="alice">Welcome to Acme. Press 1 for sales. Press 2 for support.</Say>
</Gather>
<Say>We did not receive your input. Goodbye.</Say>
<Hangup/>
</Response>
`);
});
app.post("/menu", (req, res) => {
const digit = req.body.Digits;
if (digit === "1") {
res.type("text/xml");
res.send(`
<Response>
<Dial>+15551234567</Dial>
</Response>
`);
} else if (digit === "2") {
res.type("text/xml");
res.send(`
<Response>
<Dial>+15557654321</Dial>
</Response>
`);
} else {
res.type("text/xml");
res.send(`
<Response>
<Say>Invalid choice.</Say>
<Redirect>/voice</Redirect>
</Response>
`);
}
});
app.listen(3000);
Step 2: Configure your phone number
In Twilio console, set the incoming voice webhook to:
https://your-server.com/voice
Collecting longer keypad input
If you need an account number or extension:
- set
numDigitsto expected length, or - allow variable length with
#as terminator
Example:
- “Enter your 6-digit account number, then press #”
Then your app validates it before routing.
Transferring calls
Common ways:
- Dial a phone number: transfer to PSTN
- Dial a SIP URI: transfer to a SIP endpoint
- Dial a conference room: for warm transfers or agent handoff
- Queue/ring group: route to multiple agents
Blind transfer
Immediately send the caller to another destination.
Warm transfer
Put caller on hold, speak to the agent first, then connect them.
Key IVR best practices
- Keep menus short: 3–5 options max
- Always provide a “speak to agent” option
- Add fallback for no input or invalid input
- Test on real phones, not just simulators
- Make prompts clear and slow enough
- Support business hours vs after-hours routing
- Log every menu step for debugging
If you want the fastest path
Use:
- Twilio or Vonage
- a small Node.js or Python webhook service
- pre-recorded prompts or TTS
- simple digit-based routing logic
If you want full control
Use:
- Asterisk
- dialplan scripts
- SIP trunks
- external logic via AGI/ARI
This is better if you need:
- on-prem deployments
- more custom transfer logic
- lower per-call dependency on a cloud API
If you want, I can give you:
- a working Twilio IVR example in Node.js or Python, or
- an Asterisk dialplan example for on-prem IVR.