The Waiver-Signature header contains a Unix timestamp and a SHA-256 HMAC: t=<timestamp>,v1=<hex>. Verify it using the endpoint's signing secret before accepting the event as authentic.
Preserve the raw body
Compute HMAC-SHA256 over the timestamp, a period and the exact request body bytes. In a framework that normally parses JSON, arrange raw-body access for this route before its JSON middleware runs. Do not stringify an already parsed object and expect the original signature to match.
Verify in Node.js
The following function verifies a Buffer. It does not configure a framework route or enqueue the event for you.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyDelivery(rawBody, header, secret, now = Date.now()) {
if (!Buffer.isBuffer(rawBody) || typeof header !== 'string') return false;
const fields = Object.fromEntries(header.split(',').map(x => x.trim().split('=')));
const timestamp = fields.t;
const signature = fields.v1;
if (!timestamp || !/^\d+$/.test(timestamp)) return false;
if (!signature || !/^[a-f0-9]{64}$/i.test(signature)) return false;
if (Math.abs(now / 1000 - Number(timestamp)) > 300) return false;
const expected = createHmac('sha256', secret)
.update(timestamp + '.')
.update(rawBody)
.digest();
const received = Buffer.from(signature, 'hex');
return received.length === expected.length && timingSafeEqual(received, expected);
}
Keep the receiver's clock synchronized. The timestamp tolerance is five minutes in either direction. An otherwise correct HMAC with an old timestamp should fail the freshness check.
Acknowledge after durable acceptance
Once verification succeeds, parse the body, validate the envelope your application expects and store the delivery in persistent storage. Return 2xx after the durable write succeeds. Let a worker perform the slower business action.
If you cannot safely store the event, return a failure so the delivery can retry. Do not return success merely to make a failing endpoint appear healthy.
Test the negative cases
Verify a valid message, a changed body, a wrong secret, a missing header, malformed hex and a timestamp outside the tolerance. Include non-ASCII content so your test catches accidental byte conversion. Never log the secret while diagnosing a mismatch.
Continue with duplicate handling and retry behavior. Signature verification proves message authenticity; your worker still needs safe processing and recovery.