DEV Community

Moisi Trungu
Moisi Trungu

Posted on • Originally published at flixzone.icu

ViciDial IVR Setup with Asterisk — Inbound Call Menus

ViciDial IVR Setup with Asterisk — Inbound Call Menus

Master building production-grade interactive voice response (IVR) systems in ViciDial using Asterisk dialplans, call routing, and real-time menu logic

Prerequisites

Before starting this tutorial, ensure you have:

  • ViciDial 2.14+ installed and running (tested on CentOS 7/8 or Ubuntu 18.04+)
  • Asterisk 13+ compiled with res_agi, res_http_post, and res_voicemail enabled
  • Root or sudo access to the ViciDial server
  • A working inbound DID or test extension
  • MySQL/MariaDB database access with vicidial user permissions
  • Basic understanding of Asterisk dialplans and ViciDial agent flow
  • Recorded audio prompts in WAV format (8-bit, 8000 Hz mono recommended)
  • At least one active campaign in ViciDial with inbound call handling enabled

Understanding ViciDial IVR Architecture

ViciDial's IVR system sits at the intersection of Asterisk dialplans and the ViciDial database. When an inbound call arrives, it follows this path:

  1. DID routes to an Asterisk context (usually defined in extensions-vicidial.conf)
  2. IVR dialplan plays prompts and collects DTMF input
  3. Digits trigger logic that queries ViciDial database or executes AGI scripts
  4. Calls route to campaigns, queues, or agents based on menu selections
  5. Call metadata logs to vicidial_log table

The key difference from traditional Asterisk IVR: ViciDial maintains call state in its database, enabling features like call recording, agent integration, and reporting.

Section 1: Core IVR Dialplan Structure

Creating the Main IVR Context

Your primary IVR context lives in /etc/asterisk/extensions-vicidial.conf. Here's a production-tested template:

[from-vicidial-ivr]
; Main IVR entry point for inbound DID calls
exten => s,1,Answer()
exten => s,n,Set(CALLFILENAME=${UNIQUEID})
exten => s,n,Set(CHANNEL(language)=en)
exten => s,n,NoOp(=== ViciDial IVR Entry - CallID: ${UNIQUEID} ===)
exten => s,n,Set(vicidial_log_id=${SHELL(/usr/share/astguiclient/VICIDIAL_log_insert.agi ${CHANNEL(name)} ${EXTEN} ${CALLERID(num)} ${CALLERID(name)})})
exten => s,n,Goto(ivr_main_menu,s,1)

[ivr_main_menu]
; Main menu - play prompt and collect input
exten => s,1,NoOp(=== Main Menu ===)
exten => s,n,Set(TIMEOUT(digit)=5)
exten => s,n,Set(TIMEOUT(response)=10)
exten => s,n,Background(/var/spool/asterisk/monolithic/recordings/main_menu_prompt)
exten => s,n,WaitExten(2)

; Menu options - route based on DTMF input
exten => 1,1,Goto(sales_queue,s,1)
exten => 2,1,Goto(support_queue,s,1)
exten => 3,1,Goto(billing_queue,s,1)
exten => 0,1,Goto(operator_queue,s,1)

; Default handler - timeout or invalid input
exten => t,1,Playback(invalid_selection)
exten => t,n,Goto(ivr_main_menu,s,1)

exten => i,1,Playback(invalid_selection)
exten => i,n,Goto(ivr_main_menu,s,1)

; Repeat menu option
exten => *,1,Goto(ivr_main_menu,s,1)

[sales_queue]
exten => s,1,NoOp(=== Routing to Sales Queue ===)
exten => s,n,Set(CAMPAIGN_ID=sales_inbound)
exten => s,n,Queue(sales_queue,t,,,300)
exten => s,n,Playback(sorry_all_agents_busy)
exten => s,n,VoiceMail(u1000@vicidial)
exten => s,n,Hangup()

[support_queue]
exten => s,1,NoOp(=== Routing to Support Queue ===)
exten => s,n,Set(CAMPAIGN_ID=support_inbound)
exten => s,n,Queue(support_queue,t,,,300)
exten => s,n,Playback(sorry_all_agents_busy)
exten => s,n,VoiceMail(u1001@vicidial)
exten => s,n,Hangup()

