SMS to Webhook
Short answer: SMS to webhook delivers every inbound text on a SIP.IO messaging channel to your own HTTPS endpoint in real time, as an HMAC-SHA256-signed HTTP POST, the moment it arrives. Set forwardWebhookUrl (and optionally forwardWebhookSecret) on the channel and SIP.IO POSTs the message to you in the same signed envelope shape as its account-wide webhooks, no polling, no inbox to check.
Why an SMS API webhook
If you’re building on the SIP.IO messaging platform, your app usually needs to react to an inbound text: log a lead, kick off a workflow, post to Slack, update a CRM record. A webhook is the standard way to do that: rather than polling for new messages, your endpoint is called the instant one arrives. SMS to webhook is the per-number version of this: point one channel’s inbound traffic at one URL, independent of your account’s general webhook subscriptions.
How it’s configured
forwardWebhookUrl and forwardWebhookSecret are fields on a messaging channel, set at creation or via PATCH:
curl -X PATCH https://api.sip.io/v1/channels/ch_… \ -H 'x-api-key: sk_…' -H 'content-type: application/json' \ -d '{ "forwardWebhookUrl": "https://acme.com/hooks/sms-inbound", "forwardWebhookSecret": "whsec_…" }'forwardWebhookUrl must be https://, and it can’t point back at messaging.sip.io itself. The secret is optional, but without one the payload arrives unsigned, so set one if you want to verify the request is really from SIP.IO.
The payload
Every inbound message on the channel is POSTed to your URL in this envelope:
{ "event": "message.received", "account_id": "acc_acme", "data": { "channelId": "ch_…", "from": "+14155550100", "to": "+14155550199", "body": "Running 10 min late", "conversationId": "conv_…", "ts": 1719600000000 }, "ts": 1719600000000}This is the same { event, account_id, data, ts } shape used by SIP.IO’s account-wide webhook subscriptions, just scoped to one number instead of the whole account. Use it when a single number’s traffic should go to its own endpoint, in addition to (or instead of) your general webhook subscriptions.
Verifying the signature
If forwardWebhookSecret is set, the request carries an x-sipio-signature header: sha256=<hex hmac>, an HMAC-SHA256 over the raw request body. Recompute it and compare in constant time, the same verification you’d already write for SIP.IO’s account-wide webhooks:
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(rawBody, header, secret) { const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex'); const a = Buffer.from(header || ''), b = Buffer.from(expected); return a.length === b.length && timingSafeEqual(a, b);}Delivery behavior
- Forwarding never blocks the provider’s
200acknowledgment, so a slow or failing endpoint on your side doesn’t affect message delivery from the carrier’s perspective. - A failed delivery retries automatically, up to 3 attempts with backoff, for network failures,
429s, and5xxresponses (a4xxlike a bad URL fails fast instead, since retrying won’t fix it). Every attempt is logged and queryable via the webhooks API, so you can see exactly what was delivered, when, and why anything failed. - SMS-to-webhook runs alongside the normal conversation and
message.receivedwebhook path, it doesn’t replace them, it’s an additional per-channel delivery.
SMS to webhook vs. SMS to email
If you’d rather route inbound texts to an inbox than an endpoint, see SMS to Email, the same inbound event mirrored as an email instead of an HTTP POST. Set forwardEmail on the channel instead of (or alongside) forwardWebhookUrl; both are independent, best-effort forwarding paths off the same inbound message.
FAQ
How does SMS-to-webhook work on SIP.IO?
Set forwardWebhookUrl (and optionally forwardWebhookSecret) on a messaging channel. Every inbound message on that channel is POSTed to your URL in the envelope { event: "message.received", account_id, data, ts }, signed with HMAC-SHA256 if a secret is set.
How do I verify the SMS webhook signature?
Recompute sha256=<hex hmac> over the raw request body using your forwardWebhookSecret and compare it, constant-time, to the x-sipio-signature header. It’s the same scheme as SIP.IO’s account-wide webhooks.
Does SIP.IO retry a failed SMS webhook delivery?
Yes. Failed deliveries retry automatically, up to 3 attempts with backoff, for network failures, 429s, and 5xx responses, and every attempt is logged and queryable.
This is one part of the Messaging platform; see the full platform overview for everything else SIP.IO does. Read the docs → · Webhook signing reference → · See pricing →