Xaqiiji
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 minutes

Python 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 minutes

PHP 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 minutes

Java 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 minutes

Go

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 minutes
Edit this page
Was this page helpful?