IVR (Interactive Voice Response) is an automated phone system that plays pre-recorded prompts and routes callers based on their keypad input. In Asterisk PBX, IVR is built entirely through the dialplan in extensions.conf – no extra modules or licenses needed. This guide covers IVR configuration on Asterisk 22 LTS using the modern PJSIP channel driver on Ubuntu 24.04 and Debian 13.

We will walk through planning a menu tree, recording prompts, writing complete dialplan contexts with business hours routing, nested sub-menus, database lookups, and a brief section on FreePBX GUI-based IVR creation. Everything here uses PJSIP (pjsip.conf), which replaced the legacy chan_sip driver and is the default in Asterisk 18+ and later. For official reference, see the Asterisk official documentation.

Prerequisites

  • A working Asterisk 22 LTS (or 20 LTS) installation on Ubuntu 24.04 or Debian 13. If you need to install Asterisk, follow our guide on installing Asterisk on Debian
  • Root or sudo access to the Asterisk server
  • At least one SIP phone or softphone (Zoiper, Linphone, MicroSIP) registered to your Asterisk server for testing
  • PJSIP channel driver loaded (default in Asterisk 18+)
  • Firewall ports open: UDP 5060 (SIP signaling), UDP 10000-20000 (RTP media)
  • Basic understanding of Asterisk dialplan concepts (contexts, extensions, priorities)

How IVR Works in Asterisk

When an incoming call hits an IVR context in the Asterisk dialplan, the system answers the call, plays an audio prompt (the greeting), and waits for the caller to press a DTMF key. Based on the digit pressed, the dialplan routes the call to another context, extension, queue, or voicemail box. If the caller presses an invalid key, the i extension handles it. If no key is pressed within the timeout, the t extension fires.

The key Asterisk applications used in IVR are:

  • Answer() – answers the incoming call
  • Background() – plays an audio file while listening for DTMF input
  • WaitExten() – waits for the caller to enter an extension
  • Goto() – jumps to another context, extension, or priority
  • GotoIfTime() – routes based on time of day (business hours)
  • Playback() – plays audio without accepting input
  • VoiceMail() – sends the caller to a voicemail box

Step 1: Plan the IVR Menu Tree

Before writing any dialplan code, map out your menu structure on paper. A good IVR should have no more than 3 levels deep and no more than 5 options per level. Always include an option to reach a live operator.

Here is the example company IVR tree we will build in this guide:

Main Menu (Welcome to Example Corp)
  Press 1 - Sales Department
    Press 1 - New Customers
    Press 2 - Existing Accounts
    Press 0 - Back to Main Menu
  Press 2 - Technical Support
    Press 1 - Network Issues
    Press 2 - Server Issues
    Press 0 - Back to Main Menu
  Press 3 - Billing Department
  Press 4 - Company Directory (dial by extension)
  Press 0 - Operator
  Timeout/Invalid - Replay menu (max 3 times, then operator)

This structure keeps things simple for callers while covering the main departments. Each sub-menu includes a way back to the main menu.

Step 2: Record IVR Prompts

You have three options for creating IVR audio prompts: record them directly through Asterisk, upload pre-recorded WAV files, or use text-to-speech.

Option A: Record Prompts Using Asterisk Record() App

Add a recording extension to your dialplan. Open /etc/asterisk/extensions.conf and add the following context:

[record-prompts]
exten => 500,1,Answer()
 same => n,Playback(beep)
 same => n,Record(/var/lib/asterisk/sounds/custom/ivr-welcome.wav,3,30,k)
 same => n,Playback(/var/lib/asterisk/sounds/custom/ivr-welcome)
 same => n,Hangup()

exten => 501,1,Answer()
 same => n,Playback(beep)
 same => n,Record(/var/lib/asterisk/sounds/custom/ivr-sales.wav,3,30,k)
 same => n,Playback(/var/lib/asterisk/sounds/custom/ivr-sales)
 same => n,Hangup()

exten => 502,1,Answer()
 same => n,Playback(beep)
 same => n,Record(/var/lib/asterisk/sounds/custom/ivr-support.wav,3,30,k)
 same => n,Playback(/var/lib/asterisk/sounds/custom/ivr-support)
 same => n,Hangup()

Create the custom sounds directory before recording:

$ sudo mkdir -p /var/lib/asterisk/sounds/custom
$ sudo chown asterisk:asterisk /var/lib/asterisk/sounds/custom

