Webhooks & EventsWebhook Signatures
Signed eventsRetry enabled
Webhook Signatures
Production-grade webhook documentation for signed event delivery, retries, failed deliveries, event logs, and compliance-safe integrations.
Signing formula
formula
signedPayload = timestamp + "." + rawRequestBodyexpectedDigest = HMAC_SHA256(webhookSigningSecret, signedPayload)x-xaqiiji-signature: t=<unix_timestamp>,v1=<expectedDigest>Node.js verification
Node.js
Node.js
import crypto from "crypto";function parseSignatureHeader(header: string) { return Object.fromEntries( header.split(",").map((part) => { const [key, value] = part.split("="); return [key.trim(), value.trim()]; }) );}export function verifyXaqiijiWebhook({ rawBody, signatureHeader, secret, toleranceSeconds = 300,}) { const { t: timestamp, v1: signature } = parseSignatureHeader(signatureHeader); if (!timestamp || !signature) { return false; } const now = Math.floor(Date.now() / 1000); if (Math.abs(now - Number(timestamp)) > toleranceSeconds) { return false; } const signedPayload = `${timestamp}.${rawBody}`; const expected = crypto .createHmac("sha256", secret) .update(signedPayload) .digest("hex"); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature) );}Express handler
Express
Express
app.post( "/webhooks/xaqiiji", express.raw({ type: "application/json" }), (req, res) => { const signature = req.header("x-xaqiiji-signature"); const rawBody = req.body.toString("utf8"); const isValid = verifyXaqiijiWebhook({ rawBody, signatureHeader: signature ?? "", secret: process.env.WEBHOOK_SIGNING_SECRET!, }); if (!isValid) { return res.status(401).send("Invalid signature"); } const event = JSON.parse(rawBody); console.log(event.event); return res.status(200).json({ received: true }); });Other languages
TypeScript
TypeScript
// TypeScript signature verification// 1. Read raw request body (do not re-serialize JSON)// 2. Parse x-xaqiiji-signature → t=<unix>, v1=<hex>// 3. signedPayload = timestamp + "." + rawBody// 4. expected = HMAC-SHA256(WEBHOOK_SIGNING_SECRET, signedPayload)// 5. Compare v1 to expected with constant-time equality// 6. Reject if timestamp is older than 5 minutesPython FastAPI
Python FastAPI
// Python FastAPI signature verification// 1. Read raw request body (do not re-serialize JSON)// 2. Parse x-xaqiiji-signature → t=<unix>, v1=<hex>// 3. signedPayload = timestamp + "." + rawBody// 4. expected = HMAC-SHA256(WEBHOOK_SIGNING_SECRET, signedPayload)// 5. Compare v1 to expected with constant-time equality// 6. Reject if timestamp is older than 5 minutesPHP Laravel
PHP Laravel
// PHP Laravel signature verification// 1. Read raw request body (do not re-serialize JSON)// 2. Parse x-xaqiiji-signature → t=<unix>, v1=<hex>// 3. signedPayload = timestamp + "." + rawBody// 4. expected = HMAC-SHA256(WEBHOOK_SIGNING_SECRET, signedPayload)// 5. Compare v1 to expected with constant-time equality// 6. Reject if timestamp is older than 5 minutesJava Spring Boot
Java Spring Boot
// Java Spring Boot signature verification// 1. Read raw request body (do not re-serialize JSON)// 2. Parse x-xaqiiji-signature → t=<unix>, v1=<hex>// 3. signedPayload = timestamp + "." + rawBody// 4. expected = HMAC-SHA256(WEBHOOK_SIGNING_SECRET, signedPayload)// 5. Compare v1 to expected with constant-time equality// 6. Reject if timestamp is older than 5 minutes.NET
.NET
// .NET signature verification// 1. Read raw request body (do not re-serialize JSON)// 2. Parse x-xaqiiji-signature → t=<unix>, v1=<hex>// 3. signedPayload = timestamp + "." + rawBody// 4. expected = HMAC-SHA256(WEBHOOK_SIGNING_SECRET, signedPayload)// 5. Compare v1 to expected with constant-time equality// 6. Reject if timestamp is older than 5 minutesGo
Go
// Go signature verification// 1. Read raw request body (do not re-serialize JSON)// 2. Parse x-xaqiiji-signature → t=<unix>, v1=<hex>// 3. signedPayload = timestamp + "." + rawBody// 4. expected = HMAC-SHA256(WEBHOOK_SIGNING_SECRET, signedPayload)// 5. Compare v1 to expected with constant-time equality// 6. Reject if timestamp is older than 5 minutesEdit this page
Was this page helpful?