Master the complete process of importing lead lists into ViciDial with proper CSV formatting, field mapping, and validation techniques to avoid common import failures in production environments.
Prerequisites
Before uploading a lead list to ViciDial, ensure you have the following:
- ViciDial installation (tested on 2.14.x and later)
- Admin access to the web interface (/vicidial/admin.php)
- Database credentials for the asterisk database
- Sufficient disk space in /var/spool/vicidial/LEADS_IN/ (typically 5GB+ for large lists)
- Linux command-line access to the ViciDial server
- Campaign already created in ViciDial (required before list assignment)
- MySQL/MariaDB client installed on your local machine (if importing via SSH tunnel)
- Basic understanding of CSV format and field delimiters
Understanding ViciDial Lead List Structure
Core Lead Tables
ViciDial stores lead data primarily in two tables:
-- Main lead table
SHOW CREATE TABLE vicidial_list\G
-- This shows the structure containing:
-- lead_id (primary key, auto-increment)
-- phone_number (VARCHAR 20)
-- first_name, last_name, address, city, state, postal_code
-- email, vendor_lead_code, source_id
-- list_id (foreign key to campaign list)
-- status (NEW, ACTIVE, etc.)
-- gmt_offset_now (for timezone handling)
The most critical fields for import are:
- phone_number – Required; primary dialing field
- list_id – Links lead to campaign
- first_name, last_name – Optional but recommended for agent context
- email – Optional but valuable for callback/document delivery
- vendor_lead_code – Unique external identifier; prevents duplicates
- source_id – Tracks lead source for compliance/analytics
- gmt_offset_now – Critical for timezone-aware calling windows
List Management in ViciDial
Campaigns in ViciDial are containers with associated lists. Each campaign can have multiple lists, and each list contains leads.
-- View existing campaigns
SELECT campaign_id, campaign_name, active, dial_method
FROM vicidial_campaigns
LIMIT 10;
-- View lists under a campaign
SELECT list_id, campaign_id, list_name, lead_count
FROM vicidial_lists
WHERE campaign_id = 'TEST_CAMPAIGN';
Preparing Your CSV File
CSV Format Specifications
ViciDial expects a specific CSV structure with proper field ordering and encoding.
phone_number,first_name,last_name,email,vendor_lead_code,source_id,gmt_offset_now
5551234567,John,Doe,[email protected],VND-123456,WEB,America/New_York
5559876543,Jane,Smith,[email protected],VND-123457,PHONE,America/Chicago
5559998888,Bob,Johnson,[email protected],VND-123458,REFERRAL,America/Los_Angeles
Required vs. Optional Fields
Required fields:
phone_number– E.164 or 10-digit format (ViciDial accepts both)
Strongly recommended:
first_name– Improves agent interaction qualityvendor_lead_code– Prevents duplicate importsgmt_offset_now– Essential for respecting TCPA calling windows
Optional but useful:
last_name,email,address,city,state,postal_codesource_id– Track which source generated the lead- Custom fields (if your ViciDial instance uses extended schema)
CSV Field Mapping Reference
Here's the complete list of importable fields and their SQL column equivalents:
CSV Field Name | SQL Table Column | Data Type | Max Length
phone_number | phone_number | VARCHAR(20) | 20
first_name | first_name | VARCHAR(50) | 50
last_name | last_name | VARCHAR(50) | 50
middle_initial | middle_initial | VARCHAR(1) | 1
address | address | VARCHAR(100) | 100
city | city | VARCHAR(50) | 50
state | state | VARCHAR(2) | 2
postal_code | postal_code | VARCHAR(10) | 10
country_code | country_code | VARCHAR(3) | 3
email | email | VARCHAR(100) | 100
vendor_lead_code | vendor_lead_code | VARCHAR(20) | 20
source_id | source_id | VARCHAR(50) | 50
gmt_offset_now | gmt_offset_now | VARCHAR(10) | 10
phone_code | phone_code | VARCHAR(20) | 20
lead_source_id | lead_source_id | VARCHAR(20) | 20
CSV Validation Rules
Before uploading, validate your CSV meets these requirements:
- No header row – ViciDial list upload expects data rows only (headers are optional in UI but not recommended)
- Consistent field count – Every row must have the same number of columns
- Proper encoding – UTF-8 without BOM
- Phone number format – 10+ digits, no spaces/dashes in raw CSV (formatting applied on import)
- No embedded newlines – Use proper CSV escaping if fields contain commas
- File size limits – Practical limit 50MB per file; split larger lists
Creating a Validation Script
#!/bin/bash
# validate_csv.sh - Pre-import CSV validation
CSV_FILE="$1"
if [ ! -f "$CSV_FILE" ]; then
echo "ERROR: File not found: $CSV_FILE"
exit 1
fi
# Check file encoding
FILE_ENCODING=$(file -b --mime-encoding "$CSV_FILE")
if [ "$FILE_ENCODING" != "utf-8" ]; then
echo "WARNING: File encoding is $FILE_ENCODING, expected utf-8"
fi
# Count lines
LINE_COUNT=$(wc -l < "$CSV_FILE")
echo "Total lines: $LINE_COUNT"
# Check for consistent field count (assuming comma-delimited)
FIRST_LINE_FIELDS=$(head -1 "$CSV_FILE" | awk -F',' '{print NF}')
echo "Expected fields per row: $FIRST_LINE_FIELDS"
# Validate all rows have same field count
INVALID_ROWS=$(awk -F',' -v expected=$FIRST_LINE_FIELDS '{
if (NF != expected) print NR": expected "$FIRST_LINE_FIELDS", got "NF
}' "$CSV_FILE")
if [ -n "$INVALID_ROWS" ]; then
echo "ERROR: Found rows with inconsistent field counts:"
echo "$INVALID_ROWS"
exit 1
fi
# Extract and validate phone numbers (column 1)
INVALID_PHONES=$(awk -F',' '{
gsub(/[^0-9]/, "", $1)
if (length($1) < 10) print NR": invalid phone "$1
}' "$CSV_FILE")
if [ -n "$INVALID_PHONES" ]; then
echo "WARNING: Found potentially invalid phone numbers:"
echo "$INVALID_PHONES" | head -20
fi
echo "Validation complete!"
Usage:
chmod +x validate_csv.sh
./validate_csv.sh leads.csv
Uploading via Web Interface
Step-by-Step Web Upload
Log into ViciDial Admin Interface:
https://your-vicidial-server/vicidial/admin.phpNavigate to List Management:
- Click Campaigns → Lists (or Leads in newer versions)
- Select the target campaign from the dropdown
Create New List (if needed):
- Click Create List button
- Enter list name (e.g., "Q4_2024_Leads")
- Set list priority (higher = called first)
- Click Add List
Upload Leads to List:
- Select the list from the dropdown
- Click Upload Leads button
- Choose CSV file from local machine
- Important: Configure field mapping (see next section)
Field Mapping Configuration
When you upload a CSV, ViciDial prompts you to map columns to database fields.
ViciDial Upload Field Mapping Dialog:
CSV Column 1 → phone_number (REQUIRED)
CSV Column 2 → first_name
CSV Column 3 → last_name
CSV Column 4 → email
CSV Column 5 → vendor_lead_code
CSV Column 6 → source_id
CSV Column 7 → gmt_offset_now
[Checkbox] Skip first row as header
[Checkbox] Replace existing leads
[Checkbox] Auto-detect duplicates by phone_number
[UPLOAD LEADS]
Critical mapping tips:
- Leave unused columns unmapped (set to "— ignore —")
- Ensure phone_number is always mapped to Column 1
- If your CSV has a header row, check "Skip first row as header"
- Leave "Replace existing leads" unchecked unless you're refreshing the entire list
Command-Line Upload Method
For production environments and large-scale imports, use the CLI approach which is faster and more scriptable.
Using the ViciDial Import Script
ViciDial includes a Perl script for direct database imports:
# Location of import script
/usr/share/astguiclient/VICIDIAL_add_lead_list.pl
# Basic syntax
perl /usr/share/astguiclient/VICIDIAL_add_lead_list.pl \
--listname "Q4_2024_Leads" \
--campaign "TEST_CAMPAIGN" \
--file "leads.csv" \
--phonefield 1 \
--firstnamefield 2 \
--lastnamefield 3 \
--emailfield 4 \
--vendorfield 5 \
--sourcefield 6 \
--tzfield 7
Complete CLI Import Example
#!/bin/bash
# import_leads.sh - Production lead import script
CAMPAIGN="TEST_CAMPAIGN"
LIST_NAME="$(date +%Y%m%d)_import"
CSV_FILE="leads.csv"
DB_HOST="localhost"
DB_USER="cron"
DB_PASS="1234"
DB_NAME="asterisk"
# Validate file
if [ ! -f "$CSV_FILE" ]; then
echo "ERROR: CSV file not found: $CSV_FILE"
exit 1
fi
# Count leads
LEAD_COUNT=$(wc -l < "$CSV_FILE")
echo "Importing $LEAD_COUNT leads to campaign: $CAMPAIGN"
# Run import
perl /usr/share/astguiclient/VICIDIAL_add_lead_list.pl \
--listname "$LIST_NAME" \
--campaign "$CAMPAIGN" \
--file "$CSV_FILE" \
--phonefield 1 \
--firstnamefield 2 \
--lastnamefield 3 \
--emailfield 4 \
--vendorfield 5 \
--sourcefield 6 \
--tzfield 7 \
--dbhost "$DB_HOST" \
--dbuser "$DB_USER" \
--dbpass "$DB_PASS" \
--dbname "$DB_NAME" \
--active "Y" \
--skipdup "Y" \
2>&1 | tee import_$(date +%s).log
echo "Import complete. Check log for details."
Direct MySQL Import
For advanced users, direct SQL insertion can be faster for very large lists (10M+ leads):
#!/bin/bash
# direct_sql_import.sh - Ultra-high-volume import
CSV_FILE="$1"
CAMPAIGN_ID="TEST_CAMPAIGN"
LIST_ID="9001"
# Create staging table
mysql -h localhost -u cron -p1234 asterisk << 'EOF'
CREATE TEMPORARY TABLE vicidial_list_staging LIKE vicidial_list;
EOF
# Load CSV into staging table
mysql -h localhost -u cron -p1234 asterisk << EOF
LOAD DATA LOCAL INFILE '$CSV_FILE'
INTO TABLE vicidial_list_staging
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
(phone_number, first_name, last_name, email, vendor_lead_code, source_id, gmt_offset_now);
EOF
# Insert from staging to production, skipping duplicates
mysql -h localhost -u cron -p1234 asterisk << EOF
INSERT INTO vicidial_list
(phone_number, first_name, last_name, email, vendor_lead_code,
source_id, gmt_offset_now, list_id, campaign_id, status, entry_date)
SELECT
phone_number, first_name, last_name, email, vendor_lead_code,
source_id, gmt_offset_now, $LIST_ID, '$CAMPAIGN_ID', 'NEW', NOW()
FROM vicidial_list_staging
WHERE phone_number NOT IN (
SELECT phone_number FROM vicidial_list WHERE list_id = $LIST_ID
)
AND phone_number IS NOT NULL
AND LENGTH(REPLACE(phone_number, REGEXP_SUBSTR(phone_number, '[^0-9]'), '')) >= 10;
-- Update lead count
UPDATE vicidial_lists
SET lead_count = (SELECT COUNT(*) FROM vicidial_list WHERE list_id = $LIST_ID)
WHERE list_id = $LIST_ID;
EOF
echo "Import complete."
Handling Timezones (Critical for TCPA Compliance)
ViciDial respects Do Not Call (DNC) regulations and time-of-day restrictions based on the gmt_offset_now field.
Timezone Values Reference
phone_number,first_name,last_name,gmt_offset_now
5551234567,John,Doe,America/New_York
5559876543,Jane,Smith,America/Chicago
5559998888,Bob,Johnson,America/Denver
5551112222,Alice,Brown,America/Los_Angeles
5551113333,Charlie,Davis,America/Anchorage
5551114444,Diana,Evans,Pacific/Honolulu
Extracting Timezone from Phone Area Code
#!/bin/bash
# area_code_timezone.sh - Auto-detect timezone from area code
# Create mapping file
cat > area_code_tz.txt << 'EOF'
201|America/New_York
202|America/New_York
203|America/New_York
212|America/New_York
# ... (continue for all area codes)
213|America/Los_Angeles
415|America/Los_Angeles
619|America/Los_Angeles
702|America/Los_Angeles
EOF
# Process CSV with timezone detection
awk -F',' '{
area_code = substr($1, 1, 3)
cmd = "grep \"^" area_code "|\" area_code_tz.txt | cut -d\"|\" -f2"
cmd | getline timezone
close(cmd)
if (timezone == "") timezone = "America/Chicago" # default
print $0 "," timezone
}' input_leads.csv > leads_with_tz.csv
Duplicate Handling and Lead Deduplication
Preventing Duplicate Imports
ViciDial's vendor_lead_code field is your primary defense against duplicates:
# Before importing, deduplicate by vendor_lead_code
sort -t',' -k5 -u leads.csv > leads_dedup.csv
# Or using awk
awk -F',' '!seen[$5]++' leads.csv > leads_dedup.csv
Checking for Existing Leads
-- Find leads already in the system by vendor_lead_code
SELECT list_id, phone_number, vendor_lead_code, status
FROM vicidial_list
WHERE vendor_lead_code IN (
SELECT vendor_lead_code FROM new_import_list
)
LIMIT 100;
-- Find potential phone duplicates
SELECT phone_number, COUNT(*) as count
FROM vicidial_list
WHERE list_id = 9001
GROUP BY phone_number
HAVING COUNT(*) > 1;
Automated Deduplication Script
#!/bin/bash
# deduplicate_leads.sh
INPUT_CSV="$1"
OUTPUT_CSV="${INPUT_CSV%.csv}_dedup.csv"
# Extract headers (if present)
HEADERS=$(head -1 "$INPUT_CSV")
# Remove duplicates, preserve first occurrence
(echo "$HEADERS"; tail -n +2 "$INPUT_CSV" | sort -t',' -k5 -u) > "$OUTPUT_CSV"
ORIGINAL_COUNT=$(tail -n +2 "$INPUT_CSV" | wc -l)
DEDUP_COUNT=$(tail -n +2 "$OUTPUT_CSV" | wc -l)
REMOVED=$((ORIGINAL_COUNT - DEDUP_COUNT))
echo "Original leads: $ORIGINAL_COUNT"
echo "After dedup: $DEDUP_COUNT"
echo "Removed duplicates: $REMOVED"
echo "Output: $OUTPUT_CSV"
Monitoring Upload Progress
Checking Upload Status via Database
-- Monitor ongoing import
SELECT
list_id,
campaign_id,
lead_count,
last_update_date
FROM vicidial_lists
WHERE list_id IN (SELECT MAX(list_id) FROM vicidial_lists LIMIT 5)
ORDER BY list_id DESC;
-- Check lead distribution
SELECT status, COUNT(*) as count
FROM vicidial_list
WHERE list_id = 9001
GROUP BY status;
-- Check for import errors
SELECT COUNT(*)
FROM vicidial_list
WHERE phone_number IS NULL OR phone_number = '';
Real-Time Import Monitoring
#!/bin/bash
# monitor_import.sh - Watch import progress
LIST_ID="9001"
DB_USER="cron"
DB_PASS="1234"
DB_NAME="asterisk"
while true; do
CURRENT=$(mysql -h localhost -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" \
-sN -e "SELECT COUNT(*) FROM vicidial_list WHERE list_id = $LIST_ID;")
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$TIMESTAMP] Leads in list: $CURRENT"
sleep 10
done
Troubleshooting Common Import Issues
Issue: "File Not Found" or Permission Denied
Cause: CSV file not in expected directory or incorrect permissions
Solution:
# Ensure file is readable
chmod 644 leads.csv
# Copy to ViciDial's standard upload directory
cp leads.csv /var/spool/vicidial/LEADS_IN/
# Verify permissions
ls -la /var/spool/vicidial/LEADS_IN/ | grep leads.csv
Issue: "Invalid Phone Number Format"
Cause: Phone numbers contain non-numeric characters or are too short
Solution:
#!/bin/bash
# clean_phones.sh
sed 's/[^0-9,\n]//g' leads.csv > leads_clean.csv
# Verify minimum 10 digits
awk -F',' '{
gsub(/[^0-9]/, "", $1)
if (length($1) >= 10) print $0
}' leads_clean.csv > leads_valid.csv
Issue: "Field Mapping Mismatch" or Blank Imports
Cause: Incorrect field mapping or CSV column order mismatch
Solution:
Verify your CSV columns match your mapping:
# Show first row with column numbers
head -1 leads.csv | awk -F',' '{for(i=1;i<=NF;i++) print i": "$i}'
# Expected output should match your mapping:
# 1: phone_number
# 2: first_name
# 3: last_name
# etc.
Issue: Duplicate Leads Being Imported
Cause: vendor_lead_code not set or duplicate checking disabled
Solution:
# Check if vendor_lead_code is unique
mysql -u cron -p1234 asterisk -e \
"SELECT vendor_lead_code, COUNT(*) FROM vicidial_list
WHERE list_id = 9001 AND vendor_lead_code IS NOT NULL
GROUP BY vendor_lead_code HAVING COUNT(*) > 1 LIMIT 20;"
# Enable duplicate checking in future imports via web UI:
# Check: [X] Auto-detect duplicates by phone_number
# Or use CLI: --skipdup "Y"
Issue: Out of Memory During Large Import
Cause: Importing massive lists (>50M leads) with insufficient RAM
Solution:
#!/bin/bash
# batch_import.sh - Split large files into chunks
CSV_FILE="$1"
CHUNK_SIZE=100000
CAMPAIGN="TEST_CAMPAIGN"
TOTAL_LINES=$(wc -l < "$CSV_FILE")
CHUNKS=$((($TOTAL_LINES / $CHUNK_SIZE) + 1))
echo "Splitting $TOTAL_LINES lines into $CHUNKS chunks of $CHUNK_SIZE..."
for i in $(seq 1 $CHUNKS); do
START=$(( ($i - 1) * $CHUNK_SIZE + 1 ))
END=$(( $i * $CHUNK_SIZE ))
CHUNK_FILE="chunk_${i}.csv"
sed -n "${START},${END}p" "$CSV_FILE" > "$CHUNK_FILE"
echo "Importing chunk $i: $CHUNK_FILE"
perl /usr/share/astguiclient/VICIDIAL_add_lead_list.pl \
--listname "${CAMPAIGN}_$(date +%s)_chunk_$i" \
--campaign "$CAMPAIGN" \
--file "$CHUNK_FILE" \
--phonefield 1 \
--firstnamefield 2 \
--lastnamefield 3 \
--dbhost localhost \
--dbuser cron \
--dbpass 1234 \
--dbname asterisk \
--active "Y" 2>&1 | tee "import_chunk_${i}.log"
rm "$CHUNK_FILE"
sleep 5 # Prevent database strain
done
echo "All chunks imported."
Issue: Leads Show "NEW" Status But Don't Dial
Cause: Campaign not active or dialers not running
Solution:
# Verify campaign is active
mysql -u cron -p1234 asterisk -e \
"SELECT campaign_id, campaign_name, active FROM vicidial_campaigns
WHERE campaign_id = 'TEST_CAMPAIGN';"
# Check if dialers are running
ps aux | grep -E "vicidial_dial|[p]erl.*dial"
# Start ViciDial daemons if stopped
systemctl restart vicidial
# Check for dialer errors in logs
tail -50 /var/log/asterisk/messages | grep -i dial
Issue: Slow Import Speed
Cause: Single-threaded import, high disk I/O, or database lock contention
Solution:
# Check database performance
mysql -u cron -p1234 asterisk -e "SHOW PROCESSLIST;" | grep -i vicidial
# Optimize table before import
mysql -u cron -p1234 asterisk -e "OPTIMIZE TABLE vicidial_list;"
# Increase insert buffer during import
mysql -u cron -p1234 asterisk << EOF
SET SESSION insert_delayed_insert_limit=100000;
SET SESSION bulk_insert_buffer_size=16000000;
EOF
# Use parallel import with multiple chunks
# (See batch_import.sh above)
Database Verification After Import
Post-Import Validation Queries
-- Count total leads imported
SELECT COUNT(*) as total_leads
FROM vicidial_list
WHERE list_id = 9001;
-- Verify required fields populated
SELECT
COUNT(*) as total,
SUM(CASE WHEN phone_number IS NULL THEN 1 ELSE 0 END) as missing_phone,
SUM(CASE WHEN first_name IS NULL THEN 1 ELSE 0 END) as missing_first,
SUM(CASE WHEN vendor_lead_code IS NULL THEN 1 ELSE 0 END) as missing_vendor_code
FROM vicidial_list
WHERE list_id = 9001;
-- Check status distribution
SELECT status, COUNT(*) as count
FROM vicidial_list
WHERE list_id = 9001
GROUP BY status
ORDER BY count DESC;
-- Verify timezone distribution
SELECT gmt_offset_now, COUNT(*) as count
FROM vicidial_list
WHERE list_id = 9001
GROUP BY gmt_offset_now
ORDER BY count DESC;
-- Find any malformed phone numbers
SELECT phone_number, COUNT(*)
FROM vicidial_list
WHERE list_id = 9001
AND (LENGTH(REPLACE(phone_number, REGEXP_SUBSTR(phone_number, '[^0-9]'), '')) < 10
OR phone_number IS NULL)
GROUP BY phone_number;
-- Verify list_id assignment
SELECT campaign_id, list_id, lead_count
FROM vicidial_lists
WHERE list_id = 9001;
Production Best Practices
Pre-Import Checklist
#!/bin/bash
# pre_import_checklist.sh
echo "=== ViciDial Pre-Import Checklist ==="
# 1. Backup database
echo "[ ] Backup database"
mysqldump -u cron -p1234 asterisk > backup_$(date +%s).sql
# 2. Validate CSV
echo "[ ] Validate CSV format and encoding"
file -b --mime-encoding "$1"
head -5 "$1"
# 3. Check campaign exists
echo "[ ] Verify campaign exists"
mysql -u cron -p1234 asterisk -sN -e \
"SELECT campaign_id FROM vicidial_campaigns WHERE campaign_id = 'TEST_CAMPAIGN';"
# 4. Check disk space
echo "[ ] Check available disk space"
df -h /var/spool/vicidial/
# 5. Check database connection
echo "[ ] Test database connection"
mysql -u cron -p1234 asterisk -e "SELECT COUNT(*) FROM vicidial_list LIMIT 1;"
# 6. Verify daemons running
echo "[ ] Verify ViciDial daemons running"
ps aux | grep -E "vicidial_dial|vicidial_agent" | grep -v grep
echo "=== Checklist Complete ==="
Backup Strategy
#!/bin/bash
# backup_before_import.sh
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/vicidial"
mkdir -p "$BACKUP_DIR"
echo "Creating database backup: $BACKUP_DIR/asterisk_$TIMESTAMP.sql.gz"
mysqldump -u cron -p1234 --single-transaction --quick asterisk | \
gzip > "$BACKUP_DIR/asterisk_$TIMESTAMP.sql.gz"
# Verify backup
gunzip -t "$BACKUP_DIR/asterisk_$TIMESTAMP.sql.gz"
if [ $? -eq 0 ]; then
echo "Backup verified successfully"
else
echo "ERROR: Backup verification failed!"
exit 1
fi
# Keep only last 10 backups
ls -t "$BACKUP_DIR"/asterisk_*.sql.gz | tail -n +11 | xargs rm -f
Logging and Audit Trail
#!/bin/bash
# import_with_audit.sh
IMPORT_LOG="/var/log/vicidial/lead_imports.log"
CSV_FILE="$1"
CAMPAIGN="TEST_CAMPAIGN"
# Log import start
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting import: $CSV_FILE" >> "$IMPORT_LOG"
# Get file metadata
FILE_SIZE=$(du -h "$CSV_FILE" | cut -f1)
FILE_HASH=$(md5sum "$CSV_FILE" | awk '{print $1}')
LEAD_COUNT=$(wc -l < "$CSV_FILE")
echo "[$(date '+%Y-%m-%d %H:%M:%S')] File: $CSV_FILE | Size: $FILE_SIZE | Leads: $LEAD_COUNT | MD5: $FILE_HASH" >> "$IMPORT_LOG"
# Run import with error capturing
perl /usr/share/astguiclient/VICIDIAL_add_lead_list.pl \
--listname "${CAMPAIGN}_$(date +%s)" \
--campaign "$CAMPAIGN" \
--file "$CSV_FILE" \
--phonefield 1 \
--firstnamefield 2 \
--lastnamefield 3 \
--emailfield 4 \
--vendorfield 5 \
--sourcefield 6 \
--tzfield 7 \
--dbhost localhost \
--dbuser cron \
--dbpass 1234 \
--dbname asterisk \
--active "Y" 2>&1 | tee -a "$IMPORT_LOG"
# Log completion
FINAL_COUNT=$(mysql -u cron -p1234 asterisk -sN -e \
"SELECT COUNT(*) FROM vicidial_list WHERE list_id = (SELECT MAX(list_id) FROM vicidial_lists);")
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Import complete. Final lead count: $FINAL_COUNT" >> "$IMPORT_LOG"
Summary
Uploading lead lists to ViciDial requires careful attention to CSV formatting, field mapping, and validation. The key steps are:
- Prepare your CSV with proper encoding (UTF-8), consistent field counts, and valid phone numbers
- Map fields correctly, ensuring phone_number is primary and vendor_lead_code is set for duplicate detection
- Set timezones (gmt_offset_now) for TCPA compliance and proper calling windows
- Choose your upload method — web UI for small lists, CLI for production/large-scale imports
- Validate after import using database queries to ensure data integrity
- Implement safeguards with backups, deduplication, and audit logging for production reliability
For optimal results in production environments:
- Always deduplicate leads before import using
vendor_lead_code - Split very large lists (>50M leads) into chunks to avoid memory issues
- Test imports with a small sample first before running full campaigns
- Monitor upload progress with real-time database queries
- Keep comprehensive logs and backups for compliance and troubleshooting
- Use the CLI/Perl scripts for scriptable, repeatable imports rather than relying on the web UI
With these practices, you can reliably and efficiently manage lead lists at any scale in ViciDial production environments.