Skip to main content

Webhooks & Callbacks

Exotel uses webhooks (HTTP callbacks) to notify your application about events in real-time. Instead of polling the API, you provide a URL and Exotel sends event data to it as an HTTP POST request.

How Webhooks Work

1. You make an API call with a StatusCallback URL
2. The action happens (call completes, SMS delivered, etc.)
3. Exotel sends an HTTP POST to your URL with event data
4. Your server responds with HTTP 200 to acknowledge receipt
Important
  • Your endpoint must respond with HTTP 200 within 15 seconds
  • If your server doesn't respond or returns a non-2XX status, Exotel will retry up to 2 times
  • Implement fallback logic using the respective Details API to ensure you don't miss events

Voice Call StatusCallback

Notifies your application when a call reaches a terminal state (completed, failed, busy, no-answer).

Configured via: StatusCallback parameter when making a call

Default Payload

Sent for every call completion:

{
"CallSid": "80bfbec2d78bbbf10fb851f4fa165211",
"DateUpdated": "2024-01-15 14:30:45",
"Status": "completed",
"RecordingUrl": "https://s3-ap-southeast-1.amazonaws.com/recordings/abc123.mp3"
}
FieldTypeDescription
CallSidStringUnique call identifier
DateUpdatedDateTimeLast status update (YYYY-MM-DD HH:mm:ss)
StatusStringcompleted, failed, busy, or no-answer
RecordingUrlStringRecording URL (if recording was enabled, otherwise null)

Extended Payload (Event-Specific)

When you subscribe to events via StatusCallbackEvents (supports terminal and answered), additional fields are included:

{
"CallSid": "80bfbec2d78bbbf10fb851f4fa165211",
"EventType": "terminal",
"DateCreated": "2024-01-15 14:25:10",
"DateUpdated": "2024-01-15 14:30:45",
"To": "09123456789",
"From": "09876543210",
"PhoneNumberSid": "0XXXXXX4890",
"StartTime": "2024-01-15 14:25:12",
"EndTime": "2024-01-15 14:30:45",
"Status": "completed",
"ConversationDuration": 320,
"Direction": "outbound-api",
"CustomField": "order_12345",
"RecordingUrl": "https://s3-ap-southeast-1.amazonaws.com/recordings/abc123.mp3",
"Legs": [
{
"OnCallDuration": 335,
"Status": "completed",
"AnsweredBy": "NA"
},
{
"OnCallDuration": 320,
"Status": "completed",
"AnsweredBy": "HUMAN"
}
]
}
FieldTypeDescription
EventTypeStringterminal or answered
DateCreatedDateTimeWhen the call was initiated
ToStringRecipient phone number
FromStringCalling phone number
PhoneNumberSidStringExoPhone identifier
StartTimeDateTimeWhen the call started
EndTimeDateTimeWhen the call ended
ConversationDurationIntegerSeconds both parties were connected
DirectionStringinbound, outbound-dial, or outbound-api
CustomFieldStringYour custom metadata from the original request
LegsArrayPer-leg details (see below)

Leg Information

Each leg in the Legs array contains:

FieldTypeDescription
OnCallDurationIntegerDuration in seconds
StatusStringcompleted, busy, failed, no-answer, canceled, null
AnsweredByStringHuman, Machine, NotSure, or NA (first leg)
note

Extended callback fields require both From and To parameters in the original call request. StatusCallbackEvents does not apply when using VoiceUrl.


SMS Delivery Callback

Notifies your application when an SMS delivery status changes.

Configured via: StatusCallback parameter when sending an SMS

Payload

{
"SmsSid": "sms_abc123def456",
"To": "+919876543210",
"From": "EXOTEL",
"Status": "DELIVERED_TO_HANDSET",
"ExoStatusCode": 20005,
"DateUpdated": "2024-01-15 10:35:22"
}
FieldTypeDescription
SmsSidStringUnique SMS identifier
ToStringRecipient number
FromStringSender ID or ExoPhone
StatusStringDelivery status (see SMS Status Codes)
ExoStatusCodeIntegerNumeric status code
DateUpdatedDateTimeWhen the status changed

WhatsApp Status Callback

Notifies your application when a WhatsApp message status changes.

Configured via: status_callback parameter when sending a message

