How do I verify Fynex webhook signatures?
Every webhook is signed. Recompute an HMAC-SHA256 of the timestamp and raw body with your signing secret, compare it to the X-Fynex-Signature header, and reject anything older than 5 minutes.
Every webhook Fynex sends is signed, so you can confirm it really came from us and wasn’t tampered with. Each request carries two headers — X-Fynex-Signature and X-Fynex-Timestamp. To verify, recompute the signature from the timestamp and the raw request body using your signing secret, and check it matches.
The headers
X-Fynex-Signature: sha256=<hex>— an HMAC-SHA256, hex-encoded.X-Fynex-Timestamp: <unix seconds>— when we sent it.
How to verify
- Read
X-Fynex-Timestampand the raw request body (verify before any JSON parsing — parsing and re-serialising changes the bytes). - Build the signed string as
timestamp + "." + rawBody. - Compute
HMAC-SHA256(signingSecret, signedString)and hex-encode it. - Compare it to the hex in
X-Fynex-Signature, using a constant-time comparison. - Reject the request if the timestamp is more than 5 minutes from now — this stops replays.
import crypto from 'node:crypto'
function verify(rawBody, headers, secret) {
const ts = headers['x-fynex-timestamp']
const sig = headers['x-fynex-signature'].replace('sha256=', '')
// reject stale requests (5-minute tolerance)
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false
const expected = crypto
.createHmac('sha256', secret)
.update(`${ts}.${rawBody}`)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
}
Notes
- Your signing secret is set per seller account with your webhook configuration; you can regenerate it if it leaks.
- If no secret is configured, requests aren’t signed — set one to enable verification.
- Always return quickly (a 2xx) once verified; do heavy work afterwards, because delivery times out at 10 seconds and retries.
Related
Was this helpful?Thanks for the feedback.