Webhooks
A webhook sends events to your URL as they happen, for example when an SMS is delivered or an email bounces. See SMS events and email events for what you can subscribe to.
Creating a webhook
Section titled “Creating a webhook”{ "url": "https://yourcompany.com/webhooks/connect", "events": ["sms.delivered", "sms.failed", "sms.received", "email.bounced"]}The response includes the webhook’s secret, which is only shown once. Store it somewhere safe.
apiVersionsets theConnect-Versionthe payloads follow. It defaults to the current version, so your payloads don’t change when a new version is released.inboundNumberlimits the webhook tosms.receivedfor one of your virtual numbers.
API reference: POST /v2/webhooks
Payload
Section titled “Payload”Every webhook is a POST with a JSON body. data is the message, email, batch or suppression as it was when the event happened:
{ "id": "358120561368793088", "type": "sms.delivered", "occurredAt": "2026-10-10T09:30:04Z", "apiVersion": "2026-10-01", "workspaceId": "301245883010879488", "data": { "id": "357913724415131648", "direction": "outbound", "status": "delivered", "...": "the rest of the message" }}Each delivery has a Webhook-Id header that stays the same if we retry it. Use it to ignore a webhook you have already handled.
Verifying webhooks
Section titled “Verifying webhooks”Every webhook is signed so you can check it came from us. The Signature-Input and Signature headers are an HTTP Message Signature (RFC 9421) using hmac-sha256, with your webhook’s secret as the key. The signature covers the method, host, path, query, and the Content-Digest, Content-Type and Webhook-Id headers. Reject a webhook whose signature doesn’t match or whose expires time has passed. Signatures expire 5 minutes after they are made.
Rotating the secret
Section titled “Rotating the secret”POST /v2/webhooks/{id}/rotate-secret issues a new secret, shown once. For the next 72 hours, or until you rotate again, each webhook carries two signatures: sig under the new secret and sig-prev under the old one. The keyid of each is the secret’s version, so you can switch over without missing a webhook.
Retries
Section titled “Retries”Reply with any 2xx status to tell us you received a webhook. Otherwise we retry after 5 minutes, 15 minutes, 1 hour, 4 hours, 8 hours and 12 hours. If you reply 429, we wait for your Retry-After instead.
GET /v2/webhooks/{id}/deliveries lists the deliveries to a webhook with their latest attempt, so you can see what failed and why.
When a webhook keeps failing
Section titled “When a webhook keeps failing”If every attempt to a webhook fails for 6 hours, we switch it off and set autoDisabled. Set active back to true with PATCH /v2/webhooks/{id} once your endpoint is fixed.
autoDisableAfterMinuteschanges how long, from 5 minutes to 7 days.autoDisableExemptnever switches the webhook off.atRiskAlertPercentsends one warning per outage once that share of the time has passed. It defaults to 10%.
429 replies don’t count as failures.
Our IP addresses
Section titled “Our IP addresses”Webhooks come from fixed IP addresses, if you need to allow them through a firewall.