Every webhook request includes three Svix headers:
svix-id: msg_2dQp…
svix-timestamp: 1714305600
svix-signature: v1,K8vDqK5g…
Verify in Node
import { Webhook } from "svix";
const wh = new Webhook(process.env.AGNTIX_WEBHOOK_SECRET);
app.post("/webhooks/agntix", express.raw({ type: "application/json" }), (req, res) => {
try {
const payload = wh.verify(req.body, {
"svix-id": req.headers["svix-id"],
"svix-timestamp": req.headers["svix-timestamp"],
"svix-signature": req.headers["svix-signature"],
});
handleEvent(JSON.parse(payload.toString()));
res.sendStatus(200);
} catch (err) {
res.sendStatus(400);
}
});
Verify in Python
from svix.webhooks import Webhook, WebhookVerificationError
wh = Webhook(os.environ["AGNTIX_WEBHOOK_SECRET"])
try:
payload = wh.verify(request.body, {
"svix-id": request.headers["svix-id"],
"svix-timestamp": request.headers["svix-timestamp"],
"svix-signature": request.headers["svix-signature"],
})
except WebhookVerificationError:
return Response(status=400)
Replay protection
The svix-timestamp is enforced ±5 minutes. Old replays are rejected automatically.
Always verify on the raw request body, not a parsed JSON object. Any reformatting will break
the signature.