GuidesSMS webhooks
SMS webhooks
Texts send webhooks like emails do: subscribe an endpoint to the events you want, and we sign each delivery the same way.
The events
| Event | When | data |
|---|---|---|
sms.queued | We accepted the text, or scheduled it. | The text |
sms.sent | It was handed to the carrier network. | The text |
sms.delivered | The phone received it. | The text |
sms.failed | It could not be delivered, or we skipped it. | The text, plus failed.type and failed.reason |
sms.received | Someone texted one of your numbers. | The received text |
contact.sms_unsubscribed | A phone opted out, by STOP or any other way. | contact_id, phone, origin, occurred_at |
Add them to an endpoint's events with POST /webhooks or PATCH /webhooks/{webhook_id}. A text from a campaign or an automation carries broadcast_id or automation_run_id. A canceled text sends nothing.
A delivered text
{
"type": "sms.delivered",
"created_at": "2026-10-19T20:41:04.000Z",
"data": {
"object": "sms",
"id": "01928c3e-5b7a-7c1e-9a2f-3d4e5f60718a",
"status": "delivered",
"from": "+18335550199",
"to": "+14155550123",
"text": "Acme: Your order #1042 has shipped.",
"category": "transactional",
"encoding": "gsm7",
"segments": 1,
"price_each": "0.015",
"cost": "0.015",
"currency": "usd",
"included": true,
"scheduled_at": null,
"created_at": "2026-10-19T20:41:00.000Z",
"tags": {
"order": "1042"
}
}
}A reply
{
"type": "sms.received",
"created_at": "2026-10-19T20:41:04.000Z",
"data": {
"object": "received_sms",
"id": "01928c3f-0c1d-7e2f-8a3b-4c5d6e7f8091",
"from": "+14155550123",
"to": "+18335550199",
"text": "Is my order on its way?",
"media": [],
"keyword": null,
"action": "forwarded",
"contact_id": "e169aa45-1ecf-4183-9955-b1499d5701d3",
"received_at": "2026-10-19T20:45:00.000Z"
}
}STOP, START, HELP and Y replies do not send sms.received: we act on them, and an opt-out sends contact.sms_unsubscribed. Images in a reply come as short-lived signed links.