Skip to main content

Verify webhook delivery

This guide shows the complete receiver pattern. See Webhooks for event and lifecycle concepts.

Express example

import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";

const app = express();

app.post(
"/assayra/events",
express.raw({ type: "application/json" }),
async (req, res) => {
const timestamp = String(req.header("Proofline-Timestamp") ?? "");
const signature = String(req.header("Proofline-Signature") ?? "");
const deliveryId = String(req.header("Proofline-Delivery-Id") ?? "");
const rawBody = Buffer.from(req.body);

const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!Number.isFinite(age) || age > 300) return res.sendStatus(401);

const expected = createHmac("sha256", process.env.ASSAYRA_WEBHOOK_SECRET!)
.update(`${timestamp}.`)
.update(rawBody)
.digest("hex");

const supplied = Buffer.from(signature, "hex");
const computed = Buffer.from(expected, "hex");
if (
supplied.length !== computed.length ||
!timingSafeEqual(supplied, computed)
) {
return res.sendStatus(401);
}

const inserted = await events.insertOnce(deliveryId, rawBody);
res.sendStatus(202);
if (inserted) await queue.publish({ deliveryId });
},
);

Use the exact header names and signing envelope displayed by your Developer Hub because the endpoint contract is versioned.

Worker

async function handle(event: AssayraEvent) {
if (event.type !== "application.decided") return;

const application = await assayra.applications.get(
event.data.applicationId,
);
await customerAccounts.applyAssayraState(
application.application.externalReference,
application.application.status,
{ idempotencyKey: event.id },
);
}

Receiver checklist

  • raw body captured before JSON middleware;
  • timestamp tolerance enforced;
  • constant-time signature comparison;
  • delivery/event ID deduplicated in durable storage;
  • fast 2xx acknowledgement;
  • asynchronous, retryable processing;
  • application state reconciled from the API; and
  • secret rotation and failure alerts tested.