Millis AI Integration
The MillisAIAutoCaller class implements the IAICaller interface to provide integration with the Millis AI service for automated outbound calls. This integration handles API communication, call initiation, status polling, and recording retrieval with comprehensive error handling and rate limiting.
Overview
Millis AI is an external AI service that handles the actual voice calling and conversation execution. The MillisAIAutoCaller acts as an adapter that translates the MMS platform's lead and script data into Millis AI's API format and manages the lifecycle of calls through the Millis platform.
API Integration
Call Initiation
The InitiateCall method sends a POST request to the Millis AI /call/initiate endpoint with the following request structure:
{
"phone_number": "+1234567890",
"lead_name": "John Doe",
"script": "Hello, this is an automated call...",
"agent_id": "agent_123",
"api_key": "sk_millis_abc123xyz",
"webhook_url": "https://mms.platform.com/callbacks/millis",
"metadata": {
"lead_id": "5678",
"campaign_id": "campaign_910"
}
}Request Parameters:
phone_number: E.164 formatted phone number of the leadlead_name: Name of the lead for personalization in the AI conversationscript: Call script or prompt that guides the AI agent behavioragent_id: Identifier of the AI agent configuration in Millisapi_key: Authentication token for Millis AI APIwebhook_url: Callback URL for status updates when call completesmetadata: Additional context passed through to webhook
Response Handling
Successful response from Millis AI:
{
"success": true,
"call_id": "call_millis_abc123def456",
"status": "initiated",
"timestamp": "2026-03-21T14:30:45Z"
}Response Fields:
call_id: Unique identifier for the initiated call, used for status pollingstatus: Initial status is always "initiated"timestamp: UTC timestamp when call was created
Error response:
{
"success": false,
"error": "invalid_phone_number",
"message": "Phone number format is invalid",
"error_code": 400
}Configuration
The Millis AI integration requires configuration stored in application settings:
| Configuration Key | Description | Type | Example |
|---|---|---|---|
MillisAI:ApiKey | Millis AI API authentication key | String | sk_millis_abc123xyz |
MillisAI:ApiEndpoint | Base URL for Millis AI API | String | https://api.millis.ai/v1 |
MillisAI:AgentId | Default agent configuration ID in Millis | String | agent_prod_123 |
MillisAI:DefaultScript | Default call script if none provided | String | Multi-line script text |
MillisAI:MaxConcurrentCalls | Maximum concurrent calls limit | Integer | 50 |
MillisAI:CallTimeoutSeconds | Maximum call duration in seconds | Integer | 600 |
MillisAI:WebhookSecret | Secret for validating webhook signatures | String | webhook_secret_xyz |
MillisAI:RetryMaxAttempts | Maximum retry attempts for API calls | Integer | 3 |
MillisAI:RetryBackoffMs | Initial backoff in milliseconds | Integer | 1000 |
Millis AI API Call Flow
Request/Response/Callback Sequence
Call Status Polling
The GetCallStatus method polls the Millis AI /call/status/:call_id endpoint:
Request:
GET https://api.millis.ai/v1/call/status/call_millis_abc123def456
Authorization: Bearer sk_millis_abc123xyzResponse:
{
"call_id": "call_millis_abc123def456",
"status": "in_progress",
"duration_seconds": 45,
"agent_speaking": true,
"transcript_preview": "Hello John, this is an automated call...",
"started_at": "2026-03-21T14:30:45Z"
}Possible Status Values:
initiated: Call just created, waiting to connectringing: Phone is ringingconnected: Call answeredin_progress: Active conversationcompleted: Call finished normallyfailed: Call failed to connect or completeno_answer: Lead did not answerbusy: Lead's line was busy
Webhook Callback
When a call completes, Millis AI sends a webhook callback to the registered webhook URL:
Webhook Request:
{
"call_id": "call_millis_abc123def456",
"status": "completed",
"duration_seconds": 120,
"lead_name": "John Doe",
"lead_phone": "+1234567890",
"disposition": "completed_call",
"recording_url": "https://recordings.millis.ai/r/abc123def456.mp3",
"transcript": "Full conversation transcript...",
"metadata": {
"lead_id": "5678",
"campaign_id": "campaign_910"
},
"timestamp": "2026-03-21T14:32:45Z",
"signature": "sha256_hmac_hash_of_payload"
}Webhook Processing:
- Signature Validation: Verify HMAC-SHA256 signature using webhook secret
- Idempotency: Check if call_id already processed to handle retries
- Recording URL Storage: Extract and store recording URL for manager access
- Transcript Storage: Store full conversation transcript for quality review
- Status Update: Update call status in database to "completed"
- Acknowledgment: Return 200 OK to confirm receipt
Call Recording
The GetCallRecording method retrieves the call recording from Millis AI:
Request:
GET https://api.millis.ai/v1/call/recording/call_millis_abc123def456
Authorization: Bearer sk_millis_abc123xyzResponse:
- Returns audio file stream (MP3 or WAV format)
- Includes
Content-TypeandContent-Lengthheaders - File is stored in Millis infrastructure and cached
Recording Management:
- Recordings are retained for a configurable period (typically 90 days)
- URLs are long-lived but not permanent
- System caches recording metadata locally
- Managers can review recordings via MMS UI
- Recordings may be used for quality assurance and model training (with consent)
Rate Limiting
The system enforces rate limiting to prevent overwhelming the Millis AI service:
Rate Limiting Configuration:
MaxConcurrentCalls: Maximum simultaneous calls (default: 50)- Per-lead rate limit: Minimum 60 seconds between calls to same number
- Per-campaign rate limit: Configurable calls per minute
- Backoff strategy: Exponential backoff with jitter for retries
Error Handling
API Error Codes
| HTTP Code | Millis Error | Handling |
|---|---|---|
| 400 | invalid_phone_number | Log and mark as failed |
| 400 | invalid_script_length | Log and mark as failed |
| 401 | unauthorized | Check API key configuration |
| 429 | rate_limit_exceeded | Retry with backoff |
| 500 | internal_server_error | Retry with backoff |
| 503 | service_unavailable | Retry with backoff |
| 504 | gateway_timeout | Retry with backoff |
Retry Logic
- Retryable Errors: 429, 500, 503, 504 (server errors)
- Non-Retryable Errors: 400, 401 (client errors)
- Exponential Backoff: Initial delay 1000ms, multiplier 2.0, max 60000ms
- Maximum Attempts: Configurable, default 3
- Jitter: Random 0-100ms added to prevent thundering herd
Error Recovery
On terminal API failure:
- Update lead status to "Failed_AI_Call"
- Log complete error details with call attempt timestamp
- Create manual task for staff assignment
- Notify campaign manager of API issues if threshold exceeded
- Trigger alert if error rate exceeds 10% in 5-minute window
Performance Optimization
Connection Pooling
- HttpClient instance reused across all API calls
- Connection pool size: 10 connections
- Request timeout: 30 seconds
- Read timeout: 10 seconds
Caching
- Configuration cached in memory for 24 hours
- Agent ID cached per campaign
- Recording URLs cached with expiration
- Call status cached for 10 minutes
Async Operations
- All API calls use
async/await - Webhook callbacks processed asynchronously
- Status polling runs on background thread pool
- No blocking I/O in main request path
Monitoring and Observability
Key Metrics:
- Calls initiated per minute
- Success rate of InitiateCall
- Average call duration
- Recording retrieval success rate
- Webhook callback delivery success
- API latency percentiles (p50, p95, p99)
- Rate limit hits per hour
- Retry rate by error type
Logging:
- Log all API requests and responses at debug level
- Log all API errors with full details
- Log webhook callbacks with validation results
- Log rate limit events
- Structured logging with call_id correlation
Related Components
IAICaller: Interface implemented by this classAIAutoCallerFactory: Factory that instantiates this providerPostPendingLeadsToAIScheduler: Scheduler that uses this integrationLead: Data model for lead information- Webhook Handler: Component that processes Millis AI callbacks