← All Tutorials

How to Manage ViciDial Lists: Deactivate, Reset & Delete Leads

ViciDial Administration Intermediate 16 min read #100 Published · Updated

Permanently remove leads, recycle phone numbers, and reset list state without data loss or orphaned records.

List management in ViciDial involves three distinct operations: deactivation (marking leads inactive while keeping records), reset (clearing call history and status to retry a campaign), and deletion (removing records from the database). Each operation interacts differently with the call log, agent notes, and list state. Performing them incorrectly leaves orphaned records, duplicate dials, or blocks legitimate callback attempts. This tutorial covers the safe procedures for all three, the database tables involved, and recovery methods when operations go wrong.

Tested on ViciDial 2.14+ (SVN 3555+), Asterisk 16/18, MariaDB 10.5+

Prerequisites

Understanding ViciDial list status codes

Before performing any operation, you must understand how ViciDial stores lead state. A lead is defined by its record in the vicidial_list table. Its disposition is stored in the status field using two-letter codes.

Common status codes:

The status field is case-sensitive. Always verify actual status values in your database before filtering:

mysql -u asterisk -p asterisk -e "SELECT DISTINCT status FROM vicidial_list LIMIT 20;"

Deactivating leads without deletion

Deactivation marks leads inactive while preserving all call history, notes, and audit trails. This is the safest approach for removing leads from active campaigns without losing data.

Why deactivate instead of delete?

Deleted records cannot be recovered without a database restore. Deactivated records remain queryable for reports, compliance audits, and callback analysis. If a client later disputes a call or charges back, the record still exists. Regulatory bodies (FCC, TCPA) expect records to persist for the call history they represent.

Mark a list as inactive via the web interface

Navigate to /vicidial/admin.php and log in as administrator.

  1. Go to Lists menu > List Management
  2. Find the list by list_id or description
  3. Click Edit
  4. Set "Status" to "INACTIVE"
  5. Save

This changes only the list record, not individual leads. Active agents still see the list in their dropdown but cannot dial it.

Deactivate specific leads by phone number

To deactivate a subset of leads (e.g., complaints, do-not-calls), use the database directly. Back up first:

mysqldump -u asterisk -p asterisk vicidial_list > /backup/vicidial_list_$(date +%Y%m%d_%H%M%S).sql

Then update leads matching phone numbers:

UPDATE vicidial_list 
SET status = 'DEAD' 
WHERE phone_number IN (
  '5551234567',
  '5559876543'
) 
AND list_id = 101;

Verify the count before executing:

SELECT COUNT(*) FROM vicidial_list 
WHERE phone_number IN ('5551234567', '5559876543') 
AND list_id = 101;

Deactivate all leads in a list

If you want to halt a campaign entirely, mark all leads in that list as DEAD:

UPDATE vicidial_list 
SET status = 'DEAD' 
WHERE list_id = 101;

Check the impact first:

SELECT COUNT(*) FROM vicidial_list 
WHERE list_id = 101 
AND status NOT IN ('DEAD', 'XFER', 'DNC');

This counts leads still available for dialing. If the number is high and you want to pause rather than kill the list, set list status to INACTIVE instead.

Deactivate leads with a specific disposition or age

Deactivate leads that were last dialed before a certain date:

UPDATE vicidial_list 
SET status = 'DEAD' 
WHERE list_id = 101 
AND last_call_time < DATE_SUB(NOW(), INTERVAL 90 DAY) 
AND status = 'CALLBACK';

This removes stale callbacks. Verify nothing has already called them recently:

SELECT list_id, phone_number, status, last_call_time, last_local_call_time 
FROM vicidial_list 
WHERE list_id = 101 
AND last_call_time < DATE_SUB(NOW(), INTERVAL 90 DAY) 
LIMIT 5;

Resetting leads for re-dialing

Resetting clears the call history and disposition from a lead while keeping the phone number and list assignment. This is used when you want agents to re-attempt leads in a campaign.

Why reset instead of deactivate?

Deactivation removes leads from the active pool permanently. Reset returns them to NEW or CALLBACK status so they can be dialed again. Common reasons: campaign rule changes, new agent skill set, or a manual call from the client asking for a second attempt.

Reset all leads in a list to NEW

Backup the database first:

mysqldump -u asterisk -p asterisk vicidial_list vicidial_log > /backup/before_reset_$(date +%Y%m%d_%H%M%S).sql

Then reset:

UPDATE vicidial_list 
SET status = 'NEW', 
    last_call_time = NULL, 
    last_local_call_time = NULL, 
    country_code = NULL 
WHERE list_id = 101;

This removes all disposition and call timing but preserves the phone number, owner, and custom fields. Leads appear as if never dialed.

