Proposal, not live spec. A webhook design drawn from Stripe, Svix, Transak, and Plaid.
For team review - exact event names, payloads, and the signing scheme are decided with the
routing layer.
Structure (Svix’s 7-section shape)
Intro - Events & event types - Adding endpoints - Testing - Signature verification -
Retries - Troubleshooting. Every section below maps to one of these.
Event catalog
Each event maps to a transaction status:
| Event | Fires when |
|---|
deposit.created | A deposit is created |
deposit.routing | Funds begin settling cross-chain |
deposit.source_confirmed | Source payment confirmed |
deposit.completed | USDC landed - safe to credit the user |
deposit.failed | Deposit failed |
deposit.refunded | A completed deposit was reversed |
Common envelope: { id, type, created, data: { ... } }.
Signature verification (Stripe HMAC pattern)
- Header:
Rheon-Signature: t=<timestamp>,v1=<signature>
- Signed payload:
{timestamp}.{raw_request_body}
- HMAC-SHA256 with the endpoint secret, compared in constant time
- ⚠️ Use the raw body - if the framework re-serializes it, verification fails. This
is the single most common integration bug, worth calling out explicitly.
- Timestamp guards against replay; reject events older than ~5 minutes.
Alternative (Transak): a JWT-signed payload verified with a partner access token. HMAC
header is simpler for partners to consume.
Retries, delivery & idempotency
Benchmarks to set expectations:
| Provider | 2xx timeout | Retry window | Backoff |
|---|
| Stripe | ~5s | up to 3 days | exponential |
| Plaid | 10s | up to 24h | 30s ×4, honors Retry-After |
- Return
2xx before heavy work: verify → enqueue → return 200, then process async.
- No ordering guarantee - events can arrive out of order; reconcile against the API.
- Idempotency - events can arrive more than once; deduplicate on
id.
Testing (the quality signal - Stripe)
- CLI with a localhost tunnel:
rheon listen --forward-to localhost:PORT/webhook
- Trigger the full lifecycle (
created → routing → completed) on demand in the sandbox
- A public tunnel (ngrok) for local endpoints
Troubleshooting
A table of HTTP status / error → cause → fix (connection refused, 3xx redirect, 4xx, 5xx,
TLS, timeout, signature mismatch), plus source IP ranges for partners that firewall.