Docs
Calls API
Calls API
Manage phone call webhooks and call center integrations.
The Calls API enables integration with voice communication platforms, handling webhooks from call providers and tracking call activities within your organization.
Call Webhook
Handle incoming webhooks from voice communication platforms like Retell, Vapi, or Bland AI.
POST /api/calls/webhookHeaders
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key for authentication |
Content-Type | Yes | Must be application/json |
X-Webhook-Signature | No | Signature for webhook verification (provider-specific) |
Request Body
The webhook payload varies by provider. Common structure:
{
"callId": "call_abc123",
"provider": "retell",
"event": "call.completed",
"from": "+14155551234",
"to": "+14155555678",
"duration": 180,
"status": "completed",
"recording_url": "https://example.com/recordings/abc123.mp3",
"transcript": "Full conversation transcript...",
"metadata": {
"contactId": "contact_456def",
"agentId": "agent_789ghi"
},
"timestamp": "2025-01-15T10:30:00.000Z"
}Webhook Events
| Event | Description |
|---|---|
call.initiated | Call has been initiated |
call.ringing | Phone is ringing |
call.answered | Call was answered |
call.completed | Call has ended normally |
call.failed | Call failed to connect |
call.recording_ready | Recording is available |
Response
Status Code: 200 OK
{
"success": true,
"message": "Webhook processed successfully",
"callId": "call_abc123"
}Example Request
curl -X POST "https://api.evon.com/api/calls/webhook" \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"callId": "call_abc123",
"provider": "retell",
"event": "call.completed",
"from": "+14155551234",
"to": "+14155555678",
"duration": 180,
"status": "completed"
}'Supported Providers
Retell AI
Retell AI provides conversational AI for phone calls.
{
"provider": "retell",
"event": "call.completed",
"call_id": "retell_call_123",
"agent_id": "agent_retell_456",
"call_status": "ended",
"end_timestamp": 1705318200,
"transcript": "...",
"recording_url": "https://...",
"metadata": {}
}Vapi
Vapi enables voice AI assistants.
{
"provider": "vapi",
"type": "end-of-call-report",
"call": {
"id": "vapi_call_123",
"status": "ended",
"startedAt": "2025-01-15T10:30:00.000Z",
"endedAt": "2025-01-15T10:33:00.000Z",
"transcript": "...",
"recordingUrl": "https://..."
}
}Bland AI
Bland AI provides conversational AI capabilities.
{
"provider": "bland",
"event_type": "call_ended",
"call_id": "bland_call_123",
"from": "+14155551234",
"to": "+14155555678",
"call_length": 180,
"transcript": "...",
"recording_url": "https://..."
}Webhook Security
Signature Verification
Verify webhook signatures to ensure requests come from authorized sources:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}Error Responses
401 Unauthorized
{
"error": "Unauthorized",
"message": "Invalid or missing API key"
}400 Bad Request
{
"error": "Invalid webhook payload",
"message": "Missing required field: callId"
}500 Internal Server Error
{
"error": "Internal server error",
"message": "Failed to process webhook"
}Use Cases
Call Tracking and Analytics
Capture call data for analytics and reporting:
// Webhook endpoint receives call data
app.post('/api/calls/webhook', async (req, res) => {
const callData = req.body;
// Store call metrics
await analytics.track('call_completed', {
duration: callData.duration,
outcome: callData.status,
contactId: callData.metadata?.contactId
});
res.json({ success: true });
});Automatic Contact Updates
Update contact records based on call outcomes:
if (callData.event === 'call.completed') {
await updateContact(callData.metadata.contactId, {
lastCallDate: callData.timestamp,
callCount: { increment: 1 },
lastCallDuration: callData.duration
});
}Trigger Follow-up Actions
Automate workflows based on call events:
if (callData.status === 'no-answer') {
// Schedule follow-up call
await scheduleCall({
contactId: callData.metadata.contactId,
scheduledFor: addHours(new Date(), 2)
});
} else if (callData.status === 'completed') {
// Send thank you email
await sendEmail({
to: contact.email,
template: 'post_call_thank_you'
});
}