Learn to deactivate inactive leads, reset call counts, purge bad data, and safely delete lists without breaking agent workflows or violating call compliance rules.
Prerequisites
You need the following to work through this guide:
- Root or sudo access to your ViciDial server.
- MySQL/MariaDB command-line access or a tool like phpMyAdmin.
- Understanding of the ViciDial database schema, specifically the vicidial_list and vicidial_log tables.
- An active ViciDial installation (version 2.14+ recommended).
- Asterisk running with ViciDial agent module loaded.
- A test list or non-production list to practice on first.
- SSH access to the server where ViciDial runs.
- Backup of your entire ViciDial database before making bulk changes.
If you're running ViciDial in Docker or a custom build, adjust paths accordingly. This guide assumes a standard Linux installation at /var/www/html/vicidial/ with MySQL at localhost.
Understanding ViciDial list states and the lead lifecycle
Before you modify or delete leads, understand how ViciDial tracks them.
Lead statuses in vicidial_list table
The vicidial_list table stores all contacts. The status column determines what happens to each lead:
- NEW: Agent has never touched it. Dialer will attempt.
- ACTIVE: Agent called it. Outcome is one of your call results.
- INACTIVE: Marked do-not-call or bad number. Dialer skips it.
- HOLD: Callback scheduled. Agent set a return date/time.
- DEAD: Lead exhausted after max attempts. Dialer does not call again.
Each status flows through your dialplan. Understanding which status blocks dialing prevents accidents when you reset or deactivate in bulk.
The difference between reset, deactivate, and delete
Reset: Changes status back to NEW, clears phone attempts, lets dialer call again. Useful for bad data or testing.
Deactivate: Changes status to INACTIVE. Dialer never calls it. Phone remains in list. Useful for GDPR/TCPA compliance or known bad numbers.
Delete: Removes the row from vicidial_list entirely. Cannot be undone without backup. Use only for test data or spam.
Deleting is irreversible. Deactivation is safer. Reset is reversible if you have transaction logs.
Method 1: Deactivate leads via the web admin interface
The safest method for small batches is the ViciDial admin panel.
Access the admin panel and locate list management
Open your browser and navigate to your ViciDial admin URL. It is usually:
http://<your-vicidial-server>/vicidial/admin.php
Log in with an admin account. From the left sidebar, find "Manage Lists" or "List Management".
Filter leads by status or criteria
On the List Management page, select your list from the dropdown. Then set filters:
- Status: Select ACTIVE or NEW to narrow down what you see.
- Area code: Filter by geography if needed.
- Created date: Filter by when the lead was added.
- Last call date: Find leads never called or last called before a cutoff.
Apply the filter. The page displays matching leads.
Bulk deactivate from the interface
Select the checkbox "Select all visible" at the top of the results table. A dropdown menu appears offering actions:
- Change Status
- Send to List
- Export to CSV
- Delete
Choose "Change Status" and select INACTIVE from the submenu. A confirmation page appears. Review the count of affected leads. Click Confirm.
The status change is immediate. No database restart needed.
This method is slow for lists larger than a few thousand leads because the web interface processes one page at a time. For large lists, use SQL directly.
Method 2: Reset and deactivate leads using direct SQL commands
SQL is faster and more precise. This is the method used in production for nightly bulk operations.
Connect to the vicidial database
SSH into your ViciDial server and access MySQL:
mysql -u root -p asterisk
When prompted, enter your MySQL root password. You see the mysql> prompt.
Verify you are in the asterisk database:
SELECT DATABASE();
Output should show asterisk. If not, run:
USE asterisk;
Deactivate leads by status
To mark all NEW leads in a specific list as INACTIVE:
UPDATE vicidial_list
SET status = 'INACTIVE'
WHERE list_id = '101'
AND status = 'NEW';
Check the result. MySQL returns the number of rows affected. If the count seems wrong, run a SELECT first to preview:
SELECT COUNT(*) FROM vicidial_list
WHERE list_id = '101'
AND status = 'NEW';
This query counts without changing data. Run it before the UPDATE to make sure your WHERE clause is correct.
Deactivate by last call date
To deactivate leads that were never called or not called in the last 90 days:
UPDATE vicidial_list
SET status = 'INACTIVE'
WHERE list_id = '101'
AND (last_local_call_time IS NULL
OR last_local_call_time < DATE_SUB(NOW(), INTERVAL 90 DAY));
This helps clean up stale leads without removing them from the database.
Reset leads back to NEW status
To reset all ACTIVE leads in a list back to NEW so they can be dialed again:
UPDATE vicidial_list
SET status = 'NEW',
call_count = 0,
last_local_call_time = NULL
WHERE list_id = '101'
AND status = 'ACTIVE';
Setting call_count to 0 tells the dialer this lead has never been attempted. The dialer will call it as a fresh lead. Be cautious: if agents see the same person twice, they may hang up or complain.
Reset leads with a specific phone number or pattern
To reset all leads with a phone number matching a pattern:
UPDATE vicidial_list
SET status = 'NEW',
call_count = 0
WHERE list_id = '101'
AND phone_number LIKE '555%';
This is useful if you know a phone number range was entered incorrectly or is no longer valid for calling.
Check changes before committing
If you want to preview changes without applying them, wrap the command in a transaction:
START TRANSACTION;
UPDATE vicidial_list
SET status = 'INACTIVE'
WHERE list_id = '101'
AND status = 'NEW';
SELECT COUNT(*) FROM vicidial_list WHERE list_id = '101' AND status = 'INACTIVE';
ROLLBACK;
The ROLLBACK undoes the change. Run the same query with COMMIT instead of ROLLBACK to apply permanently.
Method 3: Delete leads and entire lists
Deletion is permanent. Back up first.
Backup the vicidial_list table before deletion
From the bash prompt, create a SQL dump:
mysqldump -u root -p asterisk vicidial_list > vicidial_list_backup_$(date +%Y%m%d_%H%M%S).sql
Enter your MySQL password. A file is created with a timestamp. Store this somewhere safe, not on the same disk as the database.
Delete individual leads by phone number
To delete a specific phone number from a list:
DELETE FROM vicidial_list
WHERE list_id = '101'
AND phone_number = '5551234567';
MySQL reports how many rows were deleted. If zero rows were deleted, the phone number did not exist in that list.
Delete all leads in a list
To delete every lead in a list:
DELETE FROM vicidial_list
WHERE list_id = '101';
This removes all contacts. The list itself remains in the vicidial_lists table and can be imported again.
Delete leads by status
To delete only INACTIVE leads to reclaim space:
DELETE FROM vicidial_list
WHERE list_id = '101'
AND status = 'INACTIVE';
This is useful for removing do-not-call contacts or cleaned-up data.
Verify deletion and check referential integrity
After deletion, confirm the list count:
SELECT COUNT(*) FROM vicidial_list WHERE list_id = '101';
Check if any orphaned records exist in vicidial_log (the call history table):
SELECT COUNT(*) FROM vicidial_log
WHERE list_id = '101'
AND lead_id NOT IN (SELECT lead_id FROM vicidial_list);
If this count is non-zero, you have call records for leads that no longer exist. This is harmless but leaves dead data. To clean it:
DELETE FROM vicidial_log
WHERE list_id = '101'
AND lead_id NOT IN (SELECT lead_id FROM vicidial_list);
Method 4: Reset leads using the CLI tools
ViciDial ships with command-line scripts in /usr/share/astguiclient/. Use these for automation in cron jobs.
List available CLI tools
Navigate to the tools directory:
ls -la /usr/share/astguiclient/ | grep -E '\.pl$'
You see Perl scripts. The main ones for list management are:
- ADMIN_reset_list.pl: Resets call counts on a list.
- ADMIN_vicidial_list_load.pl: Imports lists into the database.
- ADMIN_phonebook_manager.pl: Manages contacts.
Run ADMIN_reset_list.pl to reset call counts
This script resets the call_count field for all leads in a list:
/usr/share/astguiclient/ADMIN_reset_list.pl --list-id 101
The script does not prompt. It immediately resets. Output is minimal. To see what it does, run with verbose flag if supported:
perl /usr/share/astguiclient/ADMIN_reset_list.pl --list-id 101 --verbose
Check the /var/log/astguiclient/ logs to see what was executed:
tail -f /var/log/astguiclient/ADMIN_reset_list.log
Logs are not always written, so check the database to confirm:
SELECT COUNT(*), AVG(call_count), MAX(call_count) FROM vicidial_list WHERE list_id = '101';
If all call_count values are now 0 or lower than before, the reset worked.
Schedule list resets in cron
To reset a list every night at 2 AM:
crontab -e
Add this line:
0 2 * * * /usr/share/astguiclient/ADMIN_reset_list.pl --list-id 101 >> /var/log/astguiclient/cron_reset.log 2>&1
Save and exit. The script runs daily. Check the log file to confirm success:
tail /var/log/astguiclient/cron_reset.log
Method 5: Bulk import status changes from CSV
If you have a list of lead IDs and new statuses in a spreadsheet, import them via CSV.
Prepare the CSV file
Create a CSV with three columns: list_id, lead_id, status.
list_id,lead_id,status
101,50001,INACTIVE
101,50002,INACTIVE
101,50003,NEW
102,50100,HOLD
Save as leads_update.csv.
Use ADMIN_phonebook_manager.pl to import
The phonebook manager script can import and update leads:
/usr/share/astguiclient/ADMIN_phonebook_manager.pl \
--import-csv leads_update.csv \
--action update
Check the output for errors. If successful, verify in the database:
SELECT lead_id, status FROM vicidial_list WHERE lead_id IN (50001, 50002, 50003);
If the script fails or is unavailable in your version, fall back to writing a bash loop that runs SQL UPDATE statements for each row.
Bash loop for CSV import
Create a file update_leads.sh:
#!/bin/bash
while IFS=',' read -r list_id lead_id status; do
if [ "$list_id" != "list_id" ]; then
mysql -u root -p'yourpassword' asterisk -e \
"UPDATE vicidial_list SET status='$status' WHERE list_id=$list_id AND lead_id=$lead_id;"
fi
done < leads_update.csv
echo "Import complete."
Make it executable:
chmod +x update_leads.sh
./update_leads.sh
This updates the database row by row. It is slower than a single SQL statement but works when the CLI tools are missing or incompatible.
Managing list state during agent campaigns
Agents dial from lists. If you modify a list while agents are on calls, cache inconsistencies can occur.
Pause the dialer before bulk changes
To stop the dialer from assigning new leads:
Log into the admin panel and navigate to Campaign Management. Find your campaign and click Pause. The dialer stops pulling new leads from queues. Agents on active calls continue.
Wait for current calls to finish or hang them up manually. Then run your SQL updates. Finally, Resume the campaign.
Alternatively, from the CLI, check the status using Asterisk:
asterisk -rx "vicidial show dialers"
This shows active dialers. If your ViciDial version supports it, you can restart the dialer:
service vicidial restart
This stops all campaigns. Agents are logged out. Campaigns resume after restart.
Clear the agent session cache
If an agent remains logged in after you modify a list, their local cache may be stale. Force a logout:
UPDATE vicidial_users SET logged_in = 0 WHERE user='agentname';
The agent must log back in. On login, they fetch fresh list data.
Monitor lead assignment with vicidial_log
After resuming campaigns, check that leads are being called:
SELECT DATE(call_date), COUNT(*) FROM vicidial_log
WHERE list_id = '101'
AND call_date > DATE_SUB(NOW(), INTERVAL 1 HOUR)
GROUP BY DATE(call_date);
This shows calls in the last hour grouped by date. If the count is zero or very low, the dialer may not be working correctly.
Compliance and audit trails
Deactivating or deleting leads must be logged for GDPR, TCPA, or internal policy compliance.
Log all manual changes to a separate table
Create an audit table to track who changed what:
CREATE TABLE IF NOT EXISTS vicidial_lead_audit (
audit_id INT AUTO_INCREMENT PRIMARY KEY,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
changed_by VARCHAR(50),
list_id INT,
lead_id INT,
old_status VARCHAR(20),
new_status VARCHAR(20),
reason TEXT
);
Before running a bulk UPDATE, log it:
INSERT INTO vicidial_lead_audit (changed_by, list_id, old_status, new_status, reason)
SELECT 'admin', list_id, status, 'INACTIVE', 'Stale leads, not called in 90 days'
FROM vicidial_list
WHERE list_id = '101'
AND status = 'NEW'
AND (last_local_call_time IS NULL OR last_local_call_time < DATE_SUB(NOW(), INTERVAL 90 DAY));
UPDATE vicidial_list
SET status = 'INACTIVE'
WHERE list_id = '101'
AND status = 'NEW'
AND (last_local_call_time IS NULL OR last_local_call_time < DATE_SUB(NOW(), INTERVAL 90 DAY));
Query the audit table to see all changes:
SELECT * FROM vicidial_lead_audit ORDER BY timestamp DESC LIMIT 100;
Export a compliance report
Before deactivating a large batch, export the affected leads:
mysql -u root -p asterisk -e \
"SELECT lead_id, phone_number, status, last_local_call_time FROM vicidial_list WHERE list_id='101' AND status='NEW';" \
> leads_to_deactivate_$(date +%Y%m%d).csv
Store this file with your compliance records. It proves which numbers you stopped calling and when.
Troubleshooting
Problem: Leads still appear in agent screen after marking INACTIVE
Cause: Agent session cache not cleared. Dialer or agent application is cached.
Solution: Log the agent out or force a session refresh:
UPDATE vicidial_users SET logged_in = 0 WHERE user='agentname';
UPDATE vicidial_user_sessions SET session_alive = 'N' WHERE user='agentname';
Kill the agent's PHP session on the web server:
rm -f /tmp/vicidial_sessions/*agentname*
Have the agent log out and back in. The agent screen refreshes list data on login.
Problem: Call counts are not resetting
Cause: The status is being changed but call_count field is not cleared, or the dialer is not picking up the reset.
Solution: Manually clear call_count:
UPDATE vicidial_list SET call_count = 0 WHERE list_id = '101' AND status = 'NEW';
Restart the dialer process:
service vicidial restart
Verify the change with a SELECT:
SELECT lead_id, call_count, status FROM vicidial_list WHERE list_id = '101' LIMIT 5;
Problem: Deletion query takes too long and locks the database
Cause: vicidial_list is large (100K+ rows) and the DELETE statement is blocking other queries.
Solution: Delete in smaller batches:
DELETE FROM vicidial_list WHERE list_id = '101' AND status = 'INACTIVE' LIMIT 10000;
Run this repeatedly until all rows are gone. Check progress:
watch -n 5 "mysql -u root -p'password' asterisk -e 'SELECT COUNT(*) FROM vicidial_list WHERE list_id=101;'"
This command refreshes every 5 seconds, showing the row count shrinking.
Alternatively, use the ADMIN tools:
/usr/share/astguiclient/ADMIN_archiver.pl --archive-list-id 101
This archives and removes old list data without locking the live table.
Problem: MySQL error "Duplicate entry" when importing CSV
Cause: A lead_id already exists in the list and you are trying to insert instead of update.
Solution: Use INSERT...ON DUPLICATE KEY UPDATE:
INSERT INTO vicidial_list (list_id, lead_id, phone_number, status)
VALUES (101, 50001, '5551234567', 'NEW')
ON DUPLICATE KEY UPDATE status = 'NEW';
This updates the status if the lead exists, or inserts if it does not.
Problem: Asterisk logs show "Unknown lead" errors after deletion
Cause: The dialer assigned a lead_id that no longer exists in vicidial_list, then the agent tried to call it.
Solution: Check for gaps in lead_id assignment:
SELECT COUNT(*) FROM vicidial_log WHERE list_id = '101' AND lead_id NOT IN (SELECT lead_id FROM vicidial_list);
If the count is high, orphaned log records exist. Clean them:
DELETE FROM vicidial_log WHERE list_id = '101' AND lead_id NOT IN (SELECT lead_id FROM vicidial_list);
Then restart the dialer to reload the list:
service vicidial restart
Problem: Web admin interface hangs when loading a large list
Cause: The list has millions of leads and the admin page tries to display them all.
Solution: Do not use the web interface. Use SQL or CLI tools instead.
For viewing, add a LIMIT to the SQL query:
SELECT * FROM vicidial_list WHERE list_id = '101' LIMIT 100;
To deactivate, use SQL directly, not the web admin.
Summary
You now know five methods to manage ViciDial lists in production: the web admin interface, direct SQL, CLI tools, CSV import, and batch scripting. The safest approach for small changes is the admin panel. For large bulk operations, SQL is faster and less error-prone.
Before making any change to a production list, back up the vicidial_list table. Deactivation is safer than deletion because it preserves the lead record. Reset call_count and status only when you intend for leads to be dialed again. Always pause campaigns or log out agents before bulk modifications to avoid cache conflicts.
Log all major changes to an audit table for compliance. Monitor the vicidial_log table after changes to confirm the dialer is working. If locks or slowdowns occur, use batch deletes with LIMIT or the ADMIN archiver tool.
Test all changes on a non-production list first. Check the database directly with SELECT queries before running UPDATE or DELETE statements. Verify agent screens reflect changes after modifications are complete. If issues arise, check the Asterisk logs at /var/log/asterisk/messages and the ViciDial CLI logs at /var/log/astguiclient/.