Skip to main content

Webhooks

Register endpoints (scope webhooks) to receive events as they happen.

Events

Subscribe to events by name when you register. An FX order that ends expired sends no webhook. Treat a webhook as a signal and read the resource (GET /fx/orders/{id}, GET /transfers/{id}, GET /payment-links/{id}) for its current state.

Delivery format

Each delivery is an HTTPS POST with a JSON body:
and these headers: The body’s id (evt_…) identifies the event; BFX-Webhook-Id identifies the delivery. Use either to de-duplicate.

Verify every delivery

Your endpoint’s signing secret (whsec_…) is returned once, in the POST /webhooks response. Store it. To verify a delivery:
  1. Read t and v1 from BFX-Webhook-Signature.
  2. Compute HMAC-SHA256(secret, "<t>.<raw body>") as lower-case hex. Use the raw request body bytes exactly as received, before any JSON parsing.
  3. Compare it to v1 in constant time. Reject on mismatch.
  4. Reject the delivery if t is more than 5 minutes from your clock. This limits replay of a captured delivery.
Lost the secret? There is no way to read it again (a retried registration returns the body without secret). Delete the endpoint and register a new one.

Retries

A delivery succeeds when your endpoint answers any 2xx within 10 seconds. Anything else is retried on this schedule, measured from the previous attempt: That is 6 attempts over about 8 hours 36 minutes. If the sixth attempt fails, the delivery is dropped and the whole endpoint is disabled: it receives no further events. There is no re-enable call; delete the endpoint and register it again. Test deliveries follow the same rules.

Managing endpoints

  • url must be HTTPS and resolve to a public address. Private, loopback and cloud-metadata addresses are refused with 400 invalid_url.
  • events must list one or more of payment_link.paid, charge.settled, fx.order.settled, fx.order.failed, fx.order.refunded, transfer.confirmed, transfer.failed. webhook.test is not subscribable; it is sent only by the test call.
  • Each account can have up to 10 active endpoints (409 endpoint_cap_reached).