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

  1. Read X-Fynex-Timestamp and the raw request body (verify before any JSON parsing — parsing and re-serialising changes the bytes).
  2. Build the signed string as timestamp + "." + rawBody.
  3. Compute HMAC-SHA256(signingSecret, signedString) and hex-encode it.
  4. Compare it to the hex in X-Fynex-Signature, using a constant-time comparison.
  5. 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.
Was this helpful?
Book a demo