Dispatching Voice Agent Calls
Examples for initiating outbound calls with voice agents.
Basic Call Dispatch
JavaScript/TypeScript
Codeconst API_KEY = "your-api-key"; const BASE_URL = "https://api.slng.ai"; async function dispatchCall(agentId, phoneNumber, args = {}) { const response = await fetch(`${BASE_URL}/v1/agents/${agentId}/calls`, { method: "POST", headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ phone_number: phoneNumber, arguments: args, }), }); if (!response.ok) { const error = await response.json(); throw new Error(`Failed to dispatch call: ${error.error}`); } return response.json(); } // Basic call const result = await dispatchCall( "550e8400-e29b-41d4-a716-446655440000", "+14155551234", ); console.log(`Call dispatched: ${result.call_id}`);
Python
Codeimport requests API_KEY = "your-api-key" BASE_URL = "https://api.slng.ai" def dispatch_call(agent_id, phone_number, arguments=None): response = requests.post( f"{BASE_URL}/v1/agents/{agent_id}/calls", headers={ "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" }, json={ "phone_number": phone_number, "arguments": arguments or {} } ) response.raise_for_status() return response.json() # Basic call result = dispatch_call( "550e8400-e29b-41d4-a716-446655440000", "+14155551234" ) print(f"Call dispatched: {result['call_id']}")
cURL
Codecurl -X POST https://api.slng.ai/v1/agents/550e8400-e29b-41d4-a716-446655440000/calls \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "phone_number": "+14155551234" }'
Calls with Template Variables
Pass dynamic values to personalize each call:
JavaScript/TypeScript
Code// Agent system_prompt uses: {{customer_name}}, {{order_id}}, {{issue_type}} const result = await dispatchCall( "550e8400-e29b-41d4-a716-446655440000", "+14155551234", { customer_name: "John Smith", order_id: "ORD-2024-12345", issue_type: "delayed shipment", }, );
Python
Code# Agent system_prompt uses: {{customer_name}}, {{order_id}}, {{issue_type}} result = dispatch_call( "550e8400-e29b-41d4-a716-446655440000", "+14155551234", { "customer_name": "John Smith", "order_id": "ORD-2024-12345", "issue_type": "delayed shipment" } )
cURL
Codecurl -X POST https://api.slng.ai/v1/agents/550e8400-e29b-41d4-a716-446655440000/calls \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "phone_number": "+14155551234", "arguments": { "customer_name": "John Smith", "order_id": "ORD-2024-12345", "issue_type": "delayed shipment" } }'
Batch Call Dispatch
Dispatch multiple calls sequentially or in parallel:
Sequential Dispatch
Codeasync function dispatchBatch(agentId, contacts) { const results = []; for (const contact of contacts) { try { const result = await dispatchCall(agentId, contact.phone, contact.args); results.push({ phone: contact.phone, success: true, call_id: result.call_id, }); // Small delay between calls to avoid rate limiting await new Promise((resolve) => setTimeout(resolve, 500)); } catch (error) { results.push({ phone: contact.phone, success: false, error: error.message, }); } } return results; } // Usage const contacts = [ { phone: "+14155551234", args: { customer_name: "John Smith", appointment_time: "2pm" }, }, { phone: "+14155555678", args: { customer_name: "Jane Doe", appointment_time: "3pm" }, }, { phone: "+14155559012", args: { customer_name: "Bob Wilson", appointment_time: "4pm" }, }, ]; const results = await dispatchBatch( "550e8400-e29b-41d4-a716-446655440000", contacts, ); console.log("Batch results:", results);
Parallel Dispatch (with concurrency limit)
Codeasync function dispatchBatchParallel(agentId, contacts, concurrency = 5) { const results = []; // Process in chunks for (let i = 0; i < contacts.length; i += concurrency) { const chunk = contacts.slice(i, i + concurrency); const chunkResults = await Promise.allSettled( chunk.map((contact) => dispatchCall(agentId, contact.phone, contact.args) .then((result) => ({ phone: contact.phone, success: true, call_id: result.call_id, })) .catch((error) => ({ phone: contact.phone, success: false, error: error.message, })), ), ); results.push(...chunkResults.map((r) => r.value || r.reason)); } return results; }
Python Batch Dispatch
Codeimport asyncio import aiohttp async def dispatch_call_async(session, agent_id, phone_number, arguments=None): async with session.post( f"{BASE_URL}/v1/agents/{agent_id}/calls", headers={ "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" }, json={ "phone_number": phone_number, "arguments": arguments or {} } ) as response: if response.status == 200: data = await response.json() return {"phone": phone_number, "success": True, "call_id": data["call_id"]} else: error = await response.json() return {"phone": phone_number, "success": False, "error": error.get("error")} async def dispatch_batch(agent_id, contacts, concurrency=5): semaphore = asyncio.Semaphore(concurrency) async def limited_dispatch(session, contact): async with semaphore: return await dispatch_call_async( session, agent_id, contact["phone"], contact.get("args") ) async with aiohttp.ClientSession() as session: tasks = [limited_dispatch(session, contact) for contact in contacts] return await asyncio.gather(*tasks) # Usage contacts = [ {"phone": "+14155551234", "args": {"customer_name": "John Smith"}}, {"phone": "+14155555678", "args": {"customer_name": "Jane Doe"}}, {"phone": "+14155559012", "args": {"customer_name": "Bob Wilson"}}, ] results = asyncio.run(dispatch_batch("550e8400-e29b-41d4-a716-446655440000", contacts)) for result in results: if result["success"]: print(f"✓ {result['phone']}: {result['call_id']}") else: print(f"✗ {result['phone']}: {result['error']}")
Phone Number Validation
The API requires E.164 format phone numbers:
Codefunction validateE164(phoneNumber) { // E.164: + followed by country code and number (max 15 digits total) const e164Regex = /^\+[1-9]\d{1,14}$/; return e164Regex.test(phoneNumber); } // Format helpers for common cases function formatUSPhone(phone) { // Remove all non-digits const digits = phone.replace(/\D/g, ""); // Handle 10-digit US numbers if (digits.length === 10) { return `+1${digits}`; } // Handle 11-digit with leading 1 if (digits.length === 11 && digits.startsWith("1")) { return `+${digits}`; } throw new Error("Invalid US phone number format"); } // Usage const formatted = formatUSPhone("(415) 555-1234"); // Returns: +14155551234 await dispatchCall(agentId, formatted);
Python Phone Validation
Codeimport re def validate_e164(phone_number): """Validate E.164 format phone number.""" return bool(re.match(r'^\+[1-9]\d{1,14}$', phone_number)) def format_us_phone(phone): """Format US phone number to E.164.""" digits = re.sub(r'\D', '', phone) if len(digits) == 10: return f"+1{digits}" elif len(digits) == 11 and digits.startswith('1'): return f"+{digits}" else: raise ValueError("Invalid US phone number format") # Usage formatted = format_us_phone("(415) 555-1234") # Returns: +14155551234
Error Handling
Codeasync function safeDispatchCall(agentId, phoneNumber, args = {}) { try { const response = await fetch(`${BASE_URL}/v1/agents/${agentId}/calls`, { method: "POST", headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ phone_number: phoneNumber, arguments: args, }), }); if (response.status === 400) { const error = await response.json(); // Common 400 errors: // - Invalid phone number format // - Missing required template variables console.error("Validation error:", error.error); return { success: false, error: "validation", message: error.error }; } if (response.status === 403) { console.error("Authentication failed"); return { success: false, error: "auth", message: "API key invalid" }; } if (response.status === 404) { console.error("Agent not found"); return { success: false, error: "not_found", message: "Agent does not exist", }; } if (!response.ok) { console.error("Unexpected error:", response.status); return { success: false, error: "unknown", message: `HTTP ${response.status}`, }; } const result = await response.json(); return { success: true, call_id: result.call_id }; } catch (error) { console.error("Network error:", error.message); return { success: false, error: "network", message: error.message }; } } // Usage with retry logic async function dispatchWithRetry(agentId, phoneNumber, args, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { const result = await safeDispatchCall(agentId, phoneNumber, args); if (result.success) { return result; } // Don't retry validation or auth errors if ( result.error === "validation" || result.error === "auth" || result.error === "not_found" ) { return result; } // Exponential backoff for network/unknown errors if (attempt < maxRetries) { const delay = Math.pow(2, attempt) * 1000; console.log(`Retry ${attempt}/${maxRetries} in ${delay}ms...`); await new Promise((resolve) => setTimeout(resolve, delay)); } } return { success: false, error: "max_retries", message: "Max retries exceeded", }; }
Campaign Management Pattern
Complete example for managing an outbound call campaign:
Codeclass CallCampaign { constructor(agentId, apiKey) { this.agentId = agentId; this.apiKey = apiKey; this.baseUrl = "https://api.slng.ai"; this.results = []; } async dispatchCall(phoneNumber, args) { const response = await fetch( `${this.baseUrl}/v1/agents/${this.agentId}/calls`, { method: "POST", headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ phone_number: phoneNumber, arguments: args, }), }, ); if (!response.ok) { const error = await response.json(); throw new Error(error.error || `HTTP ${response.status}`); } return response.json(); } async run(contacts, options = {}) { const { concurrency = 3, delayBetweenCalls = 1000, onProgress = () => {}, onComplete = () => {}, } = options; let completed = 0; const total = contacts.length; for (let i = 0; i < contacts.length; i += concurrency) { const batch = contacts.slice(i, i + concurrency); const batchResults = await Promise.allSettled( batch.map(async (contact) => { try { const result = await this.dispatchCall(contact.phone, contact.args); return { phone: contact.phone, name: contact.args?.customer_name || "Unknown", success: true, call_id: result.call_id, }; } catch (error) { return { phone: contact.phone, name: contact.args?.customer_name || "Unknown", success: false, error: error.message, }; } }), ); for (const result of batchResults) { const data = result.status === "fulfilled" ? result.value : result.reason; this.results.push(data); completed++; onProgress({ completed, total, latest: data }); } // Delay before next batch (unless this is the last batch) if (i + concurrency < contacts.length) { await new Promise((resolve) => setTimeout(resolve, delayBetweenCalls)); } } const summary = { total: this.results.length, successful: this.results.filter((r) => r.success).length, failed: this.results.filter((r) => !r.success).length, results: this.results, }; onComplete(summary); return summary; } } // Usage const campaign = new CallCampaign( "550e8400-e29b-41d4-a716-446655440000", process.env.SLNG_API_KEY, ); const contacts = [ { phone: "+14155551234", args: { customer_name: "John Smith", appointment_date: "Monday" }, }, { phone: "+14155555678", args: { customer_name: "Jane Doe", appointment_date: "Tuesday" }, }, { phone: "+14155559012", args: { customer_name: "Bob Wilson", appointment_date: "Wednesday" }, }, // ... more contacts ]; const summary = await campaign.run(contacts, { concurrency: 5, delayBetweenCalls: 2000, onProgress: ({ completed, total, latest }) => { const status = latest.success ? "✓" : "✗"; console.log( `[${completed}/${total}] ${status} ${latest.name} (${latest.phone})`, ); }, onComplete: (summary) => { console.log("\n--- Campaign Complete ---"); console.log(`Total: ${summary.total}`); console.log(`Successful: ${summary.successful}`); console.log(`Failed: ${summary.failed}`); }, });
Use Cases
Appointment Reminders
Codeconst appointmentReminders = [ { phone: "+14155551234", args: { patient_name: "John Smith", appointment_type: "dental cleaning", appointment_date: "Monday, January 15th", appointment_time: "2:00 PM", doctor_name: "Dr. Johnson", }, }, // ... more appointments ]; await campaign.run(appointmentReminders);
Payment Reminders
Codeconst paymentReminders = [ { phone: "+14155551234", args: { customer_name: "John Smith", amount_due: "$150.00", due_date: "January 20th", account_number: "****1234", }, }, // ... more reminders ];
Survey/Feedback Collection
Codeconst surveyCalls = [ { phone: "+14155551234", args: { customer_name: "John Smith", recent_purchase: "Premium Subscription", purchase_date: "last week", }, }, // ... more customers ];
Lead Qualification
Codeconst leadCalls = [ { phone: "+14155551234", args: { lead_name: "John Smith", company: "TechCorp", interest: "enterprise software", source: "website demo request", }, }, // ... more leads ];
Last modified on