SMS webhooks your endpoint can actually trust.
Subscribe to inbound messages, delivery receipts and call events. VanceTel pushes each one to your endpoint as soon as it happens — and signs every request with HMAC-SHA256 so you can verify it came from us.
POST /your-endpoint HTTP/1.1
X-Netexem-Signature: t=1717000000,v1=8a1f...c4
Content-Type: application/json
{
"id": "evt_3pQ2x9KdLm",
"type": "message.received",
"createdAt": "2026-05-31T14:02:11Z",
"data": {
"id": "msg_7nF1aZ",
"from": "+15557654321",
"to": "+15551234567",
"body": "Yes — 2pm works, thanks!",
"direction": "inbound"
}
}A signed inbound-message event, delivered the moment a text arrives.
Verify before you trust the payload.
Each request carries a timestamp and an HMAC-SHA256 digest of the raw body. Recompute it with your endpoint secret and compare in constant time. If it does not match, drop the request — no exceptions.
- Sign the raw request bytes, not the re-serialized JSON.
- Use a constant-time compare to resist timing attacks.
- Reject stale timestamps to blunt replayed requests.
import crypto from 'node:crypto'
// Verify an HMAC-SHA256 webhook signature.
// Use the RAW request body — never the re-serialized JSON.
function verify(rawBody, header, secret) {
const [, ts] = header.match(/t=(\d+)/) ?? []
const [, sig] = header.match(/v1=([a-f0-9]+)/) ?? []
if (!ts || !sig) return false
const expected = crypto
.createHmac('sha256', secret)
.update(`${ts}.${rawBody}`)
.digest('hex')
// Constant-time compare to resist timing attacks.
const a = Buffer.from(sig, 'hex')
const b = Buffer.from(expected, 'hex')
return a.length === b.length && crypto.timingSafeEqual(a, b)
}Subscribe to the events you care about.
Pick events when you register an endpoint. VanceTel delivers only those, each with a stable type and a versioned payload.
message.receivedAn inbound SMS or MMS arrives on one of your business numbers.
message.deliveredA carrier returns a delivery receipt for a message you sent.
message.failedA message could not be delivered — includes a failure reason code.
call.completedA call ends — fires with direction, duration and the numbers involved.
call.missedAn inbound call rings out without being answered on any device.
contact.createdA contact is added through the API or a synced form submission.
curl https://api.netexem.com/v1/webhook_endpoints \
-H "Authorization: Bearer $NETEXEM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/hooks/netexem",
"events": ["message.received", "message.delivered", "call.completed"]
}'Signed, retried, and typed by default.
Signed
Every request carries an X-Netexem-Signature header — an HMAC-SHA256 of the raw body keyed with your endpoint secret. Verify it before you trust a single field.
Retried
If your endpoint does not return a 2xx, the event is retried with exponential backoff. Respond fast, acknowledge early, and process the payload out of band.
Typed events
A stable event type and a versioned payload shape on every request. Switch on the type, read the data object, and ignore events you have not subscribed to.
Webhook questions, answered.
Want to see the signed events flowing into a real endpoint? Book a walkthrough.
How do I verify the webhook signature?
Every request includes an X-Netexem-Signature header containing a timestamp and an HMAC-SHA256 digest. Compute your own HMAC-SHA256 over the timestamp joined to the raw request body, keyed with your endpoint secret, then compare it to the v1 value using a constant-time comparison. Always sign the raw body bytes — re-serializing the parsed JSON can change whitespace and break the match.
Which events fire?
You subscribe to the events you care about when you create an endpoint. The catalog covers inbound messages (message.received), carrier delivery receipts (message.delivered and message.failed) and call events (call.completed, call.missed), plus contact.created. Each event has a stable type and a versioned data payload.
What happens if my endpoint is down?
Return any 2xx status to acknowledge an event. If VanceTel does not get a 2xx, the webhook is retried with exponential backoff over the following hours, so a brief outage does not drop events. Acknowledge quickly and process the payload asynchronously to avoid retries from slow handlers.
Should I also poll the API, or are webhooks enough?
Webhooks are push-based and cover inbound messages, delivery receipts and call events as they happen. The public REST API is write-and-action oriented — you use it to create endpoints, send messages and manage contacts. For most integrations, webhooks deliver the real-time events and the API performs the actions.
Listen for every message, receipt and call.
Wire VanceTel webhooks into your stack and react to phone activity in real time — every event signed, retried and typed.