SMS Webhooks
Webhooks allow Exotel to push real-time SMS events to your server, including delivery status updates and inbound message notifications. This guide covers how to set up, secure, and process SMS webhooks.
What Are SMS Webhooks?​
SMS webhooks are HTTP callbacks that Exotel sends to your configured endpoint when an event occurs. Instead of polling the API for updates, your server receives instant notifications.
| Event Type | Description | Trigger |
|---|---|---|
| Delivery Status | Status updates for outbound SMS | Message delivered, failed, or expired |
| Inbound SMS | Customer replies to your messages | New inbound message received |
Setting Up Webhooks​
Delivery Status Webhook​
Option 1: Per-Message (API Parameter)​
Set the StatusCallback parameter when sending an SMS:
curl -X POST "https://<api_key>:<api_token>@api.exotel.com/v1/Accounts/<account_sid>/Sms/send" \
-d "From=EXOTL" \
-d "To=+919876543210" \
-d "Body=Your order has shipped" \
-d "DltEntityId=1234567890123" \
-d "DltTemplateId=1107160000000012345" \
-d "StatusCallback=https://your-server.com/webhooks/sms-status"
Option 2: Account-Level (Dashboard)​
Configure a default webhook URL for all outbound SMS:
- Log in to the Exotel Dashboard.
- Navigate to Settings > SMS Settings.
- Enter your Status Callback URL.
- Select the HTTP method (POST recommended).
- Save the settings.
Inbound SMS Webhook​
Configure the webhook for receiving customer replies:
- In the Exotel Dashboard, go to Settings > SMS Settings > Inbound SMS.
- Enter your Inbound Webhook URL.
- Select the HTTP method (POST recommended).
- Save.
Webhook URL Requirements​
| Requirement | Details |
|---|---|
| Protocol | HTTPS required (HTTP not accepted in production) |
| Response time | Must respond within 10 seconds |
| Response code | Must return 2xx status (200, 201, 202) |
| Availability | Endpoint must be publicly accessible |
| Certificate | Valid SSL/TLS certificate (self-signed not accepted) |
If your webhook endpoint is behind a firewall, whitelist Exotel's IP ranges. Contact Exotel support for the current list of IP addresses.
Delivery Status Webhook Payload​
When a message status changes, Exotel sends an HTTP POST to your callback URL:
Request Format​
Content-Type: application/x-www-form-urlencoded
| Parameter | Type | Description |
|---|---|---|
SmsSid | string | Unique SMS identifier |
AccountSid | string | Your Exotel account SID |
From | string | Sender ID used |
To | string | Recipient phone number |
Status | string | High-level status (queued, sent, delivered, failed) |
DetailedStatus | string | Detailed status code |
DetailedStatusCode | integer | Numeric status code |
SentAt | string | ISO 8601 timestamp of send |
UpdatedAt | string | ISO 8601 timestamp of update |
ExternalRef | string | Your custom reference ID (if provided) |
Example: Delivered​
POST /webhooks/sms-status HTTP/1.1
Host: your-server.com
Content-Type: application/x-www-form-urlencoded
SmsSid=sms_abc123&AccountSid=acct_123&From=EXOTL&To=%2B919876543210&Status=delivered&DetailedStatus=DELIVERED_TO_HANDSET&DetailedStatusCode=20000&SentAt=2025-01-15T10%3A30%3A00%2B05%3A30&UpdatedAt=2025-01-15T10%3A30%3A05%2B05%3A30
Example: Failed​
POST /webhooks/sms-status HTTP/1.1
Host: your-server.com
Content-Type: application/x-www-form-urlencoded
SmsSid=sms_def456&AccountSid=acct_123&From=EXOTL&To=%2B919876543210&Status=failed&DetailedStatus=FAILED_DND&DetailedStatusCode=30004&SentAt=2025-01-15T10%3A30%3A00%2B05%3A30&UpdatedAt=2025-01-15T10%3A30%3A01%2B05%3A30
Inbound SMS Webhook Payload​
When a customer sends an SMS to your Exotel number:
| Parameter | Type | Description |
|---|---|---|
SmsSid | string | Unique identifier for the inbound SMS |
From | string | Customer's phone number |
To | string | Your Exotel virtual number |
Body | string | Message content |
DateCreated | string | ISO 8601 timestamp |
AccountSid | string | Your Exotel account SID |
Example: Inbound Message​
POST /webhooks/sms-inbound HTTP/1.1
Host: your-server.com
Content-Type: application/x-www-form-urlencoded
SmsSid=inb_xyz789&AccountSid=acct_123&From=%2B919876543210&To=%2B911140XXXXXX&Body=YES&DateCreated=2025-01-15T10%3A35%3A00%2B05%3A30
Handling Webhooks​
Node.js (Express)​
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: true }));
// Delivery status webhook
app.post('/webhooks/sms-status', (req, res) => {
const { SmsSid, Status, DetailedStatus, To } = req.body;
console.log(`SMS ${SmsSid} to ${To}: ${Status} (${DetailedStatus})`);
// Update your database with the delivery status
updateSmsStatus(SmsSid, Status, DetailedStatus);
res.status(200).send('OK');
});
// Inbound SMS webhook
app.post('/webhooks/sms-inbound', (req, res) => {
const { From, Body, SmsSid } = req.body;
console.log(`Inbound SMS from ${From}: ${Body}`);
// Process the inbound message asynchronously
processInboundSms(From, Body, SmsSid);
res.status(200).send('OK');
});
app.listen(3000);
Python (Flask)​
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhooks/sms-status', methods=['POST'])
def sms_status():
sms_sid = request.form.get('SmsSid')
status = request.form.get('Status')
detailed = request.form.get('DetailedStatus')
to_number = request.form.get('To')
print(f"SMS {sms_sid} to {to_number}: {status} ({detailed})")
update_sms_status(sms_sid, status, detailed)
return 'OK', 200
@app.route('/webhooks/sms-inbound', methods=['POST'])
def sms_inbound():
from_number = request.form.get('From')
body = request.form.get('Body')
print(f"Inbound from {from_number}: {body}")
process_inbound(from_number, body)
return 'OK', 200
Retry Policy​
If your webhook endpoint does not respond with a 2xx status code, Exotel retries:
| Attempt | Delay After Previous |
|---|---|
| 1st retry | 30 seconds |
| 2nd retry | 2 minutes |
| 3rd retry | 10 minutes |
| Final (4th) | 30 minutes |
After all retries are exhausted, the callback is marked as failed. You can retrieve missed events from the dashboard or via the SMS Details API.
Securing Your Webhooks​
IP Whitelisting​
Restrict incoming requests to Exotel's IP ranges:
- Contact Exotel support to obtain the current IP whitelist.
- Configure your firewall or web server to accept requests only from those IPs.
HTTPS Enforcement​
Always use HTTPS endpoints. Exotel does not send webhooks to plain HTTP URLs in production environments.
Request Validation​
Validate that incoming requests contain expected parameters and originate from Exotel:
app.post('/webhooks/sms-status', (req, res) => {
// Validate required fields
if (!req.body.SmsSid || !req.body.AccountSid) {
return res.status(400).send('Invalid payload');
}
// Validate account SID matches your account
if (req.body.AccountSid !== process.env.EXOTEL_ACCOUNT_SID) {
return res.status(403).send('Unauthorized');
}
// Process the webhook
// ...
res.status(200).send('OK');
});
Process webhook payloads asynchronously. Acknowledge receipt immediately with a 200 response, then handle the business logic in a background job or queue. This prevents timeouts and ensures reliable delivery.
Testing Webhooks​
Using ngrok for Local Development​
During development, use ngrok to expose your local server:
ngrok http 3000
Use the generated HTTPS URL (e.g., https://abc123.ngrok.io/webhooks/sms-status) as your webhook URL in the Exotel dashboard or API.
Verifying Webhook Delivery​
- Send a test SMS via the Exotel API or dashboard.
- Check your server logs for the incoming webhook request.
- Verify the payload fields match the expected format.
- Confirm your endpoint returned a 200 response.
Best Practices​
- Always respond quickly -- Return a 2xx response within 5 seconds; process data asynchronously.
- Be idempotent -- The same callback may be delivered multiple times; use
SmsSidas a deduplication key. - Log all webhooks -- Store raw webhook payloads for debugging and audit trails.
- Monitor webhook failures -- Set up alerts if your endpoint starts failing to respond.
- Use a queue -- Push incoming webhooks to a message queue (RabbitMQ, SQS, Redis) for reliable processing.
- Handle all statuses -- Your code should handle every possible status, not just
deliveredandfailed.
Next Steps​
- SMS Delivery Reports -- Understand delivery statuses
- Two-Way SMS -- Build interactive SMS workflows
- SMS Status Codes -- Complete status code reference
- SMS API Reference -- API documentation