Webhooks

Webhook security & verification

Every signed webhook includes X-VenPays-Signature: t=<unix>,v1=<hex>.


Algorithm

  1. Parse t and v1 from the header
  2. Read the exact raw body string
  3. Compute HMAC-SHA256 over "{t}.{raw_body}" using the full secret string (including whsec_ if present)
  4. Compare hex digests with a constant-time function
  5. Optionally reject old timestamps (for example skew > 5 minutes)

Do not re-serialize JSON before verifying. VenPays signs compact canonical JSON (separators=(",", ":"), sort_keys=True).


Node.js example

import crypto from 'crypto'

export function verifyVenPaysSignature(secret, header, rawBody) {
  const parts = Object.fromEntries(
    header.split(',').map((p) => p.trim().split('='))
  )
  const signed = `${parts.t}.${rawBody}`
  const expected = crypto.createHmac('sha256', secret).update(signed).digest('hex')
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}

Additional headers: X-Webhook-Event, X-Webhook-Event-Id, User-Agent: V-Pay-Webhook/1.0.

Previous
Events