Dial extension 500 from any registered phone, speak the welcome message after the beep, and press # to stop recording. Asterisk plays back the recording so you can verify it sounds correct.

Option B: Upload Pre-recorded WAV Files

If you record prompts externally (professional voiceover, Audacity, etc.), convert them to the correct format and copy to the sounds directory. Asterisk expects 8kHz, 16-bit, mono WAV files for best compatibility:

$ sox ivr-welcome-original.wav -r 8000 -c 1 -b 16 ivr-welcome.wav
$ sudo cp ivr-welcome.wav /var/lib/asterisk/sounds/custom/
$ sudo chown asterisk:asterisk /var/lib/asterisk/sounds/custom/ivr-welcome.wav

Install sox if it is not already present:

$ sudo apt install sox

Option C: Text-to-Speech with Festival

For quick testing or low-budget setups, you can use Festival TTS with Asterisk. Install Festival and the Asterisk integration:

$ sudo apt install festival

Then use the Festival() application in your dialplan to generate speech on the fly:

exten => s,1,Answer()
 same => n,Festival(Welcome to Example Corp. Press 1 for sales. Press 2 for support.)
 same => n,WaitExten(5)

Festival TTS is fine for development and testing, but for production systems, always use professionally recorded prompts for a polished caller experience.

Step 3: Configure PJSIP Endpoints

Before building the IVR dialplan, make sure your PJSIP endpoints are configured. This replaces the old sip.conf approach. Edit /etc/asterisk/pjsip.conf and define your extensions. Here is a complete example with four department endpoints:

;; === Transport ===
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060

;; === Sales Extension 101 ===
[101]
type=endpoint
context=company-ivr
disallow=all
allow=ulaw
allow=alaw
auth=auth101
aors=101
callerid="Sales Dept" <101>

[auth101]
type=auth
auth_type=userpass
username=101
password=SalesSecure2026!

[101]
type=aor
max_contacts=2
remove_existing=yes

;; === Support Extension 102 ===
[102]
type=endpoint
context=company-ivr
disallow=all
allow=ulaw
allow=alaw
auth=auth102
aors=102
callerid="Support Dept" <102>

[auth102]
type=auth
auth_type=userpass
username=102
password=SupportSecure2026!

[102]
type=aor
max_contacts=2
remove_existing=yes

;; === Billing Extension 103 ===
[103]
type=endpoint
context=company-ivr
disallow=all
allow=ulaw
allow=alaw
auth=auth103
aors=103
callerid="Billing Dept" <103>

[auth103]
type=auth
auth_type=userpass
username=103
password=BillingSecure2026!

[103]
type=aor
max_contacts=2
remove_existing=yes

;; === Operator Extension 100 ===
[100]
type=endpoint
context=company-ivr
disallow=all
allow=ulaw
allow=alaw
auth=auth100
aors=100
callerid="Operator" <100>

[auth100]
type=auth
auth_type=userpass
username=100
password=OperatorSecure2026!

[100]
type=aor
max_contacts=2
remove_existing=yes

Each endpoint block defines the PJSIP registration, authentication, and address-of-record (AOR). The context=company-ivr setting places all calls from these endpoints into the IVR dialplan context. Note that PJSIP uses PJSIP/101 for dialing instead of the old SIP/101 syntax.

Reload the PJSIP configuration after making changes:

$ sudo asterisk -rx "pjsip reload"

Verify endpoints are loaded:

$ sudo asterisk -rx "pjsip show endpoints"

Step 4: Configure IVR Dialplan in extensions.conf

This is the core of the IVR setup. Open /etc/asterisk/extensions.conf and add the following contexts. This complete configuration includes a welcome greeting, business hours routing, main menu, sub-menus, timeout handling, and after-hours voicemail.

Incoming Call Handler with Business Hours

The incoming context checks the time and routes callers to either the live IVR or the after-hours message:

;; ============================================
;; Incoming call handler - checks business hours
;; ============================================
[company-incoming]
exten => s,1,NoOp(Incoming call from ${CALLERID(all)})
 same => n,Answer()
 same => n,Wait(1)
 ;; Monday-Friday 8:00-18:00
 same => n,GotoIfTime(08:00-18:00,mon-fri,*,*?company-ivr-main,s,1)
 ;; Saturday 9:00-13:00
 same => n,GotoIfTime(09:00-13:00,sat,*,*?company-ivr-main,s,1)
 ;; All other times - after hours
 same => n,Goto(company-after-hours,s,1)

