Learn how to configure and manage both agent-initiated and automatic callbacks in ViciDial with practical examples, database queries, and production troubleshooting techniques.
Prerequisites
Before implementing callbacks in ViciDial, ensure you have:
- ViciDial version 2.14.1 or higher installed and running
- Root or sudo access to the ViciDial server
- MySQL/MariaDB access with administrative privileges
- Asterisk 13+ properly configured with SIP trunks or IAX2
- At least one active campaign set up in ViciDial
- Working agent logins and active phone extensions
- Proper dial permissions configured for agents
- Call recording enabled (optional but recommended for compliance)
- Outbound carrier/trunk verification — test a manual dial first
Verify your installation:
mysql -u root -p asterisk -e "SELECT version FROM version LIMIT 1;"
asterisk -rx "core show version"
ps aux | grep -E "(asterisk|vicidial)" | grep -v grep
Understanding ViciDial Callbacks
What Are Callbacks?
Callbacks in ViciDial allow agents or the system to schedule calls to contact at a later time. This prevents contact overload, respects time zones, and increases connection rates. ViciDial supports two callback types:
- Agent Callbacks (CALLBK) — Agents schedule callbacks directly from the call screen
- Auto Callbacks — System automatically reschedules based on lead disposition rules
Why Callbacks Matter
- Higher contact rates: Callbacks reach customers when they're available
- Better agent efficiency: Agents don't waste time on busy/no-answer leads
- Compliance: Schedule calls during business hours per time zone
- Lead recovery: Systematically retry abandoned or incomplete interactions
- Customer satisfaction: Reduces unwanted interruptions
Key Database Tables
Callbacks are stored primarily in these tables:
vicidial_log— Call history withcalled_count,status,callback_timevicidial_callbacks— Dedicated callback records with phone, time, agentvicidial_carrier_log— Route tracking for callback attemptsvicidial_lists— Campaign list configuration with callback settings
Agent Callbacks Configuration
Step 1: Enable Callbacks in Campaign Settings
Access the ViciDial web interface and navigate to Admin > Campaigns.
- Select your campaign
- Scroll to Callback Settings
- Set
Allow Agent Callbacksto YES - Set
Callback Time Window(e.g., 1 day, 7 days, 30 days) - Enable
Allow Same-Day Callbacksif needed - Set
Callback Dial Timeoutto 45-60 seconds - Save changes
Verify via database:
SELECT campaign_id, campaign_name, allow_agent_callbacks, callback_time_window
FROM vicidial_campaigns
WHERE campaign_name = 'YOUR_CAMPAIGN';
Expected output:
campaign_id | campaign_name | allow_agent_callbacks | callback_time_window
1 | Sales | Y | 1440
Step 2: Configure Agent Callback Permissions
Open /etc/asterisk/extensions-vicidial.conf and locate the agent login context. Add callback-specific permissions:
[from-internal-agent]
exten => *1,1,NoOp(Agent Callback Requested)
exten => *1,2,ViciDial(${CALLERID(num)}|1|${UNIQUEID}|CALLBACK)
exten => *1,3,Hangup()
; Callback with custom time picker
exten => *2,1,NoOp(Schedule Callback with Date/Time)
exten => *2,2,Playback(please-enter-time)
exten => *2,3,Read(callback_minutes|enter-time|||5)
exten => *2,4,ViciDial(${CALLERID(num)}|1|${UNIQUEID}|CALLBACK|${callback_minutes})
exten => *2,5,Hangup()
Step 3: Database Setup for Agent Callbacks
Create callback records directly in the database. ViciDial's agent interface does this automatically, but you should understand the structure:
CREATE TABLE IF NOT EXISTS vicidial_callbacks (
callback_id INT AUTO_INCREMENT PRIMARY KEY,
lead_id INT NOT NULL,
campaign_id INT NOT NULL,
phone_number VARCHAR(20) NOT NULL,
callback_time DATETIME NOT NULL,
callback_date DATE NOT NULL,
user_id INT,
agent_id VARCHAR(20),
status ENUM('PENDING','COMPLETED','FAILED','CANCELLED') DEFAULT 'PENDING',
notes TEXT,
created_date DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX (callback_time),
INDEX (campaign_id),
INDEX (lead_id),
FOREIGN KEY (lead_id) REFERENCES vicidial_list(lead_id)
);
Insert a test callback record:
INSERT INTO vicidial_callbacks
(lead_id, campaign_id, phone_number, callback_time, callback_date, agent_id, status, notes)
VALUES
(1001, 1, '5551234567', DATE_ADD(NOW(), INTERVAL 2 DAY), CURDATE() + INTERVAL 2 DAY, 'AGENT001', 'PENDING', 'Customer requested callback Friday morning');
-- Verify insertion
SELECT * FROM vicidial_callbacks WHERE lead_id = 1001;
Step 4: Agent-Side Configuration
Agents access callbacks via the main call screen at /agc/vicidial.php. When an agent clicks Schedule Callback:
- A popup appears requesting callback time
- Agent selects date and time (respecting time zone)
- Lead is marked with callback disposition
- Record inserted into
vicidial_callbacks
To ensure agents see the callback button, verify their user privileges:
SELECT user_id, vicidial_login, modify_callbackcallback_time
FROM vicidial_users
WHERE vicidial_login = 'AGENT001';
The user must have modify_callback set to Y:
UPDATE vicidial_users
SET modify_callback = 'Y'
WHERE vicidial_login = 'AGENT001';
Step 5: Test Agent Callback
- Log in as an agent
- Receive or dial a test call
- Click Schedule Callback button on call screen
- Enter callback date/time (e.g., +2 hours)
- Click Confirm
- Agent screen should show "CALLBACK SCHEDULED"
- Check database:
SELECT * FROM vicidial_callbacks
WHERE agent_id = 'AGENT001'
ORDER BY created_date DESC LIMIT 1;
Automatic Callback Configuration
Step 1: Configure Disposition Rules
Automatic callbacks trigger based on call dispositions. Configure this in Admin > Dispositions.
Map dispositions to auto-callback actions:
| Disposition | Auto-Callback | Wait Time | Notes |
|---|---|---|---|
| NO ANSWER | YES | 30 minutes | Retry quickly |
| BUSY | YES | 1 hour | Customer busy |
| NOT INTERESTED | NO | — | Don't retry |
| CALLBACK REQUESTED | YES | 24 hours | Customer availability |
| ANSWERING MACHINE | YES | 48 hours | Wait before retry |
Database configuration:
SELECT disposition_id, disposition, auto_callback_enabled, auto_callback_delay_minutes
FROM vicidial_dispositions
WHERE campaign_id = 1;
Update disposition for auto-callback:
UPDATE vicidial_dispositions
SET auto_callback_enabled = 'Y', auto_callback_delay_minutes = 30
WHERE disposition = 'NO ANSWER' AND campaign_id = 1;
Step 2: Configure Auto-Callback Script
ViciDial uses scheduled scripts to process callbacks. Edit or create /usr/share/astguiclient/process_callbacks.pl:
#!/usr/bin/perl
# Process Auto-Callbacks - Run every 15 minutes via cron
use strict;
use DBI;
use DateTime;
use DateTime::TimeZone;
my $dsn = 'DBI:mysql:asterisk:localhost';
my $user = 'root';
my $pass = 'PASSWORD';
my $dbh = DBI->connect($dsn, $user, $pass) or die "Cannot connect: $DBI::errstr";
# Fetch pending callbacks due now
my $sql = qq{
SELECT cb.callback_id, cb.lead_id, cb.phone_number,
cb.callback_time, vl.customer_timezone, vl.campaign_id
FROM vicidial_callbacks cb
JOIN vicidial_list vl ON cb.lead_id = vl.lead_id
WHERE cb.status = 'PENDING'
AND cb.callback_time <= NOW()
AND cb.callback_time > DATE_SUB(NOW(), INTERVAL 5 MINUTE)
};
my $sth = $dbh->prepare($sql);
$sth->execute();
while (my $row = $sth->fetchrow_hashref()) {
my $callback_id = $row->{callback_id};
my $lead_id = $row->{lead_id};
my $phone = $row->{phone_number};
my $campaign_id = $row->{campaign_id};
# Insert into outbound queue
my $insert_sql = qq{
INSERT INTO vicidial_log
(lead_id, phone_number, campaign_id, status, call_date,
user, source_id, callback_id)
VALUES (?, ?, ?, 'QUEUE', NOW(), 'AUTO-CALLBACK', 'CALLBACK', ?)
};
my $insert_sth = $dbh->prepare($insert_sql);
$insert_sth->execute($lead_id, $phone, $campaign_id, $callback_id);
# Mark callback as processed
my $update_sql = qq{
UPDATE vicidial_callbacks
SET status = 'COMPLETED'
WHERE callback_id = ?
};
my $update_sth = $dbh->prepare($update_sql);
$update_sth->execute($callback_id);
print "Processed callback ID: $callback_id for lead $lead_id\n";
}
$sth->finish();
$dbh->disconnect();
exit(0);
Make executable:
chmod +x /usr/share/astguiclient/process_callbacks.pl
chown asterisk:asterisk /usr/share/astguiclient/process_callbacks.pl
Step 3: Schedule Callback Processing via Cron
Add to /etc/cron.d/astguiclient:
# Process auto-callbacks every 15 minutes
*/15 * * * * asterisk /usr/share/astguiclient/process_callbacks.pl >> /var/log/asterisk/callbacks.log 2>&1
# Alternative: every 5 minutes for more responsive system
*/5 * * * * asterisk /usr/share/astguiclient/process_callbacks.pl >> /var/log/asterisk/callbacks.log 2>&1
Restart cron:
systemctl restart cron
# or
systemctl restart crond
Step 4: Configure Asterisk for Callback Delivery
Edit /etc/asterisk/extensions-vicidial.conf to add callback delivery context:
[callback-delivery]
; Callback context - called by ViciDial dialer
exten => s,1,NoOp(Callback delivery for ${CALLBACK_LEAD_ID})
exten => s,2,Set(CALLERID(name)=Your Company)
exten => s,3,Dial(SIP/YOUR_TRUNK/${CALLBACK_PHONE},45,gU(callback-hangup^s^1))
exten => s,4,Hangup()
; Track callback result
[callback-hangup]
exten => s,1,NoOp(Callback hangup - disposition: ${DIALSTATUS})
exten => s,2,NoOp(Returning to IVR/Agent)
exten => s,3,Return()
Reload Asterisk:
asterisk -rx "dialplan reload"
Step 5: Configure Callback Time Window & DNC
Prevent callbacks outside business hours:
-- Set campaign callback hours: 8am-6pm
UPDATE vicidial_campaigns
SET callback_start_hour = 8,
callback_end_hour = 18,
callback_respect_timezone = 'Y'
WHERE campaign_id = 1;
-- Verify
SELECT campaign_id, callback_start_hour, callback_end_hour,
callback_respect_timezone
FROM vicidial_campaigns
WHERE campaign_id = 1;
Add DNC (Do Not Call) exceptions for callbacks:
-- Ensure callbacks can override DNC
UPDATE vicidial_campaigns
SET callback_ignore_dnc = 'Y'
WHERE campaign_id = 1;
Callback Delivery & Queuing
Step 1: Configure Callback Queue
ViciDial uses a dedicated callback queue. Configure in /etc/asterisk/queues.conf:
[callback-queue]
strategy = ringall
timeout = 45
retry = 3
weight = 0
autopause = no
announce-frequency = 0
announce-holdtime = no
maxlen = 500
Step 2: Callback Outbound Route
Configure outbound routing for callbacks. In /etc/asterisk/extensions-vicidial.conf:
[vicidial-callback-out]
exten => _X.,1,NoOp(Callback outbound route)
exten => _X.,2,Set(CALLBACK_MODE=yes)
exten => _X.,3,Set(CALLERID(name)=Support Team)
exten => _X.,4,Dial(SIP/YOUR_CARRIER/${EXTEN}@carrier.com,45,gU(log-callback^s^1))
exten => _X.,5,Goto(handle-callback-fail,${EXTEN},1)
exten => _X.,6,Hangup()
[handle-callback-fail]
exten => _X.,1,NoOp(Callback failed - Status: ${DIALSTATUS})
exten => _X.,2,Set(callback_status=${DIALSTATUS})
exten => _X.,3,Hangup()
[log-callback]
exten => s,1,NoOp(Callback connected)
exten => s,2,Return()
Step 3: ViciDial Dialer Configuration
Configure the ViciDial dialer to handle callbacks. Edit /etc/asterisk/sip-vicidial.conf:
[vicidial-callback-trunk]
type=peer
host=YOUR_CARRIER_IP
username=YOUR_USERNAME
secret=YOUR_PASSWORD
context=vicidial-callback-out
dtmfmode=rfc2833
relaxdtmf=yes
qualify=yes
qualifyfreq=60
insecure=port,invite
directmedia=no
Reload SIP:
asterisk -rx "sip reload"
Callback Status Tracking
Monitor Callback Queue
asterisk -rx "queue show callback-queue"
Expected output:
callback-queue has 5 calls (max unlimited) in 'ringall' strategy
No members are available
(1 call waiting)
Query Callback Status
Real-time callback status:
SELECT
cb.callback_id,
cb.lead_id,
vl.phone_number,
cb.callback_time,
cb.status,
cb.agent_id,
vl.campaign_id
FROM vicidial_callbacks cb
JOIN vicidial_list vl ON cb.lead_id = vl.lead_id
WHERE cb.status = 'PENDING'
AND cb.callback_time <= NOW()
ORDER BY cb.callback_time ASC;
Callback completion report:
SELECT
DATE(cb.created_date) as callback_date,
COUNT(*) as total_callbacks,
SUM(CASE WHEN cb.status = 'COMPLETED' THEN 1 ELSE 0 END) as completed,
SUM(CASE WHEN cb.status = 'FAILED' THEN 1 ELSE 0 END) as failed,
SUM(CASE WHEN cb.status = 'PENDING' THEN 1 ELSE 0 END) as pending,
ROUND(100 * SUM(CASE WHEN cb.status = 'COMPLETED' THEN 1 ELSE 0 END) / COUNT(*), 2) as completion_rate
FROM vicidial_callbacks cb
GROUP BY DATE(cb.created_date)
ORDER BY callback_date DESC;
Update Callback Status Manually
If a callback fails and needs rescheduling:
UPDATE vicidial_callbacks
SET callback_time = DATE_ADD(NOW(), INTERVAL 24 HOUR),
status = 'PENDING'
WHERE callback_id = 42;
Cancel a callback:
UPDATE vicidial_callbacks
SET status = 'CANCELLED'
WHERE callback_id = 42;
Advanced Configuration
Time Zone-Aware Callbacks
ViciDial respects customer time zones for callback scheduling. Configure in campaign:
UPDATE vicidial_campaigns
SET callback_respect_timezone = 'Y'
WHERE campaign_id = 1;
Set customer timezone in vicidial_list:
UPDATE vicidial_list
SET customer_timezone = 'America/Chicago'
WHERE lead_id = 1001;
Supported time zones (see /usr/share/zoneinfo/):
- America/New_York
- America/Chicago
- America/Denver
- America/Los_Angeles
- America/Anchorage
- Pacific/Honolulu
- etc.
Callback with Voicemail Fallback
Configure fallback to voicemail if callback fails:
[vicidial-callback-out]
exten => _X.,1,NoOp(Callback with voicemail fallback)
exten => _X.,2,Set(CALLERID(name)=Support)
exten => _X.,3,Dial(SIP/TRUNK/${EXTEN},45,gU(callback-hangup^s^1))
exten => _X.,4,Goto(voicemail-fallback,${EXTEN},1)
exten => _X.,5,Hangup()
[voicemail-fallback]
exten => _X.,1,NoOp(Callback failed, attempting voicemail)
exten => _X.,2,VoiceMail(${EXTEN}@default)
exten => _X.,3,Hangup()
Callback with IVR Menu
Route callbacks through an IVR before agent delivery:
[callback-ivr]
exten => s,1,NoOp(Callback IVR)
exten => s,2,Playback(welcome-callback)
exten => s,3,Set(TIMEOUT(digit)=5)
exten => s,4,Set(TIMEOUT(response)=10)
exten => s,5,Read(menu_choice|please-enter-department,1,,3)
exten => s,6,Goto(route-callback,${menu_choice},1)
exten => s,7,Hangup()
[route-callback]
exten => 1,1,Queue(sales-callbacks)
exten => 2,1,Queue(support-callbacks)
exten => 3,1,Queue(billing-callbacks)
exten => i,1,Playback(invalid)
exten => i,2,Goto(callback-ivr,s,1)
Restrict Callback Frequency
Prevent callback storms by tracking attempt frequency:
SELECT
lead_id,
phone_number,
COUNT(*) as callback_count,
MAX(created_date) as last_callback
FROM vicidial_callbacks
WHERE created_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY lead_id
HAVING callback_count > 5;
Block leads with excessive callbacks:
UPDATE vicidial_list
SET status = 'TEMP_BLOCK'
WHERE lead_id IN (
SELECT lead_id FROM vicidial_callbacks
WHERE created_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY lead_id
HAVING COUNT(*) > 3
);
Troubleshooting
Callbacks Not Triggering
Symptom: Callbacks remain in PENDING status past their scheduled time.
Solution:
- Verify cron job is running:
ps aux | grep process_callbacks.pl
- Check cron logs:
grep process_callbacks /var/log/syslog
# or
tail -50 /var/log/asterisk/callbacks.log
- Verify script has correct permissions:
ls -la /usr/share/astguiclient/process_callbacks.pl
# Should show: -rwxr-xr-x asterisk:asterisk
- Manually test the script:
sudo -u asterisk /usr/share/astguiclient/process_callbacks.pl
echo $? # Should return 0 on success
- Check MySQL connectivity from callback script:
mysql -u root -p asterisk -e "SELECT COUNT(*) FROM vicidial_callbacks WHERE status='PENDING';"
Callbacks Queued But Not Dialing
Symptom: Callbacks appear in database but agents don't receive calls.
Solution:
- Check Asterisk dialplan loaded:
asterisk -rx "dialplan show callback-delivery"
- Verify SIP trunk is registered:
asterisk -rx "sip show peers"
- Check channel availability:
asterisk -rx "core show channels"
- Review Asterisk CLI logs in real-time:
asterisk -rn
Then trigger a callback and watch output.
- Test trunk dial directly:
asterisk -rx "channel originate SIP/TRUNK/5551234567 extension test@from-internal"
Callbacks Showing Wrong Time
Symptom: Callbacks display or execute at incorrect times.
Solution:
- Verify server timezone:
timedatectl status
date
- Verify MySQL timezone:
SELECT @@global.time_zone, @@session.time_zone;
Should show system timezone. If showing SYSTEM, set explicitly:
SET GLOBAL time_zone = 'America/Chicago';
- Verify ViciDial campaign timezone setting:
SELECT callback_respect_timezone, campaign_timezone
FROM vicidial_campaigns
WHERE campaign_id = 1;
- Check individual lead timezone:
SELECT lead_id, customer_timezone
FROM vicidial_list
WHERE lead_id = 1001;
Callback Permission Denied
Symptom: Agents click Schedule Callback but get permission error.
Solution:
- Verify agent user has callback permission:
SELECT user_id, vicidial_login, modify_callback, campaign_id
FROM vicidial_users
WHERE vicidial_login = 'AGENT001';
- Enable callback permission:
UPDATE vicidial_users
SET modify_callback = 'Y'
WHERE vicidial_login = 'AGENT001';
- Verify campaign allows agent callbacks:
SELECT allow_agent_callbacks
FROM vicidial_campaigns
WHERE campaign_id = 1;
- If disabled, enable:
UPDATE vicidial_campaigns
SET allow_agent_callbacks = 'Y'
WHERE campaign_id = 1;
- Reload ViciDial web interface (clear browser cache).
High Callback Failure Rate
Symptom: Many callbacks marked FAILED status.
Solution:
- Review failure reasons:
SELECT
COUNT(*) as failed_count,
dialstatus,
disposition
FROM vicidial_log
WHERE source_id = 'CALLBACK'
AND call_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND status = 'FAILED'
GROUP BY dialstatus, disposition;
- Check trunk capacity:
asterisk -rx "core show channels brief" | wc -l
- Verify carrier is accepting calls:
asterisk -rx "sip show peers" | grep YOUR_TRUNK
- Review Asterisk full logs:
tail -200 /var/log/asterisk/full
grep -i callback /var/log/asterisk/full | tail -50
- Check for SIP errors (401 UNAUTHORIZED, 403 FORBIDDEN):
grep -i "^.*SIP/.*401\|^.*SIP/.*403" /var/log/asterisk/full | tail -20
- If carrier rejects, verify credentials:
# In /etc/asterisk/sip-vicidial.conf, check:
# - username
# - secret (password)
# - host IP
# - port (usually 5060)
Database Growing Too Large
Symptom: vicidial_callbacks table consuming excessive disk space.
Solution:
Archive old completed callbacks:
-- Create archive table
CREATE TABLE vicidial_callbacks_archive LIKE vicidial_callbacks;
-- Move callbacks older than 90 days
INSERT INTO vicidial_callbacks_archive
SELECT * FROM vicidial_callbacks
WHERE created_date < DATE_SUB(NOW(), INTERVAL 90 DAY)
AND status IN ('COMPLETED', 'FAILED', 'CANCELLED');
-- Delete archived records
DELETE FROM vicidial_callbacks
WHERE created_date < DATE_SUB(NOW(), INTERVAL 90 DAY)
AND status IN ('COMPLETED', 'FAILED', 'CANCELLED');
-- Optimize table
OPTIMIZE TABLE vicidial_callbacks;
Add automatic cleanup to cron:
0 2 * * * asterisk mysql -u root -p PASSWORD asterisk -e "DELETE FROM vicidial_callbacks WHERE created_date < DATE_SUB(NOW(), INTERVAL 120 DAY) AND status IN ('COMPLETED','FAILED','CANCELLED'); OPTIMIZE TABLE vicidial_callbacks;" >> /var/log/asterisk/cleanup.log 2>&1
Summary
ViciDial callbacks—both agent-initiated and automatic—significantly improve contact rates and customer satisfaction when properly configured. This guide covered:
Key Takeaways:
Agent Callbacks allow agents to schedule follow-up calls with customers at their preferred times, improving conversions and reducing contact resistance.
Auto-Callbacks automatically retry failed calls based on disposition rules, maximizing lead recovery without manual agent intervention.
Database structure centers on the
vicidial_callbackstable, with records linked to leads, campaigns, and agents for comprehensive tracking.Asterisk dialplan delivers callbacks through dedicated contexts, supporting SIP trunks, time-zone awareness, and voicemail fallback.
Cron-based processing triggers callbacks at scheduled times, requiring proper permissions and MySQL connectivity to function reliably.
Troubleshooting focuses on verifying permissions, database records, cron execution, timezone settings, and carrier connectivity.
Best Practices:
- Always test callbacks with a single lead before enabling for entire campaign
- Monitor callback completion rates weekly via SQL queries
- Set reasonable callback windows (e.g., 1-30 days) to avoid lead staleness
- Respect time zones—configure per-lead or per-campaign as needed
- Archive old callback records monthly to maintain database performance
- Document your dialplan changes and script modifications for future maintenance
- Review Asterisk logs (
/var/log/asterisk/full) during troubleshooting
Next Steps:
- Deploy the
process_callbacks.plscript with cron scheduling - Configure callback rules for your top 2-3 dispositions
- Train agents on the callback button and best practices
- Monitor first week for issues via database queries and Asterisk CLI
- Adjust callback timing based on success rates
Proper callback configuration transforms ViciDial from a simple dialer into an intelligent lead management system that works 24/7 on behalf of your agents.