Verify webhook signatures + retries
The signature header
Every webhook includes:
X-Releaseo-Signature: t=1719501234,v1=abc123…
X-Releaseo-Event-Id: evt_…
t is the Unix timestamp; v1 is the HMAC-SHA256 of ${t}.${body} using your signing secret.
Verify in Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyReleaseo(req, secret) {
const header = req.headers['x-releaseo-signature'];
const [tPart, sigPart] = header.split(',');
const t = tPart.replace('t=', '');
const v1 = sigPart.replace('v1=', '');
const payload = `${t}.${req.rawBody}`;
const expected = createHmac('sha256', secret).update(payload).digest('hex');
return timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}
Reject replays
Compare the timestamp against Date.now() — reject anything older than 5 minutes.
Retry behavior
6 attempts over 24 hours
Backoff: 30s, 2m, 10m, 1h, 6h, 24h
Stop after a 2xx response
Audit log in Settings → Integrations → Webhooks → Deliveries
Make endpoints idempotent
Use X-Releaseo-Event-Id as your idempotency key — same id = same event, even on retry.