After-Hours Context

When calls arrive outside business hours, play a message and offer voicemail:

;; ============================================
;; After hours - play message, offer voicemail
;; ============================================
[company-after-hours]
exten => s,1,Answer()
 same => n,Playback(custom/ivr-after-hours)
 ;; "Our offices are closed. Leave a message after the tone."
 same => n,VoiceMail(100@default,u)
 same => n,Hangup()

Main IVR Menu

This is the primary menu callers hear during business hours. It uses a loop counter to limit replays to 3 attempts before routing to the operator:

;; ============================================
;; Main IVR menu
;; ============================================
[company-ivr-main]
exten => s,1,Answer()
 same => n,Set(TIMEOUT(digit)=3)
 same => n,Set(TIMEOUT(response)=10)
 same => n,Set(IVR_RETRIES=0)
 same => n(menu),NoOp(IVR attempt ${IVR_RETRIES})
 same => n,Background(custom/ivr-welcome)
 ;; "Welcome to Example Corp. Press 1 for sales, 2 for support,
 ;;  3 for billing, 4 for company directory, 0 for operator."
 same => n,WaitExten(5)

;; Menu options
exten => 1,1,Goto(ivr-sales,s,1)
exten => 2,1,Goto(ivr-support,s,1)
exten => 3,1,Dial(PJSIP/103,30,r)
 same => n,VoiceMail(103@default,u)
 same => n,Hangup()
exten => 4,1,Goto(ivr-directory,s,1)
exten => 0,1,Dial(PJSIP/100,30,r)
 same => n,VoiceMail(100@default,u)
 same => n,Hangup()

;; Invalid input handler
exten => i,1,Playback(option-is-invalid)
 same => n,Set(IVR_RETRIES=$[${IVR_RETRIES}+1])
 same => n,GotoIf($[${IVR_RETRIES}<3]?s,menu)
 same => n,Playback(goodbye)
 same => n,Hangup()

;; Timeout handler
exten => t,1,Playback(are-you-still-there)
 same => n,Set(IVR_RETRIES=$[${IVR_RETRIES}+1])
 same => n,GotoIf($[${IVR_RETRIES}<3]?s,menu)
 ;; After 3 timeouts, send to operator
 same => n,Dial(PJSIP/100,30,r)
 same => n,Hangup()

The TIMEOUT(digit) setting controls how long Asterisk waits between key presses (for multi-digit input). TIMEOUT(response) controls how long it waits for any initial input. The IVR_RETRIES counter prevents infinite loops by sending callers to the operator after 3 failed attempts.

Sales Sub-Menu (Nested IVR)

The sales department has its own sub-menu with options for new and existing customers:

;; ============================================
;; Sales sub-menu
;; ============================================
[ivr-sales]
exten => s,1,Background(custom/ivr-sales)
 ;; "Sales department. Press 1 for new customers, 2 for existing
 ;;  accounts, 0 to return to the main menu."
 same => n,WaitExten(5)

exten => 1,1,Dial(PJSIP/101,30,r)
 same => n,VoiceMail(101@default,u)
 same => n,Hangup()

exten => 2,1,Dial(PJSIP/101,30,r)
 same => n,VoiceMail(101@default,u)
 same => n,Hangup()

;; Return to main menu
exten => 0,1,Goto(company-ivr-main,s,1)

exten => i,1,Playback(option-is-invalid)
 same => n,Goto(ivr-sales,s,1)

exten => t,1,Goto(company-ivr-main,s,1)

Support Sub-Menu

The support sub-menu routes callers to different support queues based on their issue:

;; ============================================
;; Support sub-menu
;; ============================================
[ivr-support]
exten => s,1,Background(custom/ivr-support)
 ;; "Technical support. Press 1 for network issues, 2 for server
 ;;  issues, 0 to return to the main menu."
 same => n,WaitExten(5)

exten => 1,1,Dial(PJSIP/102,30,r)
 same => n,VoiceMail(102@default,u)
 same => n,Hangup()

exten => 2,1,Dial(PJSIP/102,30,r)
 same => n,VoiceMail(102@default,u)
 same => n,Hangup()

exten => 0,1,Goto(company-ivr-main,s,1)

exten => i,1,Playback(option-is-invalid)
 same => n,Goto(ivr-support,s,1)

