Endpoints
Webhooks
Register HTTP endpoints that receive real-time email events.
Webhooks POST a JSON event to your HTTPS endpoint when an email’s status changes. Respond with a 2xx within 10 seconds; other responses are retried, up to 12 attempts in total. Every request is signed with HMAC-SHA256 so you can verify it came from SNDR.
Signature verification
Each request carries X-Sndr-Signature: t=<unix seconds>,v1=<hex>. v1 is the HMAC-SHA256 of "<t>.<raw body>", keyed with the webhook secret. While a staged key exists, a second signature v1s is added; accept the request if any signature matches.
JavaScript
const crypto = require('crypto')
// header = req.headers['x-sndr-signature']
// rawBody = raw request body as a string, before JSON.parse
function verifySignature(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > toleranceSec) return false
const expected = crypto.createHmac('sha256', secret)
.update(parts.t + '.' + rawBody)
.digest('hex')
return Object.entries(parts).some(([key, sig]) =>
key.startsWith('v1') &&
sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
}Event payload
JSON
{
"id": "evt_5c1e9a7b-2d4",
"type": "email.delivered",
"created_at": "2026-06-01T12:00:04Z",
"data": {
"email_id": "em_3f9c1a2b-7d4",
"to": ["customer@example.com"]
}
}email.bounced and email.failed events carry data.email_id and data.error instead of data.to.
Supported events
- email.delivered — the receiving mail server accepted the email.
- email.bounced — the recipient address was rejected as invalid (hard bounce).
- email.failed — delivery failed for another reason.
- email.unsubscribed — a recipient unsubscribed using the link in an email.
- email.queued and email.complained — accepted when subscribing, but not currently sent.
- GETList webhooks
/api/cranl/v1/webhooksList all webhooks on the connected account. - POSTCreate webhook
/api/cranl/v1/webhooksRegister a webhook. - DELETEDelete webhook
/api/cranl/v1/webhooks/{id}Delete a webhook. - GETList signing keys
/api/cranl/v1/webhooks/{id}/signing-keysList the webhook’s rotation keys (status primary, secondary or retired) without secrets. - POSTStage signing key
/api/cranl/v1/webhooks/{id}/signing-keys/stageCreate a secondary key and return its secret once. - POSTPromote signing key
/api/cranl/v1/webhooks/{id}/signing-keys/{key_id}/promoteMake a secondary key the primary. - POSTRetire signing key
/api/cranl/v1/webhooks/{id}/signing-keys/{key_id}/retireRetire a secondary key without promoting it.