Webhook signing
Every webhook Delivery carries X-Snapcaster-Timestamp as Unix seconds and X-Snapcaster-Signature as sha256=<lowercase hex>.
The signed message is the timestamp concatenated directly with the exact raw request body bytes.
There is no delimiter.
Verify before parsing JSON. 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}$/i.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);}Use an exact-byte body facility such as express.raw() for the webhook route.
Only after verification succeeds should the handler parse JSON and deduplicate on event_id.
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.
The Signing secret is different in sandbox and production. Do not use a Seller’s Marketplace API key for webhook verification.
Need help?
Email Marketplace support with this page and the sandbox environment prefilled.
Never include an API key or Signing secret in the message.