exten => t,1,Goto(company-ivr-main,s,1)

Company Directory (Dial by Extension)

Allow callers to dial a known extension number directly:

;; ============================================
;; Company directory - dial by extension
;; ============================================
[ivr-directory]
exten => s,1,Background(custom/ivr-directory)
 ;; "Enter the extension number you wish to reach."
 same => n,WaitExten(10)

;; Match 3-digit extensions starting with 1
exten => _1XX,1,Dial(PJSIP/${EXTEN},30,r)
 same => n,VoiceMail(${EXTEN}@default,u)
 same => n,Hangup()

exten => i,1,Playback(option-is-invalid)
 same => n,Goto(company-ivr-main,s,1)

exten => t,1,Goto(company-ivr-main,s,1)

The pattern _1XX matches any 3-digit number starting with 1 (100-199). Adjust the pattern to match your extension numbering scheme.

Step 5: Include IVR Context for Incoming Calls

For the IVR to handle incoming calls, include the incoming context in your default context or point your trunk to it. Add this line to your main context in /etc/asterisk/extensions.conf:

[default]
include => company-incoming

If you are using a SIP trunk from a VoIP provider, set the trunk’s context to company-incoming in the PJSIP endpoint definition for the trunk:

[my-voip-provider]
type=endpoint
context=company-incoming
disallow=all
allow=ulaw
allow=alaw
from_domain=sip.provider.com

After making all dialplan changes, reload the dialplan:

$ sudo asterisk -rx "dialplan reload"

Step 6: Test the IVR System

Connect to the Asterisk CLI with verbose output to watch calls flow through the dialplan:

$ sudo asterisk -rvvv

From the CLI, verify the dialplan is loaded correctly by checking each context:

CLI> dialplan show company-ivr-main

You should see output showing all extensions defined in the context. Verify PJSIP endpoints are registered:

CLI> pjsip show endpoints

Expected output shows each endpoint and its registration status:

 Endpoint:  100/100                                          Not in use    1 of inf
 Endpoint:  101/101                                          Not in use    1 of inf
 Endpoint:  102/102                                          Not in use    1 of inf
 Endpoint:  103/103                                          Not in use    1 of inf

Register a softphone (Zoiper, Linphone, or MicroSIP) with extension 101 and make a test call to the IVR. Watch the CLI for dialplan execution messages. Test each menu option, invalid input, and timeout behavior.

Check that audio prompts play correctly. If you have not recorded custom prompts yet, create placeholder files with Festival TTS or use the built-in Asterisk sound files for testing:

CLI> core show sounds

Step 7: Multi-Level IVR Example

For larger organizations, you may need three levels of menus: main menu, department, then individual person. Here is a pattern for a 3-level IVR. Add this to /etc/asterisk/extensions.conf:

;; ============================================
;; Level 1: Main menu
;; ============================================
[ivr-level1]
exten => s,1,Answer()
 same => n,Set(TIMEOUT(response)=10)
 same => n,Background(custom/ivr-main-greeting)
 same => n,WaitExten(5)

exten => 1,1,Goto(ivr-level2-sales,s,1)
exten => 2,1,Goto(ivr-level2-engineering,s,1)
exten => 0,1,Dial(PJSIP/100,30,r)

exten => i,1,Playback(option-is-invalid)
 same => n,Goto(ivr-level1,s,1)
exten => t,1,Goto(ivr-level1,s,1)

;; ============================================
;; Level 2: Sales team members
;; ============================================
[ivr-level2-sales]
exten => s,1,Background(custom/ivr-sales-team)
 ;; "Press 1 for Alice, 2 for Bob, 0 for main menu."
 same => n,WaitExten(5)

exten => 1,1,Dial(PJSIP/110,20,r)
 same => n,VoiceMail(110@default,u)
 same => n,Hangup()
exten => 2,1,Dial(PJSIP/111,20,r)
 same => n,VoiceMail(111@default,u)
 same => n,Hangup()
exten => 0,1,Goto(ivr-level1,s,1)

exten => i,1,Playback(option-is-invalid)
 same => n,Goto(ivr-level2-sales,s,1)
exten => t,1,Goto(ivr-level1,s,1)

;; ============================================
;; Level 2: Engineering team members
;; ============================================
[ivr-level2-engineering]
exten => s,1,Background(custom/ivr-eng-team)
 ;; "Press 1 for Charlie, 2 for Diana, 0 for main menu."
 same => n,WaitExten(5)

