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.
The event envelope
Every event, from every product, has the same four fields:Telling products apart
Branch on the prefix oftype. 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)
Delivery, retries, idempotency
- Return
2xxbefore 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.