Signing & verification
Every webhook request is signed so you can confirm it genuinely came from Framme. The X-Framme-Signature header carries a hex-encoded HMAC-SHA256 of the raw request body, keyed with your subscription's token. Verify it before trusting the payload.
Verify a payload
Compute the HMAC over the raw body (not a re-serialised object) and compare it to the header using a constant-time check.
import crypto from "node:crypto"
function isValid(rawBody, signature, token) {
const expected = crypto
.createHmac("sha256", token)
.update(rawBody, "utf8")
.digest("hex")
const a = Buffer.from(expected)
const b = Buffer.from(signature || "")
return a.length === b.length && crypto.timingSafeEqual(a, b)
}
// Express: capture the raw body, then verify
app.post("/framme/webhooks", express.raw({ type: "*/*" }), (req, res) => {
const ok = isValid(req.body, req.get("X-Framme-Signature"), TOKEN)
if (!ok) return res.sendStatus(401)
const event = JSON.parse(req.body.toString("utf8"))
// …handle event, then:
res.sendStatus(200)
})Verify against the raw bytes you received. JSON re-serialisation can change whitespace or key order and break the signature.