CPaaS
Guide: verifiser WeZend-webhook-signaturer i Express (med kode)
Et komplett, fungerende Express-endepunkt som mottar leveringswebhooks og avviser alt som ikke faktisk er fra WeZend.
WWeZend Team5. juli 2026 · 5 min lesing
WeZends webhooks er per melding: dere sender med webhook_url i selve send-requesten (se Webhooks), og dette er mottakersiden av det.
Endepunktet
const express = require("express");
const crypto = require("crypto");
const app = express();
app.use(express.raw({ type: "application/json" })); // vi trenger den rå bodyen for verifisering
app.post("/hooks/wezend", (req, res) => {
const signature = req.get("X-ZafeConnect-Signature");
const timestamp = req.get("X-ZafeConnect-Timestamp");
const rawBody = req.body.toString("utf8");
const expected = crypto
.createHmac("sha256", process.env.WEZEND_WEBHOOK_SECRET)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const isValid =
signature &&
expected.length === signature.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
if (!isValid) return res.status(401).send("invalid signature");
res.sendStatus(200); // svar raskt — gjør det virkelige arbeidet etterpå
const payload = JSON.parse(rawBody);
processDeliveryEvent(payload).catch(console.error);
});
Tre ting det er verdt å få riktig
- Bruk den rå bodyen til signatursjekken, ikke den parsede/reserialiserte JSON-en — reserialisering kan subtilt endre whitespace eller nøkkelrekkefølge og ødelegge HMAC-sammenligningen.
- Svar
2xxfør dere gjør tregt arbeid. Et mislykket eller tregt svar utløser et nytt forsøk (30 sek, 5 minutter, 30 minutter) — greit ved et reelt avbrudd, sløsing ved en handler som bare er treg. - Header-navnene sier fortsatt
X-ZafeConnect-*, ikkeX-WeZend-*— en rest fra plattformens opprinnelige navn som ennå ikke er omdøpt i backend. Match header-navnet nøyaktig som vist over; anta ikke at det følger dagens merkevare.
Hvor signeringshemmeligheten kommer fra
Finn (og roter) den under Innstillinger → Webhook-hemmelighet, støttet av GET /v1/webhook-secret og POST /v1/webhook-secret/rotate.