Payload

{
"sid": "msg_sid_value",
"from": "+919876500001",
"to": "+919876543210",
"status": "delivered",
"exo_status_code": 30002,
"timestamp": "2024-01-15T10:30:05Z"
}
FieldTypeDescription
sidStringMessage identifier
fromStringSender number
toStringRecipient number
statusStringsent, delivered, seen, or error status
exo_status_codeIntegerStatus code (see WhatsApp Status Codes)
timestampStringISO 8601 timestamp

Campaign Webhooks

Campaigns support three webhook types for different granularity levels.

Call Status Callback

Fires on every individual call attempt (including retries).

Configured via: call_status_callback when creating a campaign

{
"campaign_sid": "camp_abc123",
"call_sid": "call_def456",
"date_created": "2024-01-15T09:05:00+05:30",
"date_updated": "2024-01-15T09:05:47+05:30",
"number": "+919876543210",
"status": "completed"
}
FieldTypeDescription
campaign_sidStringCampaign identifier
call_sidStringUnique call identifier
numberStringCalled phone number
statusStringcompleted, failed, busy, no-answer

Call Schedule Callback

Fires after all retries for a specific number are exhausted.

Configured via: call_schedule_callback when creating a campaign

{
"campaign_sid": "camp_abc123",
"to": "+919876543210",
"from": "0XXXXXX4890",
"call_sids": ["call_def456", "call_ghi789", "call_jkl012"],
"status": "failed",
"date_created": "2024-01-15T09:05:00+05:30",
"date_updated": "2024-01-15T09:35:00+05:30"
}
FieldTypeDescription
campaign_sidStringCampaign identifier
toStringCalled phone number
fromStringExoPhone used
call_sidsArrayAll call attempt SIDs for this number
statusStringFinal status after all retries

Campaign Status Callback

Fires once when the entire campaign completes.

Configured via: status_callback when creating a campaign

{
"campaign_sid": "camp_abc123",
"status": "Completed",
"date_created": "2024-01-14T16:30:00+05:30",
"date_updated": "2024-01-15T18:00:00+05:30",
"report_url": "https://s3.amazonaws.com/.../campaign_report.csv"
}
FieldTypeDescription
campaign_sidStringCampaign identifier
statusStringCompleted, Failed, or Canceled
report_urlStringURL to download the full campaign report (CSV)

Heartbeat Webhook

Monitors the health of your ExoPhones and sends notifications when issues are detected.

Configured via: Exotel Dashboard (Heartbeat settings)

Payload

{
"timestamp": "2024-01-15T15:19:23Z",
"status_type": "CRITICAL",
"incoming_affected": ["exophone_sid_1"],
"outgoing_affected": ["exophone_sid_2"],
"data": {
"exophone_sid_1": {
"incoming_call": {
"status": "major_outage",
"last_check_time": "2024-01-15T15:19:00Z"
}
}
}
}
FieldTypeDescription
timestampStringRFC 3339 timestamp
status_typeStringOK, WARNING, CRITICAL, or PAYLOAD_TOO_LARGE
incoming_affectedArrayExoPhone SIDs with incoming call issues
outgoing_affectedArrayExoPhone SIDs with outgoing call issues
dataObjectDetailed health information per ExoPhone

Best Practices

  1. Always respond with HTTP 200 — Acknowledge receipt quickly, then process asynchronously
  2. Implement idempotency — You may receive duplicate webhooks; use CallSid/SmsSid to deduplicate
  3. Use HTTPS endpoints — Secure your callback URLs with TLS
  4. Validate the source — Verify webhook requests originate from Exotel's IP ranges
  5. Set up fallback polling — Use the Details API as a backup in case webhooks fail
  6. Log all payloads — Store raw webhook data for debugging and audit trails
  7. Handle timeouts gracefully — If processing takes >15 seconds, queue the work and respond immediately
Quick Reference
EventWebhook ParameterDocs
Call completesStatusCallbackVoice StatusCallback
SMS deliveredStatusCallbackSend SMS
WhatsApp statusstatus_callbackWhatsApp Send Message
Campaign callcall_status_callbackCampaign Webhooks
Campaign donestatus_callbackCampaign Webhooks
ExoPhone healthDashboard configHeartbeat