Quickstart
Receive and verify your first webhook in a few minutes.
Create a receiver
Your endpoint must be a public HTTPS URL that accepts POST requests and
answers with a 2xx status. Install Express:
npm i expressThis receiver verifies the signature and acknowledges the event:
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";
const SECRET = process.env.ZAHER_WEBHOOK_SECRET!; // whsec_…
const app = express();
// Keep the raw body: the signature is computed over the exact bytes sent.
app.post(
"/webhooks/zaher",
express.raw({ type: "application/json" }),
(req, res) => {
const body = req.body.toString("utf8");
if (!isValid(body, req.header("X-Zaher-Signature"), req.header("X-Zaher-Timestamp"))) {
return res.sendStatus(400);
}
const event = JSON.parse(body);
console.log("Received", event.type, event.id);
res.sendStatus(200); // acknowledge fast; do slow work afterwards
}
);
function isValid(body: string, signatureHeader?: string, timestamp?: string) {
if (!signatureHeader || !timestamp) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = createHmac("sha256", SECRET)
.update(`${timestamp}.${body}`)
.digest();
return signatureHeader.split(",").some((part) => {
const [version, hex] = part.trim().split("=");
const received = Buffer.from(hex ?? "", "hex");
return (
version === "v1" &&
received.length === expected.length &&
timingSafeEqual(received, expected)
);
});
}
app.listen(3000);Testing locally
Expose your local server over HTTPS with a tunnel such as ngrok http 3000
or cloudflared tunnel, and use the tunnel URL as your endpoint.
Add the endpoint in Zaher
- In your dashboard, open Settings → Webhooks and click Add endpoint.
- Paste your HTTPS URL and pick the events to receive.
- Copy the signing secret shown after saving and set it as
ZAHER_WEBHOOK_SECRETin your receiver. You can reveal it again later from the endpoint page.
Send a test event
On the endpoint page, choose an event under Send a test event and click
Send test. Zaher sends sample data with "test": true through the real
signing and delivery pipeline. The attempt appears in the Delivery log
with your server's response.