[billing_queue]
exten => s,1,NoOp(=== Routing to Billing Queue ===)
exten => s,n,Set(CAMPAIGN_ID=billing_inbound)
exten => s,n,Queue(billing_queue,t,,,300)
exten => s,n,Playback(sorry_all_agents_busy)
exten => s,n,VoiceMail(u1002@vicidial)
exten => s,n,Hangup()

[operator_queue]
exten => s,1,NoOp(=== Routing to Operator Queue ===)
exten => s,n,Set(CAMPAIGN_ID=operator_inbound)
exten => s,n,Queue(operator_queue,t,,,300)
exten => s,n,Hangup()
Enter fullscreen mode Exit fullscreen mode

Connecting DID to IVR Context

In your inbound route configuration (via Asterisk or ViciDial UI), point the DID to the from-vicidial-ivr context:

[from-trunk]
; Receives calls from SIP trunk
exten => 1234567890,1,Goto(from-vicidial-ivr,s,1)
Enter fullscreen mode Exit fullscreen mode

Alternatively, configure this in /etc/asterisk/sip.conf:

[trunk-provider]
type=peer
host=your.sip.provider
context=from-trunk
insecure=port,invite
Enter fullscreen mode Exit fullscreen mode

Section 2: Database-Driven Menu Logic

Storing Menu Configurations in ViciDial Database

Instead of hardcoding menus in dialplans, use the ViciDial database to define dynamic menus. Create a custom table:

CREATE TABLE vicidial_ivr_menus (
    menu_id INT AUTO_INCREMENT PRIMARY KEY,
    menu_name VARCHAR(50) UNIQUE NOT NULL,
    campaign_id VARCHAR(20),
    prompt_filename VARCHAR(255),
    timeout_seconds INT DEFAULT 10,
    max_attempts INT DEFAULT 3,
    created_date DATETIME DEFAULT CURRENT_TIMESTAMP,
    modified_date DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    active INT DEFAULT 1
) ENGINE=InnoDB;

CREATE TABLE vicidial_ivr_options (
    option_id INT AUTO_INCREMENT PRIMARY KEY,
    menu_id INT NOT NULL,
    digit_pressed VARCHAR(2),
    action_type ENUM('goto_menu', 'queue', 'voicemail', 'hangup', 'agi_script'),
    action_target VARCHAR(100),
    description VARCHAR(100),
    sequence INT,
    FOREIGN KEY (menu_id) REFERENCES vicidial_ivr_menus(menu_id),
    UNIQUE KEY unique_menu_digit (menu_id, digit_pressed)
) ENGINE=InnoDB;
Enter fullscreen mode Exit fullscreen mode

Insert sample menu configuration:

INSERT INTO vicidial_ivr_menus (menu_name, campaign_id, prompt_filename, timeout_seconds, max_attempts) VALUES
('main_menu', 'ivr_main', '/var/spool/asterisk/monolithic/recordings/main_menu', 10, 3),
('billing_submenu', 'billing_inbound', '/var/spool/asterisk/monolithic/recordings/billing_menu', 8, 2);

INSERT INTO vicidial_ivr_options (menu_id, digit_pressed, action_type, action_target, description, sequence) VALUES
(1, '1', 'queue', 'sales_queue', 'Sales Department', 1),
(1, '2', 'queue', 'support_queue', 'Support Department', 2),
(1, '3', 'goto_menu', 'billing_submenu', 'Billing', 3),
(2, '1', 'queue', 'billing_queue', 'Billing Support', 1),
(2, '2', 'voicemail', 'u1002@vicidial', 'Leave Message', 2);
Enter fullscreen mode Exit fullscreen mode

AGI Script for Dynamic Menu Routing

Create /var/lib/asterisk/agi-bin/vicidial_ivr_router.agi:

#!/usr/bin/perl
# ViciDial IVR Router - Dynamic menu handling via database

use strict;
use Asterisk::AGI;
use DBI;
use Data::Dumper;

my $agi = new Asterisk::AGI;

# Database configuration
my $dbhost = 'localhost';
my $dbname = 'asterisk';
my $dbuser = 'vicidial';
my $dbpass = 'your_db_password';

my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost", $dbuser, $dbpass)
    or die "Cannot connect: $DBI::errstr\n";

# Get variables from Asterisk
my $menu_name = $agi->get_variable('MENU_NAME');
my $digit_pressed = $agi->get_variable('DIGIT_PRESSED');
my $callid = $agi->get_variable('UNIQUEID');

