Signature format updated (2026-04) — the X-Simiz-Signature header now uses the Stripe-like format t=<unix_timestamp>,v1=<hmac_sha256_hex> (signed payload = ${timestamp}.${body}) with a 5 minute replay tolerance. For current verification snippets (Node.js, Python, PHP with timing-safe compare), see the Node.js SDK webhooks guide. The legacy sha256=<hex> snippets below are kept for historical reference only — do not use them.
Every webhook Simiz sends includes a HMAC SHA-256 signature in the X-Simiz-Signature header. You should always verify this signature before processing the event.
How it works
- Simiz computes the signature using your webhook secret and the signed payload
${timestamp}.${raw_body}
- The signature is sent in the
X-Simiz-Signature header as t=<unix_timestamp>,v1=<hmac_sha256_hex>
- On your side : parse the header, verify timestamp is within 5 min, recompute HMAC on
${timestamp}.${raw_body}, timing-safe compare
Verification examples
import crypto from 'crypto';
function verifyWebhook(
payload: string,
signature: string,
secret: string
): boolean {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expectedSignature}`)
);
}
// Express example
app.post('/webhooks/simiz',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-simiz-signature'] as string;
if (!verifyWebhook(req.body.toString(), signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body.toString());
// Process the event...
res.status(200).json({ received: true });
}
);
Security best practices
Always use timingSafeEqual (or equivalent) for signature comparison. Standard string comparison (===) is vulnerable to timing attacks.
- Use the raw body — Don’t parse JSON before verifying. Middleware like
express.json() can alter the payload
- Rotate secrets — Regenerate your webhook secret periodically via the Dashboard
- Use HTTPS — Never expose webhook endpoints over plain HTTP
- Validate event types — Only process events you expect