Webhooks
Receive real-time notifications when API-triggered calls complete. Webhooks eliminate the need for polling and enable event-driven architectures.
Overview
When you trigger a call with a callbackUrl, a webhook is delivered to that URL when the call ends (either completed or failed). This is the recommended approach for production integrations.
Webhooks are delivered per-call, not per-campaign. Each call with a
callbackUrl will receive its own webhook delivery.Webhook Payload
When a call completes, a POST request is sent to your callbackUrl with the following JSON payload:
{"event": "call.completed","callId": "8f14e45f-ceea-467f-a830-cf60f5e5a214","campaignId": "357b188c-c618-4f95-84b1-cbe26b8ce3e0","phoneNumber": "+14155551234","status": "completed","duration": 127,"endReason": "agent_hangup","analysis": {"sentiment": {"overall": "positive","score": 0.85,"confidence": 0.92},"humanContact": {"reached": true,"type": "human","confidence": 0.95},"objectives": [{"id": "1","name": "Confirm order","achieved": true,"confidence": 0.88}]},"metadata": {"orderId": "123","source": "shopify"},"completedAt": "2024-01-15T14:32:07Z"}
Event Types
| Event | Description |
|---|---|
call.completed | Call finished successfully (human or agent hangup) |
call.failed | Call failed (timeout, connection error, or no answer) |
Payload Fields
| Field | Type | Description |
|---|---|---|
event | string | Event type (call.completed or call.failed) |
callId | string | Unique identifier for the call |
campaignId | string | The API campaign the call was triggered from |
phoneNumber | string | The phone number that was called |
status | string | Final call status |
duration | number | Call duration in seconds (null for failed calls) |
endReason | string | Why the call ended (hangup, agent_hangup, timeout, etc.) |
analysis | object | AI-powered call analysis (may be null if analysis is still processing) |
metadata | object | The custom metadata you passed when triggering the call |
completedAt | string | ISO 8601 timestamp of when the call ended |
Retry Behavior
If your endpoint returns an error or times out, the webhook will be retried with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 second |
| 2nd retry | 5 seconds |
| 3rd retry | 15 seconds |
Your endpoint should return a
2xx status code within 10 seconds to be considered successful. Webhook delivery is fire-and-forget — failures do not affect call processing.Requirements
- The
callbackUrlmust use HTTPS - Your endpoint must respond within 10 seconds
- Return any
2xxstatus code to acknowledge receipt - Webhooks may be delivered more than once — design your handler to be idempotent
Example Webhook Handler
// Express.js exampleapp.post('/webhooks/call-complete', (req, res) => {const { event, callId, status, analysis, metadata } = req.body;console.log(`Call ${callId} ${event}: ${status}`);if (event === 'call.completed' && analysis) {// Process call resultsconst sentiment = analysis.sentiment?.overall;const objectivesAchieved = analysis.objectives?.filter(o => o.achieved).map(o => o.name);// Update your records using the metadataupdateOrder(metadata.orderId, {callCompleted: true,sentiment,objectivesAchieved,});}// Acknowledge receiptres.status(200).json({ received: true });});