Tools: Setting Up ViciDial Callbacks (CALLBK) — Agent & Auto - Expert Insights
Setting Up ViciDial Callbacks (CALLBK) — Agent & Auto
Prerequisites
Understanding ViciDial Callbacks
What Are Callbacks?
Why Callbacks Matter
Key Database Tables
Agent Callbacks Configuration
Step 1: Enable Callbacks in Campaign Settings
Step 2: Configure Agent Callback Permissions
Step 3: Database Setup for Agent Callbacks
Step 4: Agent-Side Configuration
Step 5: Test Agent Callback
Automatic Callback Configuration
Step 1: Configure Disposition Rules
Step 2: Configure Auto-Callback Script
Step 3: Schedule Callback Processing via Cron
Step 4: Configure Asterisk for Callback Delivery
Step 5: Configure Callback Time Window & DNC
Callback Delivery & Queuing
Step 1: Configure Callback Queue
Step 2: Callback Outbound Route
Step 3: ViciDial Dialer Configuration
Callback Status Tracking
Monitor Callback Queue
Query Callback Status
Update Callback Status Manually
Advanced Configuration
Time Zone-Aware Callbacks
Callback with Voicemail Fallback
Callback with IVR Menu
Restrict Callback Frequency
Troubleshooting
Callbacks Not Triggering
Callbacks Queued But Not Dialing
Callbacks Showing Wrong Time
Callback Permission Denied
High Callback Failure Rate
Database Growing Too Large
Summary Learn how to configure and manage both agent-initiated and automatic callbacks in ViciDial with practical examples, database queries, and production troubleshooting techniques. Before implementing callbacks in ViciDial, ensure you have: Verify your installation: 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: Callbacks are stored primarily in these tables: Access the ViciDial web interface and navigate to Admin > Campaigns. Open /etc/asterisk/extensions-vicidial.conf and locate the agent login context. Add callback-specific permissions: Create callback records directly in the database. ViciDial's agent interface does this automatically, but you should understand the structure: Insert a test callback record: Agents access callbacks via the main call screen at /agc/vicidial.php. When an agent clicks Schedule Callback: To ensure agents see the callback button, verify their user privileges: The user must have modify_callback set to Y: Automatic callbacks trigger based on call dispositions. Configure this in Admin > Dispositions. Map dispositions to auto-callback actions: Database configuration: Update disposition for auto-callback: ViciDial uses scheduled scripts to process callbacks. Edit or create /usr/share/astguiclient/process_callbacks.pl: Add to /etc/cron.d/astguiclient: Edit /etc/asterisk/extensions-vicidial.conf to add callback delivery context: Prevent callbacks outside business hours: Add DNC (Do Not Call) exceptions for callbacks: ViciDial uses a dedicated callback queue. Configure in /etc/asterisk/queues.conf: Configure outbound routing for callbacks. In /etc/asterisk/extensions-vicidial.conf: Configure the ViciDial dialer to handle callbacks. Edit /etc/asterisk/sip-vicidial.conf: Real-time callback status: Callback completion report: If a callback fails and needs rescheduling: ViciDial respects customer time zones for callback scheduling. Configure in campaign: Set customer timezone in vicidial_list: Supported time zones (see /usr/share/zoneinfo/): Configure fallback to voicemail if callback fails: Route callbacks through an IVR before agent delivery: Prevent callback storms by tracking attempt frequency: Block leads with excessive callbacks: Symptom: Callbacks remain in PENDING status past their scheduled time. Symptom: Callbacks appear in database but agents don't receive calls. Then trigger a callback and watch output. Symptom: Callbacks display or execute at incorrect times. Should show system timezone. If showing SYSTEM, set explicitly: Symptom: Agents click Schedule Callback but get permission error. Symptom: Many callbacks marked FAILED status. Symptom: vicidial_callbacks table consuming excessive disk space. Archive old completed callbacks: Add automatic cleanup to cron: ViciDial callbacks—both agent-initiated and automatic—significantly improve contact rates and customer satisfaction when properly configured. This guide covered: 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_callbacks table, 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. Proper callback configuration transforms ViciDial from a simple dialer into an intelligent lead management system that works 24/7 on behalf of your agents. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse
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
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
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
SELECT campaign_id, campaign_name, allow_agent_callbacks, callback_time_window FROM vicidial_campaigns WHERE campaign_name = 'YOUR_CAMPAIGN';
SELECT campaign_id, campaign_name, allow_agent_callbacks, callback_time_window FROM vicidial_campaigns WHERE campaign_name = 'YOUR_CAMPAIGN';
SELECT campaign_id, campaign_name, allow_agent_callbacks, callback_time_window FROM vicidial_campaigns WHERE campaign_name = 'YOUR_CAMPAIGN';
campaign_id | campaign_name | allow_agent_callbacks | callback_time_window
1 | Sales | Y | 1440
campaign_id | campaign_name | allow_agent_callbacks | callback_time_window
1 | Sales | Y | 1440
campaign_id | campaign_name | allow_agent_callbacks | callback_time_window
1 | Sales | Y | 1440
[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()
[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()
[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()
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)
);
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)
);
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 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;
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;
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;
SELECT user_id, vicidial_login, modify_callbackcallback_time FROM vicidial_users WHERE vicidial_login = 'AGENT001';
SELECT user_id, vicidial_login, modify_callbackcallback_time FROM vicidial_users WHERE vicidial_login = 'AGENT001';
SELECT user_id, vicidial_login, modify_callbackcallback_time FROM vicidial_users WHERE vicidial_login = 'AGENT001';
UPDATE vicidial_users SET modify_callback = 'Y' WHERE vicidial_login = 'AGENT001';
UPDATE vicidial_users SET modify_callback = 'Y' WHERE vicidial_login = 'AGENT001';
UPDATE vicidial_users SET modify_callback = 'Y' WHERE vicidial_login = 'AGENT001';
SELECT * FROM vicidial_callbacks WHERE agent_id = 'AGENT001' ORDER BY created_date DESC LIMIT 1;
SELECT * FROM vicidial_callbacks WHERE agent_id = 'AGENT001' ORDER BY created_date DESC LIMIT 1;
SELECT * FROM vicidial_callbacks WHERE agent_id = 'AGENT001' ORDER BY created_date DESC LIMIT 1;
SELECT disposition_id, disposition, auto_callback_enabled, auto_callback_delay_minutes FROM vicidial_dispositions WHERE campaign_id = 1;
SELECT disposition_id, disposition, auto_callback_enabled, auto_callback_delay_minutes FROM vicidial_dispositions WHERE campaign_id = 1;
SELECT disposition_id, disposition, auto_callback_enabled, auto_callback_delay_minutes FROM vicidial_dispositions WHERE campaign_id = 1;
UPDATE vicidial_dispositions SET auto_callback_enabled = 'Y', auto_callback_delay_minutes = 30 WHERE disposition = 'NO ANSWER' AND campaign_id = 1;
UPDATE vicidial_dispositions SET auto_callback_enabled = 'Y', auto_callback_delay_minutes = 30 WHERE disposition = 'NO ANSWER' AND campaign_id = 1;
UPDATE vicidial_dispositions SET auto_callback_enabled = 'Y', auto_callback_delay_minutes = 30 WHERE disposition = 'NO ANSWER' AND campaign_id = 1;
#!/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);
#!/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);
#!/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);
chmod +x /usr/share/astguiclient/process_callbacks.pl
chown asterisk:asterisk /usr/share/astguiclient/process_callbacks.pl
chmod +x /usr/share/astguiclient/process_callbacks.pl
chown asterisk:asterisk /usr/share/astguiclient/process_callbacks.pl
chmod +x /usr/share/astguiclient/process_callbacks.pl
chown asterisk:asterisk /usr/share/astguiclient/process_callbacks.pl
# 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
# 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
# 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
systemctl restart cron
# or
systemctl restart crond
systemctl restart cron
# or
systemctl restart crond
systemctl restart cron
# or
systemctl restart crond
[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()
[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()
[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()
asterisk -rx "dialplan reload"
asterisk -rx "dialplan reload"
asterisk -rx "dialplan reload"
-- 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;
-- 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;
-- 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;
-- Ensure callbacks can override DNC
UPDATE vicidial_campaigns SET callback_ignore_dnc = 'Y' WHERE campaign_id = 1;
-- Ensure callbacks can override DNC
UPDATE vicidial_campaigns SET callback_ignore_dnc = 'Y' WHERE campaign_id = 1;
-- Ensure callbacks can override DNC
UPDATE vicidial_campaigns SET callback_ignore_dnc = 'Y' WHERE campaign_id = 1;
[callback-queue]
strategy = ringall
timeout = 45
retry = 3
weight = 0
autopause = no
announce-frequency = 0
announce-holdtime = no
maxlen = 500
[callback-queue]
strategy = ringall
timeout = 45
retry = 3
weight = 0
autopause = no
announce-frequency = 0
announce-holdtime = no
maxlen = 500
[callback-queue]
strategy = ringall
timeout = 45
retry = 3
weight = 0
autopause = no
announce-frequency = 0
announce-holdtime = no
maxlen = 500
[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()
[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()
[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()
[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
[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
[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
asterisk -rx "sip reload"
asterisk -rx "sip reload"
asterisk -rx "sip reload"
asterisk -rx "queue show callback-queue"
asterisk -rx "queue show callback-queue"
asterisk -rx "queue show callback-queue"
callback-queue has 5 calls (max unlimited) in 'ringall' strategy
No members are available (1 call waiting)
callback-queue has 5 calls (max unlimited) in 'ringall' strategy
No members are available (1 call waiting)
callback-queue has 5 calls (max unlimited) in 'ringall' strategy
No members are available (1 call waiting)
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;
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;
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;
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;
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;
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 vicidial_callbacks SET callback_time = DATE_ADD(NOW(), INTERVAL 24 HOUR), status = 'PENDING'
WHERE callback_id = 42;
UPDATE vicidial_callbacks SET callback_time = DATE_ADD(NOW(), INTERVAL 24 HOUR), status = 'PENDING'
WHERE callback_id = 42;
UPDATE vicidial_callbacks SET callback_time = DATE_ADD(NOW(), INTERVAL 24 HOUR), status = 'PENDING'
WHERE callback_id = 42;
UPDATE vicidial_callbacks SET status = 'CANCELLED'
WHERE callback_id = 42;
UPDATE vicidial_callbacks SET status = 'CANCELLED'
WHERE callback_id = 42;
UPDATE vicidial_callbacks SET status = 'CANCELLED'
WHERE callback_id = 42;
UPDATE vicidial_campaigns SET callback_respect_timezone = 'Y' WHERE campaign_id = 1;
UPDATE vicidial_campaigns SET callback_respect_timezone = 'Y' WHERE campaign_id = 1;
UPDATE vicidial_campaigns SET callback_respect_timezone = 'Y' WHERE campaign_id = 1;
UPDATE vicidial_list SET customer_timezone = 'America/Chicago' WHERE lead_id = 1001;
UPDATE vicidial_list SET customer_timezone = 'America/Chicago' WHERE lead_id = 1001;
UPDATE vicidial_list SET customer_timezone = 'America/Chicago' WHERE lead_id = 1001;
[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()
[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()
[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-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)
[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)
[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)
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;
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;
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;
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
);
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
);
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
);
ps aux | grep process_callbacks.pl
ps aux | grep process_callbacks.pl
ps aux | grep process_callbacks.pl
grep process_callbacks /var/log/syslog
# or
tail -50 /var/log/asterisk/callbacks.log
grep process_callbacks /var/log/syslog
# or
tail -50 /var/log/asterisk/callbacks.log
grep process_callbacks /var/log/syslog
# or
tail -50 /var/log/asterisk/callbacks.log
ls -la /usr/share/astguiclient/process_callbacks.pl
# Should show: -rwxr-xr-x asterisk:asterisk
ls -la /usr/share/astguiclient/process_callbacks.pl
# Should show: -rwxr-xr-x asterisk:asterisk
ls -la /usr/share/astguiclient/process_callbacks.pl
# Should show: -rwxr-xr-x asterisk:asterisk
sudo -u asterisk /usr/share/astguiclient/process_callbacks.pl
echo $? # Should return 0 on success
sudo -u asterisk /usr/share/astguiclient/process_callbacks.pl
echo $? # Should return 0 on success
sudo -u asterisk /usr/share/astguiclient/process_callbacks.pl
echo $? # Should return 0 on success
mysql -u root -p asterisk -e "SELECT COUNT(*) FROM vicidial_callbacks WHERE status='PENDING';"
mysql -u root -p asterisk -e "SELECT COUNT(*) FROM vicidial_callbacks WHERE status='PENDING';"
mysql -u root -p asterisk -e "SELECT COUNT(*) FROM vicidial_callbacks WHERE status='PENDING';"
asterisk -rx "dialplan show callback-delivery"
asterisk -rx "dialplan show callback-delivery"
asterisk -rx "dialplan show callback-delivery"
asterisk -rx "sip show peers"
asterisk -rx "sip show peers"
asterisk -rx "sip show peers"
asterisk -rx "core show channels"
asterisk -rx "core show channels"
asterisk -rx "core show channels"
asterisk -rn
asterisk -rn
asterisk -rn
asterisk -rx "channel originate SIP/TRUNK/5551234567 extension test@from-internal"
asterisk -rx "channel originate SIP/TRUNK/5551234567 extension test@from-internal"
asterisk -rx "channel originate SIP/TRUNK/5551234567 extension test@from-internal"
timedatectl status
date
timedatectl status
date
timedatectl status
date
SELECT @@global.time_zone, @@session.time_zone;
SELECT @@global.time_zone, @@session.time_zone;
SELECT @@global.time_zone, @@session.time_zone;
SET GLOBAL time_zone = 'America/Chicago';
SET GLOBAL time_zone = 'America/Chicago';
SET GLOBAL time_zone = 'America/Chicago';
SELECT callback_respect_timezone, campaign_timezone FROM vicidial_campaigns WHERE campaign_id = 1;
SELECT callback_respect_timezone, campaign_timezone FROM vicidial_campaigns WHERE campaign_id = 1;
SELECT callback_respect_timezone, campaign_timezone FROM vicidial_campaigns WHERE campaign_id = 1;
SELECT lead_id, customer_timezone FROM vicidial_list WHERE lead_id = 1001;
SELECT lead_id, customer_timezone FROM vicidial_list WHERE lead_id = 1001;
SELECT lead_id, customer_timezone FROM vicidial_list WHERE lead_id = 1001;
SELECT user_id, vicidial_login, modify_callback, campaign_id FROM vicidial_users WHERE vicidial_login = 'AGENT001';
SELECT user_id, vicidial_login, modify_callback, campaign_id FROM vicidial_users WHERE vicidial_login = 'AGENT001';
SELECT user_id, vicidial_login, modify_callback, campaign_id FROM vicidial_users WHERE vicidial_login = 'AGENT001';
UPDATE vicidial_users SET modify_callback = 'Y' WHERE vicidial_login = 'AGENT001';
UPDATE vicidial_users SET modify_callback = 'Y' WHERE vicidial_login = 'AGENT001';
UPDATE vicidial_users SET modify_callback = 'Y' WHERE vicidial_login = 'AGENT001';
SELECT allow_agent_callbacks FROM vicidial_campaigns WHERE campaign_id = 1;
SELECT allow_agent_callbacks FROM vicidial_campaigns WHERE campaign_id = 1;
SELECT allow_agent_callbacks FROM vicidial_campaigns WHERE campaign_id = 1;
UPDATE vicidial_campaigns SET allow_agent_callbacks = 'Y' WHERE campaign_id = 1;
UPDATE vicidial_campaigns SET allow_agent_callbacks = 'Y' WHERE campaign_id = 1;
UPDATE vicidial_campaigns SET allow_agent_callbacks = 'Y' WHERE campaign_id = 1;
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;
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;
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;
asterisk -rx "core show channels brief" | wc -l
asterisk -rx "core show channels brief" | wc -l
asterisk -rx "core show channels brief" | wc -l
asterisk -rx "sip show peers" | grep YOUR_TRUNK
asterisk -rx "sip show peers" | grep YOUR_TRUNK
asterisk -rx "sip show peers" | grep YOUR_TRUNK
tail -200 /var/log/asterisk/full
grep -i callback /var/log/asterisk/full | tail -50
tail -200 /var/log/asterisk/full
grep -i callback /var/log/asterisk/full | tail -50
tail -200 /var/log/asterisk/full
grep -i callback /var/log/asterisk/full | tail -50
grep -i "^.*SIP/.*401\|^.*SIP/.*403" /var/log/asterisk/full | tail -20
grep -i "^.*SIP/.*401\|^.*SIP/.*403" /var/log/asterisk/full | tail -20
grep -i "^.*SIP/.*401\|^.*SIP/.*403" /var/log/asterisk/full | tail -20
# In /etc/asterisk/sip-vicidial.conf, check:
# - username
# - secret (password)
# - host IP
# - port (usually 5060)
# In /etc/asterisk/sip-vicidial.conf, check:
# - username
# - secret (password)
# - host IP
# - port (usually 5060)
# In /etc/asterisk/sip-vicidial.conf, check:
# - username
# - secret (password)
# - host IP
# - port (usually 5060)
-- 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;
-- 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;
-- 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;
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
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
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 - 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 - Agent Callbacks (CALLBK) — Agents schedule callbacks directly from the call screen
- Auto Callbacks — System automatically reschedules based on lead disposition rules - 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 - vicidial_log — Call history with called_count, status, callback_time
- vicidial_callbacks — Dedicated callback records with phone, time, agent
- vicidial_carrier_log — Route tracking for callback attempts
- vicidial_lists — Campaign list configuration with callback settings - Select your campaign
- Scroll to Callback Settings
- Set Allow Agent Callbacks to YES
- Set Callback Time Window (e.g., 1 day, 7 days, 30 days)
- Enable Allow Same-Day Callbacks if needed
- Set Callback Dial Timeout to 45-60 seconds
- Save changes - 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 - 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: - America/New_York
- America/Chicago
- America/Denver
- America/Los_Angeles
- America/Anchorage
- Pacific/Honolulu - Verify cron job is running: - Check cron logs: - Verify script has correct permissions: - Manually test the script: - Check MySQL connectivity from callback script: - Check Asterisk dialplan loaded: - Verify SIP trunk is registered: - Check channel availability: - Review Asterisk CLI logs in real-time: - Test trunk dial directly: - Verify server timezone: - Verify MySQL timezone: - Verify ViciDial campaign timezone setting: - Check individual lead timezone: - Verify agent user has callback permission: - Enable callback permission: - Verify campaign allows agent callbacks: - If disabled, enable: - Reload ViciDial web interface (clear browser cache). - Review failure reasons: - Check trunk capacity: - Verify carrier is accepting calls: - Review Asterisk full logs: - Check for SIP errors (401 UNAUTHORIZED, 403 FORBIDDEN): - If carrier rejects, verify credentials: - 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_callbacks table, 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. - 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 - Deploy the process_callbacks.pl script 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