The script will run quickly on lists under 100,000 leads. Large lists may lock the table for 30+ seconds. Run during off-hours or stagger the reset:

UPDATE vicidial_list 
SET status = 'NEW', 
    last_call_time = NULL, 
    last_local_call_time = NULL 
WHERE list_id = 101 
AND lead_id >= 1000000 
AND lead_id < 1010000 
LIMIT 10000;

Repeat with different lead_id ranges to spread the load.

Reset only leads with a specific status

Reset callbacks that were scheduled more than 7 days ago:

UPDATE vicidial_list 
SET status = 'NEW', 
    last_call_time = NOW(), 
    last_local_call_time = NOW() 
WHERE list_id = 101 
AND status = 'CALLBACK' 
AND callback_datetime < DATE_SUB(NOW(), INTERVAL 7 DAY);

This prevents agents from seeing ancient callbacks in their list.

Reset a sample of leads for AB testing

To test a script change or new IVR on a subset:

UPDATE vicidial_list 
SET status = 'NEW', 
    last_call_time = NULL 
WHERE list_id = 101 
AND lead_id % 100 < 10 
AND status IN ('DEAD', 'DISPO');

The modulo operator (lead_id % 100 < 10) selects roughly 10% of leads evenly distributed. Verify before running:

SELECT COUNT(*) FROM vicidial_list 
WHERE list_id = 101 
AND lead_id % 100 < 10;

Clear notes and custom fields during reset

To fully reset without preserving notes:

UPDATE vicidial_list 
SET status = 'NEW', 
    comments = '', 
    last_call_time = NULL, 
    last_local_call_time = NULL, 
    user = NULL 
WHERE list_id = 101;

This also clears the user field (agent who last handled it). Use with caution on compliance-sensitive lists because comments may hold required audit information.

Deleting leads permanently

Deletion removes records from the database entirely. This is irreversible without a database restore, so perform only after backups and verification.

When to delete leads

Delete only when:

Do not delete leads from completed campaigns. Archive by deactivation instead.

Delete leads by phone number

mysqldump -u asterisk -p asterisk vicidial_list vicidial_log > /backup/before_delete_$(date +%Y%m%d_%H%M%S).sql

Then verify count:

SELECT COUNT(*) FROM vicidial_list 
WHERE phone_number IN ('5551234567', '5559876543') 
AND list_id = 101;

If the count matches expectation:

DELETE FROM vicidial_list 
WHERE phone_number IN ('5551234567', '5559876543') 
AND list_id = 101;

Delete duplicate leads within a list

Find duplicates first:

SELECT phone_number, COUNT(*) as count 
FROM vicidial_list 
WHERE list_id = 101 
GROUP BY phone_number 
HAVING count > 1 
ORDER BY count DESC 
LIMIT 10;

To keep only the oldest (first-imported) copy and delete newer duplicates:

DELETE vl FROM vicidial_list vl 
WHERE list_id = 101 
AND lead_id NOT IN (
  SELECT MIN(lead_id) 
  FROM vicidial_list 
  WHERE list_id = 101 
  GROUP BY phone_number
);

This is a safe way to remove accidental duplicates. Verify the count:

SELECT COUNT(*) FROM vicidial_list 
WHERE list_id = 101 
AND lead_id NOT IN (
  SELECT MIN(lead_id) 
  FROM vicidial_list 
  WHERE list_id = 101 
  GROUP BY phone_number
);

Delete all leads in a list

Before deleting the entire list:

SELECT COUNT(*) FROM vicidial_list WHERE list_id = 101;
SELECT COUNT(*) FROM vicidial_log WHERE list_id = 101;
SELECT COUNT(*) FROM vicidial_closer_log WHERE list_id = 101;

Then back up:

mysqldump -u asterisk -p asterisk vicidial_list vicidial_log vicidial_closer_log > /backup/list_101_$(date +%Y%m%d).sql

Delete only the leads, not the list itself:

DELETE FROM vicidial_list WHERE list_id = 101;

The call logs remain intact in vicidial_log and vicidial_closer_log. Reporting still works.

Cascade delete (advanced)

If you need to delete leads and all related call log entries:

mysqldump -u asterisk -p asterisk > /backup/full_backup_$(date +%Y%m%d).sql

Get the lead IDs:

SELECT GROUP_CONCAT(lead_id) FROM vicidial_list WHERE list_id = 101 LIMIT 1 \G

Then delete in transaction:

START TRANSACTION;
DELETE FROM vicidial_log WHERE list_id = 101;
DELETE FROM vicidial_closer_log WHERE list_id = 101;
DELETE FROM vicidial_list WHERE list_id = 101;
COMMIT;