$agi->verbose("IVR Router: Menu=$menu_name, Digit=$digit_pressed", 3);

# Fetch menu configuration
my $menu_query = $dbh->prepare(
    "SELECT menu_id, prompt_filename, timeout_seconds FROM vicidial_ivr_menus WHERE menu_name = ? AND active = 1"
);
$menu_query->execute($menu_name) or die "Query failed: $DBI::errstr\n";
my $menu = $menu_query->fetchrow_hashref();

unless ($menu) {
    $agi->exec('Playback', 'invalid_selection');
    $agi->set_variable('MENU_ACTION', 'retry');
    $dbh->disconnect();
    exit(0);
}

# Fetch option for pressed digit
my $option_query = $dbh->prepare(
    "SELECT action_type, action_target FROM vicidial_ivr_options WHERE menu_id = ? AND digit_pressed = ?"
);
$option_query->execute($menu->{menu_id}, $digit_pressed) or die "Query failed: $DBI::errstr\n";
my $option = $option_query->fetchrow_hashref();

if ($option) {
    $agi->verbose("Executing action: $option->{action_type} -> $option->{action_target}", 3);

    if ($option->{action_type} eq 'queue') {
        $agi->set_variable('QUEUE_NAME', $option->{action_target});
        $agi->set_variable('MENU_ACTION', 'queue');
    } elsif ($option->{action_type} eq 'goto_menu') {
        $agi->set_variable('MENU_NAME', $option->{action_target});
        $agi->set_variable('MENU_ACTION', 'goto_menu');
    } elsif ($option->{action_type} eq 'voicemail') {
        $agi->set_variable('VOICEMAIL_BOX', $option->{action_target});
        $agi->set_variable('MENU_ACTION', 'voicemail');
    } elsif ($option->{action_type} eq 'hangup') {
        $agi->set_variable('MENU_ACTION', 'hangup');
    }
} else {
    $agi->verbose("No action defined for digit: $digit_pressed", 2);
    $agi->set_variable('MENU_ACTION', 'invalid');
}

$dbh->disconnect();
exit(0);
Enter fullscreen mode Exit fullscreen mode

Make the script executable:

chmod 755 /var/lib/asterisk/agi-bin/vicidial_ivr_router.agi
chown asterisk:asterisk /var/lib/asterisk/agi-bin/vicidial_ivr_router.agi
Enter fullscreen mode Exit fullscreen mode

Dialplan Integration with AGI

Update your main dialplan to use the AGI script:

[ivr_dynamic_menu]
exten => s,1,NoOp(=== Dynamic Menu Handler ===)
exten => s,n,Set(TIMEOUT(digit)=5)
exten => s,n,Set(TIMEOUT(response)=${timeout_seconds})
exten => s,n,Background(${prompt_filename})
exten => s,n,WaitExten(2)

exten => 1,1,Set(DIGIT_PRESSED=1)
exten => 1,n,AGI(vicidial_ivr_router.agi)
exten => 1,n,GotoIf($["${MENU_ACTION}"="queue"]?execute_queue,s,1)
exten => 1,n,GotoIf($["${MENU_ACTION}"="goto_menu"]?ivr_dynamic_menu,s,1)
exten => 1,n,GotoIf($["${MENU_ACTION}"="voicemail"]?execute_voicemail,s,1)
exten => 1,n,Hangup()

exten => 2,1,Set(DIGIT_PRESSED=2)
exten => 2,n,AGI(vicidial_ivr_router.agi)
exten => 2,n,GotoIf($["${MENU_ACTION}"="queue"]?execute_queue,s,1)
exten => 2,n,GotoIf($["${MENU_ACTION}"="goto_menu"]?ivr_dynamic_menu,s,1)
exten => 2,n,Hangup()

; Repeat for digits 3-9...

exten => t,1,Playback(invalid_selection)
exten => t,n,Goto(ivr_dynamic_menu,s,1)

exten => i,1,Playback(invalid_selection)
exten => i,n,Goto(ivr_dynamic_menu,s,1)

[execute_queue]
exten => s,1,Queue(${QUEUE_NAME},t,,,300)
exten => s,n,Playback(all_agents_busy)
exten => s,n,Hangup()

[execute_voicemail]
exten => s,1,VoiceMail(${VOICEMAIL_BOX})
exten => s,n,Hangup()
Enter fullscreen mode Exit fullscreen mode

