Skip to main content
Webhooks push a status change to your backend, so you credit a user the moment money lands instead of polling. There is one webhook surface for the whole platform, not one per product: you subscribe once, say which products and payment methods you want events for, and every event arrives in the same envelope, signed the same way, with the same retry policy. Only the event names differ, because each product keeps its own status set. Polling stays available alongside: each product’s status endpoint is listed on Transaction statuses.

One subscription, many products

A subscription is one endpoint URL on your account plus the scope it receives:
  • Product - crypto deposits, card payments, bank transfers and virtual accounts, payouts.
  • Payment method within that product where it matters - for example a card payment paid by card or by Apple Pay, or a bank transfer over one rail rather than another.
Subscriptions are configured on your account, like your key permissions and your fee - ask us to set the endpoint and the scope during onboarding, and to change it later. A product outside the scope never reaches the endpoint, so a subscription scoped to deposits does not start receiving payout events when payouts are enabled on your key.

The event envelope

Every event, from every product, has the same four fields:

Telling products apart

Branch on the prefix of type. It is the product, and it decides which status set the suffix belongs to: The statuses are the product’s own - a deposit says done and a card payment says completed because they move through different machinery. Do not map them onto one vocabulary in your code; branch per prefix and read that product’s table on Transaction statuses.

Event catalog

One event per product means “the money landed” - that is the only one you credit on, marked in bold. Crypto deposits Card payments - by card or Apple Pay; the payment method does not change the events Bank transfers and virtual accounts A virtual account is reusable, so this fires once per settlement rather than once per account. Payouts - card, bank, and from a virtual account

Signature verification

Every delivery is signed so you can trust it came from Rheon:
  • Header: Rheon-Signature: t=<timestamp>,v1=<signature>
  • Signed payload: <timestamp>.<raw_request_body>
  • HMAC-SHA256 with your endpoint secret, compared in constant time
  • Use the raw request body - if your framework re-serializes it, verification fails (the single most common integration bug)
  • Reject events whose timestamp is older than ~5 minutes (replay protection)
One endpoint secret covers the whole subscription, whichever product the event is from.

Delivery, retries, idempotency

  • Return 2xx before heavy work: verify, enqueue, return 200, then process async.
  • No ordering guarantee - events can arrive out of order; reconcile against that product’s status endpoint.
  • Idempotency - an event can arrive more than once; deduplicate on id.
  • Failed deliveries are retried with backoff over a retry window.

Testing

Point a subscription at your test endpoint and drive a flow in the sandbox. One limit to know before you rely on it: the sandbox cannot force a transaction to its completed state, so the crediting event for crypto deposits and cards is not something you can trigger there - build that branch to the terminal status and test the rest of the lifecycle.
For anything your backend must trust (crediting a user), rely on a webhook you verified or a terminal status you fetched yourself - never on client-side UI state.