exten => 1,1,Dial(PJSIP/120,20,r)
 same => n,VoiceMail(120@default,u)
 same => n,Hangup()
exten => 2,1,Dial(PJSIP/121,20,r)
 same => n,VoiceMail(121@default,u)
 same => n,Hangup()
exten => 0,1,Goto(ivr-level1,s,1)

exten => i,1,Playback(option-is-invalid)
 same => n,Goto(ivr-level2-engineering,s,1)
exten => t,1,Goto(ivr-level1,s,1)

This three-level structure scales well for mid-size companies. Avoid going deeper than 3 levels – callers will hang up if they have to navigate too many menus.

Step 8: IVR with Database Lookup Using AGI

For dynamic IVR routing – such as looking up a customer account number and routing based on their account status – you can use AGI (Asterisk Gateway Interface) scripts. This example uses a Python AGI script that queries a database.

First, install the Python AGI library:

$ sudo apt install python3-pyst2

Create the AGI script at /var/lib/asterisk/agi-bin/customer-lookup.py:

#!/usr/bin/env python3
import asterisk.agi as agi
import sqlite3

def main():
    a = agi.AGI()
    account = a.get_variable('ACCOUNT_NUM')
    a.verbose("Looking up account: %s" % account)

    conn = sqlite3.connect('/var/lib/asterisk/customers.db')
    cursor = conn.cursor()
    cursor.execute("SELECT department FROM customers WHERE account_id=?", (account,))
    row = cursor.fetchone()
    conn.close()

    if row:
        a.set_variable('CUSTOMER_DEPT', row[0])
        a.verbose("Found department: %s" % row[0])
    else:
        a.set_variable('CUSTOMER_DEPT', 'unknown')
        a.verbose("Account not found")

if __name__ == '__main__':
    main()

Make the script executable:

$ sudo chmod 755 /var/lib/asterisk/agi-bin/customer-lookup.py
$ sudo chown asterisk:asterisk /var/lib/asterisk/agi-bin/customer-lookup.py

Then add the dialplan context that collects the account number and runs the lookup:

;; ============================================
;; IVR with database lookup
;; ============================================
[ivr-account-lookup]
exten => s,1,Answer()
 same => n,Playback(custom/enter-account-number)
 ;; Read 6-digit account number from caller
 same => n,Read(ACCOUNT_NUM,,6,,2,10)
 same => n,AGI(customer-lookup.py)
 same => n,GotoIf($["${CUSTOMER_DEPT}"="sales"]?ivr-sales,s,1)
 same => n,GotoIf($["${CUSTOMER_DEPT}"="support"]?ivr-support,s,1)
 same => n,GotoIf($["${CUSTOMER_DEPT}"="unknown"]?not-found,1)
 same => n,Goto(company-ivr-main,s,1)

exten => not-found,1,Playback(custom/account-not-found)
 same => n,Goto(company-ivr-main,s,1)

The Read() application collects digits from the caller. The AGI script queries the database and sets a channel variable. The dialplan then routes based on the result. For production use, consider using MySQL or PostgreSQL instead of SQLite, and add connection error handling to the AGI script.

Step 9: Configure IVR in FreePBX (GUI Method)

If you are running FreePBX on top of Asterisk, you can create IVR menus through the web interface without editing config files directly. See the Asterisk IVR documentation for background on how auto-attendants work under the hood.

To create an IVR in FreePBX:

  1. Log into the FreePBX admin panel at http://your-server-ip/admin
  2. Navigate to Applications > IVR
  3. Click “Add IVR” to create a new menu
  4. Set the IVR name (e.g., “Main Menu”), announcement (upload or select a recording), and timeout settings
  5. Under IVR Entries, add each digit option and its destination (extension, ring group, another IVR, voicemail, etc.)
  6. Set the “Invalid Destination” and “Timeout Destination” to replay the IVR or route to the operator
  7. Click Submit, then Apply Config

FreePBX generates the underlying Asterisk dialplan automatically. To point an inbound route to the IVR, go to Connectivity > Inbound Routes, select your DID, and set the destination to the IVR you just created.

For nested IVRs in FreePBX, create multiple IVR entries and set one IVR’s menu option to point to another IVR as the destination. The process is the same – each level is a separate IVR object in the GUI.

