Svix
Overview
Svix is a webhook delivery platform used by many SaaS products. Its signing scheme uses three headers and includes a message ID in the signed string.
Add the signing secret to Splithook
The signing secret is available from the Svix dashboard (or API) — it starts with whsec_.
- Settings → Signing secrets → New.
- Provider: Svix.
- Paste the
whsec_secret. - In your destination, set Signing mode to Re-sign, select this secret.
Verify signatures in your handler
Use the official Svix SDK:
// Node.js
import { Webhook } from 'svix';
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const wh = new Webhook(process.env.SVIX_WEBHOOK_SECRET);
let payload;
try {
payload = wh.verify(req.body, {
'svix-id': req.headers['svix-id'] as string,
'svix-timestamp': req.headers['svix-timestamp'] as string,
'svix-signature': req.headers['svix-signature'] as string,
});
} catch (err) {
return res.status(400).send('Invalid signature');
}
// handle payload...
res.sendStatus(200);
});
# Python
from svix.webhooks import Webhook
wh = Webhook(os.environ['SVIX_WEBHOOK_SECRET'])
payload = wh.verify(request.data, {
'svix-id': request.headers.get('svix-id'),
'svix-timestamp': request.headers.get('svix-timestamp'),
'svix-signature': request.headers.get('svix-signature'),
})
How Splithook re-signs Svix events
Svix uses three headers:
svix-id: msg_2TqxxxxxxxxxxxI
svix-timestamp: 1714900000
svix-signature: v1,base64encodedhmac==
The signed string is: {svix-id}.{svix-timestamp}.{body}.
On replay, Splithook:
- Keeps
svix-idunchanged (message ID is stable across replays). - Replaces
svix-timestampwithnow(). - Recomputes
HMAC-SHA256(secret, "{svix-id}.{new_timestamp}.{body}"). - Base64-encodes and prefixes with
v1,.
Svix verifiers check the timestamp within a 5-minute tolerance — the refresh ensures replays pass.
Filtering
Svix-based platforms typically put the event type in the JSON body. Use event_type (if set via a header) or body.type:
body.type == 'invoice.created'
body.type matches '^invoice\.'