Shared building blocks · 7 of 15
Webhook signing
Verify Snapcaster webhook HMAC signatures over the raw request body.
Snapcaster sends these signature headers with every webhook.
X-Snapcaster-Timestampstring requiredUnix seconds when the request was signed; reject if outside a ±5 minute window.
X-Snapcaster-Signaturestring requiredsha256=+ lowercase hex of HMAC_SHA256(signingSecret, timestamp ‖ raw request body).
The signed message is the timestamp followed by the raw request body, byte for byte, with no delimiter between them. Verify before you parse the JSON, because re-serializing a parsed body changes its bytes and invalidates the signature.
const crypto = require('node:crypto');
function verifySnapcasterWebhook(rawBody, headers, signingSecret) {
const timestamp = headers['x-snapcaster-timestamp'];
const signature = headers['x-snapcaster-signature'];
if (typeof timestamp !== 'string' || typeof signature !== 'string') return false;
if (!/^\d+$/.test(timestamp) || !/^sha256=[a-f0-9]{64}$/.test(signature)) return false;
const timestampSeconds = Number(timestamp);
if (!Number.isSafeInteger(timestampSeconds)) return false;
if (Math.abs(Date.now() / 1000 - timestampSeconds) > 300) return false;
const expected = Buffer.from(
'sha256=' +
crypto.createHmac('sha256', signingSecret).update(timestamp).update(rawBody).digest('hex'),
);
const received = Buffer.from(signature);
return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}Build a webhook receiver shows the whole receiver around this function, including how to read the raw body.
Verification order
Section titled “Verification order”- Capture the raw body bytes.
- Reject a missing or malformed timestamp or signature.
- Reject a timestamp outside the five-minute replay window.
- Recompute HMAC-SHA256 over
timestamp || rawBodywith the environment’s per-platform signing secret. - Compare the complete prefixed signature in constant time.
- Parse JSON and deduplicate the delivery on
event_id.
If verification fails, return a non-2xx response so Snapcaster retries the delivery.
The signing secret differs between sandbox and production, and each environment has one live secret, so rotating the signing secret is a cutover. Do not verify webhooks with a seller’s marketplace API key.
Test your receiver
Section titled “Test your receiver”To have Snapcaster send your endpoint one signed webhook.test event, call POST /webhooks/test with a new UUID Idempotency-Key.
Snapcaster signs and retries it like every other event, and the response’s event_id is the one the delivery carries.
The test works for every subscription, in sandbox and in production, and changes no order and no stock.
A platform may send five test events a minute, and past that the call returns RATE_LIMITED with Retry-After.
WEBHOOK_ENDPOINT_NOT_REGISTERED means Snapcaster has not registered your receiver in this environment yet.
Path A continues with Keep stock in sync, and Path B skips ahead to Receive and ship orders.
Need help?
The email includes this page and selects sandbox as the environment. Update it if you need help with production.
Never include an API key or signing secret in the message.