Overview
Batch calls allow you to:- Upload lists of phone numbers
- Process hundreds of calls automatically
- Monitor progress in real-time
- Get detailed reports
- Handle errors gracefully
Creating a Batch
Upload via API
Copy
curl -X POST http://localhost:8010/api/batch-calls \
-H "Authorization: Bearer YOUR_TOKEN" \
-F "file=@calls.csv" \
-F "agent_id=agent-123" \
-F "campaign_id=camp-456"
CSV Format
Copy
phone,name,email,customer_id,custom_field
+1234567890,John Doe,john@example.com,cust-123,value1
+1234567891,Jane Smith,jane@example.com,cust-124,value2
+1234567892,Bob Wilson,bob@example.com,cust-125,value3
JSON Format
Copy
[
{
"phone": "+1234567890",
"name": "John Doe",
"email": "john@example.com",
"customer_id": "cust-123",
"custom_data": {
"order_id": "ORD-456",
"amount": 99.99
}
},
{
"phone": "+1234567891",
"name": "Jane Smith",
"email": "jane@example.com",
"customer_id": "cust-124",
"custom_data": {
"order_id": "ORD-457",
"amount": 149.99
}
}
]
Batch Configuration
Python Example
Copy
from Service.BatchCallService import BatchCallService
from models.models import BatchCallRequest
service = BatchCallService()
batch_request = BatchCallRequest(
agent_id="agent-123",
file_url="s3://bucket/calls.csv", # or local file path
campaign_name="Q1 Sales Outreach",
concurrency=5, # Max parallel calls
retry_failed=True,
column_mapping={
"phone": "phone_number",
"name": "customer_name",
"email": "customer_email"
},
metadata={
"campaign_id": "camp-456",
"priority": "normal"
}
)
batch = await service.create_batch(batch_request)
print(f"Batch created: {batch.id}")
Monitoring Progress
Real-time Status
Copy
# Get batch status
curl -X GET http://localhost:8010/api/batch-calls/{batch_id} \
-H "Authorization: Bearer YOUR_TOKEN"
Copy
{
"batch_id": "batch-789",
"status": "in_progress",
"total_calls": 1000,
"completed": 450,
"failed": 12,
"pending": 538,
"progress_percent": 45,
"estimated_completion": "2024-01-15T15:30:00Z",
"start_time": "2024-01-15T14:00:00Z",
"errors": [
{
"row": 5,
"phone": "+1234567895",
"error": "Invalid phone number",
"retry_count": 1
}
]
}
WebSocket Updates
Copy
// Real-time batch progress
const ws = new WebSocket('ws://localhost:8010/ws/batch/{batch_id}');
ws.addEventListener('message', (event) => {
const update = JSON.parse(event.data);
console.log(`Progress: ${update.completed}/${update.total}`);
console.log(`Status: ${update.status}`);
});
Batch Processing Flow
Copy
1. Upload File
↓
2. Validate Data
↓
3. Parse CSV/JSON
↓
4. Check Phone Numbers
↓
5. Create Call Records
↓
6. Queue Calls
↓
7. Execute (with concurrency limit)
↓
8. Handle Errors & Retries
↓
9. Generate Report
Advanced Configuration
Scheduling Batch Execution
Copy
batch_request = BatchCallRequest(
agent_id="agent-123",
file_url="s3://bucket/calls.csv",
scheduled_start_time="2024-01-20 09:00:00",
scheduled_timezone="America/New_York",
concurrent_calls=10,
)
batch = await service.schedule_batch(batch_request)
Custom Timing
Copy
batch_request = BatchCallRequest(
agent_id="agent-123",
file_url="s3://bucket/calls.csv",
call_timing={
"business_hours_only": True,
"start_hour": 9,
"end_hour": 17,
"timezone": "America/New_York",
"skip_weekends": True,
"delay_between_calls": 5 # seconds
}
)
Retry Logic
Copy
batch_request = BatchCallRequest(
agent_id="agent-123",
file_url="s3://bucket/calls.csv",
retry_policy={
"max_retries": 3,
"retry_delay": 300, # 5 minutes
"exponential_backoff": True,
"retry_on": ["busy", "no_answer", "timeout"]
}
)
Error Handling
Invalid Phone Numbers
Copy
# Enable validation
batch_request = BatchCallRequest(
agent_id="agent-123",
file_url="s3://bucket/calls.csv",
validate_phone_numbers=True,
invalid_phone_handling="skip" # or "use_as_is"
)
Data Validation
Copy
# Validate data before processing
async def validate_batch_data(file_path: str):
issues = []
with open(file_path) as f:
reader = csv.DictReader(f)
for idx, row in enumerate(reader, start=1):
if not row.get('phone'):
issues.append(f"Row {idx}: Missing phone number")
if not validate_phone_number(row['phone']):
issues.append(f"Row {idx}: Invalid phone format")
if len(issues) > 10: # Stop after 10 errors
break
return issues
Results and Reporting
Get Batch Results
Copy
# Download results
curl -X GET http://localhost:8010/api/batch-calls/{batch_id}/results \
-H "Authorization: Bearer YOUR_TOKEN" \
-o results.csv
Results CSV Format
Copy
phone,name,status,call_id,duration_seconds,recording_url,transcript,error_message
+1234567890,John Doe,completed,call-1,180,https://...,Agent: Hello...,
+1234567891,Jane Smith,failed,call-2,,https://...,,(busy signal)
+1234567892,Bob Wilson,in_progress,call-3,45,,,...
Generate Report
Copy
report = await service.generate_report(batch_id)
print(f"Total Calls: {report.total}")
print(f"Completed: {report.completed}")
print(f"Failed: {report.failed}")
print(f"Success Rate: {report.success_rate * 100:.1f}%")
print(f"Average Duration: {report.avg_duration}s")
print(f"Average Cost: ${report.total_cost:.2f}")
Report Export
Copy
# Export as PDF
curl -X GET http://localhost:8010/api/batch-calls/{batch_id}/report.pdf \
-H "Authorization: Bearer YOUR_TOKEN" \
-o report.pdf
# Export as JSON
curl -X GET http://localhost:8010/api/batch-calls/{batch_id}/report.json \
-H "Authorization: Bearer YOUR_TOKEN" \
-o report.json
Stopping a Batch
Pause Batch
Copy
curl -X POST http://localhost:8010/api/batch-calls/{batch_id}/pause \
-H "Authorization: Bearer YOUR_TOKEN"
Resume Batch
Copy
curl -X POST http://localhost:8010/api/batch-calls/{batch_id}/resume \
-H "Authorization: Bearer YOUR_TOKEN"
Cancel Batch
Copy
curl -X POST http://localhost:8010/api/batch-calls/{batch_id}/cancel \
-H "Authorization: Bearer YOUR_TOKEN"
Cost Optimization
Batch Pricing Calculation
Copy
batch_report = await service.get_batch_report(batch_id)
cost_breakdown = {
"outbound_calls": batch_report.completed_calls * 0.05,
"call_duration": batch_report.total_minutes * 0.01,
"transcription": batch_report.transcribed_minutes * 0.01,
"storage": batch_report.recording_size_gb * 0.023,
}
total_cost = sum(cost_breakdown.values())
print(f"Total Batch Cost: ${total_cost:.2f}")
Cost-saving Tips
- Concurrency: Batch calls don’t overlap, so you pay sequentially
- Disable Recording: Skip recording for analytics-only calls
- Disable Transcription: For calls without transcript needs
- Off-peak Hours: Schedule batches during off-peak times
Performance
Optimal Settings
Copy
# For 10,000 calls
batch_request = BatchCallRequest(
agent_id="agent-123",
file_url="s3://bucket/calls.csv",
concurrency=15, # Parallel calls
timeout_per_call=300, # 5 minutes
batch_size=100, # Process in chunks
)
Monitoring Performance
Copy
# Check system status
curl -X GET http://localhost:8010/api/system/status \
-H "Authorization: Bearer YOUR_TOKEN"
Copy
{
"active_batches": 2,
"active_calls": 8,
"queue_size": 150,
"cpu_usage": 45,
"memory_usage": 62,
"disk_usage": 28
}
Examples
Sales Outreach Campaign
Copy
batch = await service.create_batch({
"agent_id": "sales-agent-123",
"file_url": "s3://leads/q1-leads.csv",
"campaign_name": "Q1 Sales Push",
"concurrent_calls": 10,
"schedule": {
"start_time": "2024-01-15 09:00:00",
"end_time": "2024-01-15 17:00:00",
"timezone": "America/New_York"
}
})
Customer Survey Campaign
Copy
batch = await service.create_batch({
"agent_id": "survey-agent-456",
"file_url": "s3://surveys/customer-list.csv",
"campaign_name": "Customer Satisfaction Survey",
"record_call": True,
"transcribe_call": True,
"max_retries": 2,
})
Appointment Reminders
Copy
batch = await service.create_batch({
"agent_id": "reminder-agent-789",
"file_url": "s3://reminders/upcoming-appointments.json",
"campaign_name": "Appointment Reminders",
"schedule": {
"time": "24_hours_before",
"timezone": "America/Los_Angeles"
}
})
Next Steps
Scheduler
Schedule individual calls for later execution.