Section 3: Call Recording and ViciDial Integration

Enabling Call Recording in IVR

ViciDial requires explicit recording setup. Add this to your IVR entry context:

[from-vicidial-ivr]
exten => s,1,Answer()
exten => s,n,Set(CALLFILENAME=${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID})
exten => s,n,Set(CHANNEL(language)=en)
exten => s,n,MixMonitor(/var/spool/asterisk/monolithic/recordings/ivr/${CALLFILENAME}.wav,b)
exten => s,n,Set(RECORDING_FILE=/var/spool/asterisk/monolithic/recordings/ivr/${CALLFILENAME}.wav)
exten => s,n,NoOp(=== ViciDial IVR Recording: ${RECORDING_FILE} ===)
exten => s,n,Goto(ivr_main_menu,s,1)
Enter fullscreen mode Exit fullscreen mode

Ensure the recording directory exists and has proper permissions:

mkdir -p /var/spool/asterisk/monolithic/recordings/ivr
chown asterisk:asterisk /var/spool/asterisk/monolithic/recordings/ivr
chmod 755 /var/spool/asterisk/monolithic/recordings/ivr
Enter fullscreen mode Exit fullscreen mode

Logging IVR Events to ViciDial Database

Create a dialplan macro to log IVR interactions:

[macro-ivr_log_event]
; Arguments: ${ARG1}=event_type, ${ARG2}=menu_name, ${ARG3}=digit_pressed
exten => s,1,NoOp(=== Logging IVR Event ===)
exten => s,n,AGI(agi://<ivr_logger_script>,${ARG1},${ARG2},${ARG3})

[from-vicidial-ivr-logged]
exten => s,1,Answer()
exten => s,n,Set(CALLFILENAME=${UNIQUEID})
exten => s,n,MixMonitor(/var/spool/asterisk/monolithic/recordings/ivr/${CALLFILENAME}.wav,b)
exten => s,n,Macro(ivr_log_event,ivr_entry,main_menu,)
exten => s,n,Goto(ivr_main_menu,s,1)

[ivr_main_menu]
exten => s,1,Set(TIMEOUT(digit)=5)
exten => s,n,Set(TIMEOUT(response)=10)
exten => s,n,Background(/var/spool/asterisk/monolithic/recordings/main_menu_prompt)
exten => s,n,WaitExten(2)

exten => 1,1,Macro(ivr_log_event,digit_pressed,main_menu,1)
exten => 1,n,Goto(sales_queue,s,1)

exten => 2,1,Macro(ivr_log_event,digit_pressed,main_menu,2)
exten => 2,n,Goto(support_queue,s,1)

exten => t,1,Macro(ivr_log_event,timeout,main_menu,)
exten => t,n,Goto(ivr_main_menu,s,1)

exten => i,1,Macro(ivr_log_event,invalid_input,main_menu,)
exten => i,n,Goto(ivr_main_menu,s,1)
Enter fullscreen mode Exit fullscreen mode

Section 4: Advanced Features — Caller Authentication and Call Routing

Account Lookup with DTMF Entry

Allow customers to enter an account number for routing:

[ivr_account_lookup]
exten => s,1,NoOp(=== Account Lookup ===)
exten => s,n,Set(TIMEOUT(digit)=5)
exten => s,n,Playback(enter_account_number)
exten => s,n,Read(ACCOUNT_NUMBER,please_enter_account)
exten => s,n,AGI(agi://<account_validation>,${ACCOUNT_NUMBER})
exten => s,n,GotoIf($["${ACCOUNT_VALID}"="1"]?lookup_success,s,1)
exten => s,n,Playback(account_not_found)
exten => s,n,Goto(ivr_main_menu,s,1)

[lookup_success]
exten => s,1,NoOp(=== Account Found: ${ACCOUNT_NUMBER} ===)
exten => s,n,Set(CAMPAIGN_ID=${ACCOUNT_CAMPAIGN})
exten => s,n,Queue(${ACCOUNT_QUEUE},t,,,300)
exten => s,n,Playback(sorry_all_agents_busy)
exten => s,n,Hangup()
Enter fullscreen mode Exit fullscreen mode

IVR Call Priority Based on Menu Selection

Route calls with different queue priorities:

[ivr_priority_menu]
exten => s,1,NoOp(=== Priority Menu ===)
exten => s,n,Set(TIMEOUT(digit)=5)
exten => s,n,Set(TIMEOUT(response)=10)
exten => s,n,Background(/var/spool/asterisk/monolithic/recordings/priority_menu)
exten => s,n,WaitExten(2)

; High priority (existing customers)
exten => 1,1,Set(QUEUE_PRIORITY=10)
exten => 1,n,Set(CALL_TYPE=existing_customer)
exten => 1,n,Goto(route_to_queue,s,1)

; Standard priority (new customers)
exten => 2,1,Set(QUEUE_PRIORITY=5)
exten => 2,n,Set(CALL_TYPE=new_customer)
exten => 2,n,Goto(route_to_queue,s,1)

; VIP priority
exten => 3,1,Set(QUEUE_PRIORITY=15)
exten => 3,n,Set(CALL_TYPE=vip_customer)
exten => 3,n,Goto(route_to_queue,s,1)

[route_to_queue]
exten => s,1,NoOp(=== Queue with Priority ${QUEUE_PRIORITY} ===)
exten => s,n,Set(QUEUE_PRIORITY=${QUEUE_PRIORITY})
exten => s,n,Queue(sales_queue,t,,,300)
exten => s,n,Hangup()
Enter fullscreen mode Exit fullscreen mode

Section 5: Troubleshooting IVR Issues

Common Problems and Solutions

IVR Not Receiving DTMF Input

Problem: Menu plays but pressing buttons doesn't work.

Diagnosis:

asterisk -rx "sip set debug on"
asterisk -rx "core set verbose 3"
tail -f /var/log/asterisk/messages | grep -i dtmf
Enter fullscreen mode Exit fullscreen mode

Solution: Check for DTMF mode mismatch. ViciDial typically uses RFC2833 (RTP-based):

[sip-vicidial]
dtmfmode=rfc2833
Enter fullscreen mode Exit fullscreen mode

Restart Asterisk:

systemctl restart asterisk
Enter fullscreen mode Exit fullscreen mode

Calls Dropping After Menu Selection

Problem: Call disconnects after pressing a digit.

Diagnosis: Check dialplan syntax:

asterisk -rx "dialplan reload"
asterisk -rx "dialplan show from-vicidial-ivr" | grep -A5 "exten => 1"
Enter fullscreen mode Exit fullscreen mode

Solution: Verify all Goto() statements reference valid contexts and extensions:

exten => 1,1,Goto(sales_queue,s,1)
; Verify that 'sales_queue' context exists with 's' extension
Enter fullscreen mode Exit fullscreen mode

Recording Files Not Found

Problem: Playback fails with "file not found" error.

Diagnosis:

ls -la /var/spool/asterisk/monolithic/recordings/
asterisk -rx "core set verbose 3" | grep -i playback
Enter fullscreen mode Exit fullscreen mode

Solution: Ensure audio files exist and are in correct format:

# Check format
file /var/spool/asterisk/monolithic/recordings/main_menu_prompt.wav

# Convert if necessary
sox input.wav -b 8 -r 8000 output.wav remix -

# Test playback
asterisk -rx "core set verbose 3"
# In dialplan: Playback(/var/spool/asterisk/monolithic/recordings/test_prompt)
Enter fullscreen mode Exit fullscreen mode

IVR Context Not Loading

Problem: "Unknown context" error when dialing DID.

Diagnosis:

asterisk -rx "dialplan show from-vicidial-ivr"
asterisk -rx "core show functions" | grep Load
Enter fullscreen mode Exit fullscreen mode

Solution: Reload dialplan and verify syntax:

# Check syntax first
asterisk -vvvvvc -g 2>&1 | head -50

# Reload
asterisk -rx "dialplan reload"

# Verify
asterisk -rx "dialplan show from-vicidial-ivr" | head -20
Enter fullscreen mode Exit fullscreen mode

AGI Script Errors

Problem: AGI script returns error, calls fail.

Diagnosis:

tail -f /var/log/asterisk/messages | grep agi
asterisk -rx "agi debug on"
Enter fullscreen mode Exit fullscreen mode

Solution: Check script permissions and Perl dependencies:

chmod 755 /var/lib/asterisk/agi-bin/vicidial_ivr_router.agi
perl -c /var/lib/asterisk/agi-bin/vicidial_ivr_router.agi
cpan install Asterisk::AGI
Enter fullscreen mode Exit fullscreen mode

Queue Timeout Not Working

Problem: Calls queue indefinitely instead of timing out.

Diagnosis:

asterisk -rx "queue show sales_queue"
Enter fullscreen mode Exit fullscreen mode

Solution: Verify queue timeout is set in dialplan:

exten => s,1,Queue(sales_queue,t,,,300)
;                                       ^^^ timeout in seconds
Enter fullscreen mode Exit fullscreen mode

Also check queue definition in queues.conf:

[sales_queue]
member => SIP/agent1
member => SIP/agent2
timeout=20
Enter fullscreen mode Exit fullscreen mode

Database Connection Failures in AGI

Problem: AGI script fails to connect to database.

Diagnosis:

mysql -h localhost -u vicidial -p asterisk -e "SELECT COUNT(*) FROM vicidial_ivr_menus;"
Enter fullscreen mode Exit fullscreen mode

Solution: Verify credentials and permissions:

# From MySQL:
GRANT SELECT ON asterisk.vicidial_ivr_menus TO 'vicidial'@'localhost';
FLUSH PRIVILEGES;

# Test Perl DBI connection
perl -e 'use DBI; my $dbh = DBI->connect("DBI:mysql:asterisk:localhost", "vicidial", "password"); print "OK\n";'
Enter fullscreen mode Exit fullscreen mode

Section 6: Monitoring and Testing Your IVR

Asterisk CLI Commands for IVR Debugging

Monitor active calls:

asterisk -rx "core show calls"
Enter fullscreen mode Exit fullscreen mode

View queue statistics:

asterisk -rx "queue show sales_queue"
Enter fullscreen mode Exit fullscreen mode

Monitor real-time verbose output:

asterisk -rx "core set verbose 3"
tail -f /var/log/asterisk/messages
Enter fullscreen mode Exit fullscreen mode

Test dialplan routing:

asterisk -rx "dialplan eval 1234567890 from-vicidial-ivr s"
Enter fullscreen mode Exit fullscreen mode

Check for syntax errors:

asterisk -rx "dialplan reload"
Enter fullscreen mode Exit fullscreen mode

Manual IVR Testing

From the Asterisk CLI, originate a test call:

asterisk -rx "channel originate SIP/test-agent Extension 1000@from-vicidial-ivr"
Enter fullscreen mode Exit fullscreen mode

Test IVR audio playback:

asterisk -rx "console dial 1000@from-vicidial-ivr"
Enter fullscreen mode Exit fullscreen mode

Accessing ViciDial Logs

View call logs in ViciDial admin:

  • Navigate to /vicidial/admin.php
  • Reports → Call Log
  • Filter by DID or time range

Query call logs directly:

SELECT * FROM vicidial_log WHERE called_number = '1234567890' 
AND call_date >= NOW() - INTERVAL 1 HOUR 
ORDER BY call_date DESC LIMIT 20;
Enter fullscreen mode Exit fullscreen mode

Check agent state during IVR interaction:

SELECT user, status, phone_number, call_date FROM vicidial_agent_log 
WHERE call_date >= NOW() - INTERVAL 1 HOUR 
ORDER BY call_date DESC;
Enter fullscreen mode Exit fullscreen mode

Summary

You now have a comprehensive production-grade ViciDial IVR setup with:

  • Core IVR dialplans that route inbound calls through menu hierarchies
  • Database-driven dynamic menus using custom tables for flexible configuration
  • AGI script integration for intelligent call routing and account lookup
  • Call recording and logging that integrates with ViciDial's reporting
  • Advanced features including caller authentication, priority routing, and multi-step menus
  • Troubleshooting techniques for common IVR issues
  • Monitoring tools to track and debug call flows in real-time

For production deployment:

  1. Backup your Asterisk configuration before making changes
  2. Test all dialplans with test calls before going live
  3. Monitor logs during the first 24 hours after deployment
  4. Set appropriate queue timeouts based on your staffing
  5. Record audio prompts professionally to improve caller experience
  6. Document custom contexts for future maintenance
  7. Implement call recording for compliance and training
  8. Schedule regular database maintenance on your custom IVR tables

The IVR system scales with ViciDial's queue management, allowing hundreds of simultaneous calls with intelligent routing based on business rules, not just static menus.

Top comments (0)