Guide
Webhooks
Subscribing to events, verifying signatures and handling retries.
Register an HTTPS endpoint and subscribe it to the events you care about. The endpoint secret is returned once at creation.
Verifying a delivery
Each delivery carries BoundlessPay-Signature: t=<unix seconds>,v1=<hex>, where v1 is HMAC-SHA256 of `${t}.${rawBody}` using the endpoint secret. Compare with a timing-safe check and reject anything older than five minutes.
import { createHmac, timingSafeEqual } from 'node:crypto'
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
const age = Math.abs(Date.now() / 1000 - Number(parts.t))
if (!parts.t || !parts.v1 || age > 300) return false
const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')
const a = Buffer.from(expected), b = Buffer.from(parts.v1)
return a.length === b.length && timingSafeEqual(a, b)
}
Verify against the raw body bytes, before any JSON parsing or re-serialisation.
Delivery semantics
- Respond
2xxquickly and do the work asynchronously; slow endpoints are retried. - Deliveries are at-least-once. De-duplicate on the event
id. - Events can arrive out of order. Treat the object in the payload as the current truth, or re-read it.
Next
Going live
