Skip to content
LogoLogo

Webhooks

BLOX delivers events as HTTP POST requests to a URL you register. Every product uses the same envelope, the same signature scheme, and the same delivery policy — learn it once. Product pages list only which events fire and what is in data.

Register an endpoint

Register one endpoint per event type from the dashboard, Devtools → Webhooks.

TypeEvents
CHECKOUTCheckout events
PAYOUTPayout events
WALLETWallet events

Each type needs its matching product enabled on your account.

Your signing secret has no relationship to your API key. Rotating one does not affect the other.

Envelope

Every delivery, every product:

{
  "eventId": "payout.updated:b0e6c2f4-…:SETTLED",
  "event": "payout.updated",
  "webhookType": "PAYOUT",
  "timestamp": "2026-07-16T09:31:05.000Z",
  "data": {}
}
FieldDescription
eventIdUnique per event. Key your idempotency on this
eventEvent name, e.g. payout.updated
webhookTypeCHECKOUT, PAYOUT, or WALLET
timestampISO 8601
dataProduct-specific payload — see the product's events page

Headers

HeaderValue
Content-Typeapplication/json
X-Blox-TimestampUnix seconds when the payload was signed
X-Blox-Signaturesha256= + hex HMAC-SHA256 of "{timestamp}.{rawBody}"

Verify the signature

HMAC-SHA256 over "{X-Blox-Timestamp}.{rawBody}", keyed with your endpoint's whsec_… secret.

Two things silently break this:

  • Use the X-Blox-Timestamp header, not the timestamp field in the body. The header is Unix seconds; the body field is ISO 8601. They are not interchangeable, and the body one will never verify.
  • Verify over the raw body bytes, before JSON parsing. Re-serializing changes them and the signature will not match.

Compare in constant time, and reject deliveries whose X-Blox-Timestamp is more than 300 seconds from your server clock.

Delivery policy

Value
Timeout10 seconds
RetriesUp to 5 attempts, exponential backoff (~1m, 2m, 4m, 8m)
RedirectsNot followed — a 3xx counts as a failure
URLPublicly reachable; must not resolve to private or local addresses

Return 2xx quickly and do the work asynchronously. After the fifth failed attempt the event is dropped, so treat webhooks as the fast path and a status poll as your backstop.

Make handlers idempotent on eventId. Deliveries are not deduplicated on our side, so a retry of a delivery your server actually received will arrive again. Record the eventId and treat a repeat as a no-op.

URL requirements

  • Publicly reachable from the internet
  • HTTPS recommended (plain HTTP currently accepted)
  • Must not resolve to private or local network addresses
  • Redirects (3xx) are treated as failures

Testing

Use a tunnel (e.g. ngrok) for local endpoints, then trigger sandbox activity — create a checkout, send a payout, or deposit to a beneficiary address.