This removes the entire record chain. It is slower and locks more tables. Use only when you must remove all traces.

Verifying list state after operations

After any bulk operation, verify consistency:

SELECT 
  list_id,
  COUNT(*) as total_leads,
  SUM(CASE WHEN status = 'NEW' THEN 1 ELSE 0 END) as new_leads,
  SUM(CASE WHEN status = 'CALLBACK' THEN 1 ELSE 0 END) as callbacks,
  SUM(CASE WHEN status = 'DEAD' THEN 1 ELSE 0 END) as dead_leads,
  SUM(CASE WHEN status = 'DNC' THEN 1 ELSE 0 END) as dnc_leads
FROM vicidial_list
WHERE list_id = 101
GROUP BY list_id;

Check for orphaned call logs (leads deleted but calls remain):

SELECT COUNT(*) FROM vicidial_log vl
WHERE NOT EXISTS (
  SELECT 1 FROM vicidial_list vll 
  WHERE vll.lead_id = vl.lead_id 
  AND vll.list_id = vl.list_id
)
AND vl.list_id = 101;

If this returns a non-zero count, those calls were from leads now deleted. The log entries persist and do not cause errors, but they represent orphaned records.

Clearing agent assignments after list operations

After resetting or deactivating a large portion of a list, clear the agent assignments so agents pick up new leads instead of cached ones:

UPDATE vicidial_closer_log 
SET lead_id = 0, 
    status = 'RESET' 
WHERE list_id = 101 
AND DATE(call_date) = CURDATE() 
AND status NOT IN ('SALE', 'DISPO');

This clears today's incomplete work. Agents see a fresh list next session.

Alternatively, log agents out forcibly and clear their session:

mysql -u asterisk -p asterisk -e "DELETE FROM vicidial_live_agents WHERE list_id = 101;"

Agents must log back in. Their screen will refresh and reload leads.

Bulk operations via the ViciDial API

For large recurring resets, automate via the REST API:

curl -X POST http://your_vicidial_ip/api/vicirest.php \
  -d "function=update_lead" \
  -d "user=admin" \
  -d "pass=password" \
  -d "lead_id=1000001" \
  -d "status=NEW" \
  -d "phone_number=5551234567" \
  -d "list_id=101"

For bulk operations, use the database directly. The API is slower for large batches.

If your installation supports it, the VICIDIAL CLI at /usr/share/astguiclient/ can also trigger resets:

/usr/share/astguiclient/ADMIN_LIST_RESET.pl --list_id 101 --reset_status NEW

Check your ViciDial version and permissions before running. Some installations disable this script.

Troubleshooting

Leads reappear after deactivation

If deactivated leads are called again, the issue is usually cached agent lists or a list being re-imported. Check:

SELECT * FROM vicidial_list WHERE phone_number = '5551234567' AND list_id = 101;

If the status shows as DEAD but agents still see it, restart the agent process:

sudo systemctl restart vicidial_agent

Or clear the web browser cache. Agent screens cache list data in JavaScript.

If leads reappear in the database, someone imported a backup or ran an inadvertent INSERT. Check audit logs:

tail -100 /var/log/asterisk/messages | grep vicidial

Reset did not clear callbacks

If callbacks remain after reset, they may be in the future or in a different table. Check both places:

SELECT COUNT(*) FROM vicidial_list 
WHERE list_id = 101 
AND status = 'CALLBACK' 
AND callback_datetime IS NOT NULL;

SELECT COUNT(*) FROM vicidial_log 
WHERE list_id = 101 
AND call_date >= DATE_SUB(NOW(), INTERVAL 1 DAY) 
AND disposition = 'CALLBACK';

To clear scheduled callbacks:

UPDATE vicidial_list 
SET callback_datetime = NULL, 
    callback_localtime = NULL 
WHERE list_id = 101 
AND status = 'CALLBACK';

Then reset status:

UPDATE vicidial_list 
SET status = 'NEW' 
WHERE list_id = 101 
AND status = 'CALLBACK';

Agents report "No leads available"

This occurs after a large deactivation or reset if the list status is set to INACTIVE or if all leads are somehow marked as unavailable. Check:

SELECT list_id, active FROM vicidial_list_parameter WHERE list_id = 101;

The active field must be 'Y':

UPDATE vicidial_list_parameter 
SET active = 'Y' 
WHERE list_id = 101;

Also verify leads exist and have dialing status:

SELECT COUNT(*) FROM vicidial_list 
WHERE list_id = 101 
AND status IN ('NEW', 'CALLBACK', 'XFER', 'ACTIVE');

If it is zero, all leads are deactivated. Reset some:

UPDATE vicidial_list 
SET status = 'NEW' 
WHERE list_id = 101 
LIMIT 1000;

Duplicate dials or high hang-up rate after reset

If agents report duplicate dials on the same number or hang-ups on callbacks, the issue is often a reset that did not clear the call log entries. The system sees a lead with status NEW but a recent call entry, and some scripts treat this as "already dialed."

Check for recent calls on fresh leads:

SELECT vl.lead_id, vl.phone_number, vl.status, MAX(vll.call_date) 
FROM vicidial_list vl 
JOIN vicidial_log vll ON vl.lead_id = vll.lead_id 
WHERE vl.list_id = 101 
AND vl.status = 'NEW' 
AND vll.call_date > DATE_SUB(NOW(), INTERVAL 1 DAY) 
GROUP BY vl.lead_id 
LIMIT 10;

These are not duplicates; they are normal. The log entries are kept for compliance. The dialer should not retry the same number in the same call. If it does, the issue is in the campaign script or IVR logic, not the list reset.

If agents report actual duplicate dials within seconds, check the dialer script and campaign settings in the ViciDial admin panel.

Database locked during bulk operation

Large updates lock the table momentarily. If agents are actively dialing, they may see "database locked" errors in Asterisk logs. Minimize this by:

  1. Running operations during off-hours (lunch, overnight)
  2. Stopping the autodial process: sudo systemctl stop asterisk
  3. Staggering the operation (batch updates with LIMIT as shown earlier)
  4. Using a dedicated read replica if your setup has one

If you must operate during active hours, stagger:

UPDATE vicidial_list 
SET status = 'NEW' 
WHERE list_id = 101 
AND lead_id >= 1000000 
AND lead_id < 1001000;
-- Wait 5 seconds
-- Repeat with next 1000 lead_ids

This allows brief lock periods interspersed with normal operation.

Frequently asked questions

Can I recover leads after deletion?

Yes, only from a database backup. There is no "undelete" in MySQL. Restore the backup to a separate server, extract the lost records, and re-import them. This requires downtime or a replica database. Prevention is better than recovery: always backup before deleting, and use deactivation instead of deletion unless you are certain the data should never exist again.

What happens to call recordings when I delete a lead?

Deleting a lead from vicidial_list does not automatically delete recordings. Call recordings are stored on the filesystem (usually /var/spool/asterisk/monitor/) and indexed in asterisk_cdr.cdr and vicidial_log. The lead deletion breaks the link in the database but files remain. To delete recordings, manually remove the files or use a cleanup script. Most setups keep recordings separate from the database for this reason.

How do I reset a list but keep agent notes and custom fields?

Only reset the status and call timing fields, not the comments or custom fields. Use this query instead of the full reset: UPDATE vicidial_list SET status = 'NEW', last_call_time = NULL WHERE list_id = 101; This preserves comments and any custom fields you added. Notes in vicidial_log also remain in the call history.

Why does resetting a list not show up immediately in the agent screen?

Agent screens cache list data in the browser and in Asterisk's in-memory list cache. After a database reset, the agent may need to log out and log back in, or refresh the browser. Alternatively, restart the Asterisk process with sudo systemctl restart asterisk. The database change is immediate, but the dialer process reads it once per cycle or upon login.

Can I reset only leads assigned to a specific agent or campaign?

Yes, but the lead assignment is not stored in vicidial_list. It is in vicidial_closer_log for active work or in the agent's current session. To reset only leads an agent touched today: UPDATE vicidial_list SET status = 'NEW' WHERE lead_id IN (SELECT DISTINCT lead_id FROM vicidial_closer_log WHERE agent = 'agent_username' AND DATE(call_date) = CURDATE()) AND list_id = 101; This resets only leads that agent worked today. Other agents' work is unaffected.

Summary

ViciDial list management requires understanding the difference between deactivation, reset, and deletion. Deactivation marks leads as DEAD or moves the list to INACTIVE status, preserving all records for audit and reporting. Reset clears call history and status to NEW, returning leads to the active pool for re-dialing. Deletion removes records entirely and should be used only for test data or documented errors.

Key operations performed in this tutorial:

Before running any bulk update, always back up the vicidial_list and vicidial_log tables. Verify counts with SELECT before DELETE or UPDATE. Run operations during off-hours if possible.

After completing list operations, check agent screens for updated lead counts, restart agents if they report stale data, and verify call logs for orphaned records. Audit logs in /var/log/asterisk/messages show dialer activity if problems arise.

Stuck on something specific?

Book a free 30-minute call. I run ViciDial centers across 3 countries and can usually unblock your setup in one session — or build it for you.

Book a Free Consultation