← All Tutorials

How to Upload a Lead List to ViciDial — CSV Format & Mapping

ViciDial Administration Intermediate 16 min read #89

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:

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:

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:

Strongly recommended:

Optional but useful:

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:

  1. No header row – ViciDial list upload expects data rows only (headers are optional in UI but not recommended)
  2. Consistent field count – Every row must have the same number of columns
  3. Proper encoding – UTF-8 without BOM
  4. Phone number format – 10+ digits, no spaces/dashes in raw CSV (formatting applied on import)
  5. No embedded newlines – Use proper CSV escaping if fields contain commas
  6. 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

  1. Log into ViciDial Admin Interface:

    https://your-vicidial-server/vicidial/admin.php
    
  2. Navigate to List Management:

    • Click CampaignsLists (or Leads in newer versions)
    • Select the target campaign from the dropdown
  3. 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
  4. 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:

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:

  1. Prepare your CSV with proper encoding (UTF-8), consistent field counts, and valid phone numbers
  2. Map fields correctly, ensuring phone_number is primary and vendor_lead_code is set for duplicate detection
  3. Set timezones (gmt_offset_now) for TCPA compliance and proper calling windows
  4. Choose your upload method — web UI for small lists, CLI for production/large-scale imports
  5. Validate after import using database queries to ensure data integrity
  6. Implement safeguards with backups, deduplication, and audit logging for production reliability

For optimal results in production environments:

With these practices, you can reliably and efficiently manage lead lists at any scale in ViciDial production environments.

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