Capturing DTMF Input with Read()
Capturing DTMF Input with Read()
Read() plays a sound prompt and waits for the caller to enter DTMFDual-Tone Multi-Frequency, the touch-tone signals phones send for digit input during a call, used by IVRs and feature codes. digits, storing the result in a channelA single call leg passing through Asterisk. Channels represent connections to endpoints and are what dialplan applications act on. variable. This is the foundation of PIN entry, extensionA dialplan entry that matches a dialed number or pattern within a context and triggers a sequence of prioritized steps. lookups, account number input, and any IVR that needs numeric data from the caller.
Basic Example
[ivr]
exten => s,1,Answer()
same => n,Wait(1)
same => n,Read(DIGITS,enter-ext-of-person,4)
same => n,Playback(you-entered)
same => n,SayDigits(${DIGITS})
same => n,Hangup()
PIN Verification
[pin-entry]
exten => s,1,Answer()
same => n,Read(PIN,agent-pass,6)
same => n,GotoIf($["${PIN}" = "123456"]?valid:invalid)
same => n(valid),Playback(auth-thankyou)
same => n,Goto(internal,s,1)
same => n(invalid),Playback(vm-incorrect)
same => n,Goto(s,1)
Extension Lookup
[dial-by-extension]
exten => s,1,Answer()
same => n,Read(EXT,enter-ext-of-person,4,,,5)
same => n,GotoIf($["${EXT}" = ""]?timeout)
same => n,Dial(PJSIP/${EXT},20)
same => n,Hangup()
same => n(timeout),Playback(vm-goodbye)
same => n,Hangup()
How it works
- Read(variable,filename,maxdigits,options,attempts,timeout): Plays the sound file and waits for DTMF input. Digits are collected until
maxdigitsis reached or the caller presses#. The result is stored invariable. - maxdigits: Limits how many digits are accepted. For a 4-digit extension, use
4. For open-ended input, omit this parameter and the caller terminates with#. - timeout: The last parameter is the timeout in seconds. If the caller doesn't press any key within this time,
Read()returns with an empty variable. Default is 10 seconds if not specified. - Sound files:
enter-ext-of-personandyou-enteredare built-in Asterisk sound files. They're searched in/var/lib/asterisk/sounds/<language>/. UsePlayback()beforeRead()if you need to play additional contextA named section of the dialplan that groups extensions. Calls enter a specific context and can only reach extensions visible from it, making contexts the basic unit of call routing and security.. - Empty input: Always check for empty input with
GotoIf($["${DIGITS}" = ""]?label)to handle timeouts and callers who don't enter anything.
Tips
- For multi-digit input where you don't know the length, omit
maxdigitsand let the caller press#to finish:Read(DIGITS,enter-your-account-number). - Chain
Read()withSayDigits()to read back input digit by digit ("four five six zero"), orSayNumber()to speak it as a whole number ("four thousand five hundred sixty"). UseSayDigits()for extensions and account numbers. - For a retry loop, use a counter:
Set(TRIES=0)then increment on invalid input andGotoIf($[${TRIES} < 3]?retry). Read()only captures digits 0-9,*, and#. The#key always terminates input when pressed; there is no option to treat it as a collectible digit.- Combine with
CHANNEL(language)to play localized prompts:Set(CHANNEL(language)=es)switches to Spanish prompts. - For IVR menus where each digit routes to a different destination, use
Background()+WaitExten()instead ofRead(): they're designed for single-key menus.
User Notes
Know a tip or gotcha for this topic? Share it below and help others.
Contribute a note
Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.