Troubleshooting Asterisk IVR Issues

Here are the most common IVR problems and how to fix them.

No Audio – Caller Hears Silence

This is usually an RTP media issue. Check these items:

  • Verify the firewall allows UDP ports 10000-20000 for RTP traffic
  • Check /etc/asterisk/rtp.conf to confirm the port range matches your firewall rules
  • If Asterisk is behind NAT, configure external_media_address and external_signaling_address in pjsip.conf transport section
  • Verify the sound file exists and is in the correct format

Check if the prompt file exists:

$ ls -la /var/lib/asterisk/sounds/custom/ivr-welcome.*

DTMF Not Detected

If callers press keys but the IVR does not respond, the issue is usually DTMF mode. In PJSIP, set the DTMF mode on the endpoint:

[101]
type=endpoint
dtmf_mode=rfc4733    ; recommended - sends DTMF as RTP events
; Other options: inband, info, auto

The rfc4733 mode (also called RFC 2833) is the most reliable. If your VoIP provider uses SIP INFO for DTMF, change to info mode. After changing, reload PJSIP:

$ sudo asterisk -rx "pjsip reload"

Timeout Issues – Menu Replays Too Fast or Too Slow

Adjust the timeout values in your dialplan. The two key settings are:

same => n,Set(TIMEOUT(response)=10)  ; seconds to wait for first digit
same => n,Set(TIMEOUT(digit)=3)     ; seconds to wait between digits

For menus with single-digit options, a response timeout of 5-10 seconds works well. For menus where callers might enter multi-digit extensions, increase the digit timeout to 5 seconds.

Wrong Context – Calls Not Reaching IVR

If incoming calls do not enter the IVR at all, check the context assignment. For PJSIP trunks, the endpoint’s context setting must point to your incoming handler:

CLI> pjsip show endpoint my-voip-provider

Look for the context field in the output. It must match your incoming context name exactly. Also verify the include statements in extensions.conf are correct.

Debugging with CLI

Enable detailed dialplan debugging to trace exactly where calls go:

CLI> core set verbose 5
CLI> dialplan set extenpatternmatchnew true

Make a test call and watch the output. Every application execution and context switch will be logged.

IVR Best Practices

Follow these guidelines to build IVR systems that callers actually want to use. For more details on Asterisk security when exposing your PBX to the internet, check our guide on securing Asterisk and FreePBX from VoIP fraud.

  • Keep prompts short – the welcome greeting should be under 15 seconds. Callers will hang up on long intros
  • Limit menu depth to 3 levels max – main menu, sub-menu, person. Never go deeper
  • Maximum 5 options per menu – research shows callers stop remembering after 4-5 choices
  • Always offer an operator option – press 0 for a live person. Frustrated callers need an exit path
  • Put the most common option first – if 70% of callers want support, make it press 1
  • Handle invalid input gracefully – replay the menu, do not hang up on the caller
  • Set reasonable timeouts – 5-10 seconds is enough. Too long makes the system feel sluggish
  • Use consistent prompts – same voice, same tone, same style across all menus
  • Test with real phones – softphones sometimes handle DTMF differently than hardware phones
  • Monitor call flow – check CDR (Call Detail Records) to see where callers drop off and optimize those menus
  • Back up your dialplan – always copy extensions.conf before making changes

Firewall Configuration

Make sure your firewall allows the required ports for SIP and RTP. On Ubuntu/Debian with UFW:

$ sudo ufw allow 5060/udp comment "SIP signaling"
$ sudo ufw allow 10000:20000/udp comment "RTP media"
$ sudo ufw reload
$ sudo ufw status

If you are using firewalld (RHEL/Rocky/AlmaLinux):

$ sudo firewall-cmd --permanent --add-port=5060/udp
$ sudo firewall-cmd --permanent --add-port=10000-20000/udp
$ sudo firewall-cmd --reload

Conclusion

You now have a fully working IVR system on Asterisk 22 LTS with PJSIP, including business hours routing, nested sub-menus, database lookups, and proper timeout handling. The same dialplan patterns work on Ubuntu 24.04 and Debian 13.

For production deployments, add TLS encryption for SIP signaling (port 5061), configure fail2ban to block brute-force SIP registration attempts, and set up regular backups of your Asterisk configuration files and voicemail storage.

Related Guides

LEAVE A REPLY

Please enter your comment!
Please enter your name here