POST to your endpoint the moment it happens, and your app does the corresponding work in your own system: credit a balance, unlock a feature, notify a user, reconcile an order.
The key mental model: a webhook is the trigger for a state change in your product. You don’t poll Etherfuse asking “is it done yet?” — you let the event tell you, then act on the status in the payload.
Webhooks vs. polling. Webhooks fire the instant a state changes. Polling the list endpoints is slower (newly created orders take a moment to index) and wasteful (most requests return “no change”). Use webhooks for anything time-sensitive.
What to do on each event
This is the part most integrations care about: when event X arrives, what should your app do? Each flow below maps the lifecycle to the actions you take in your own system.Onramp — customer buys tokens with MXN
Onramp — customer buys tokens with MXN
Subscribe to
order_updated.| Status | What happened | What your app does |
|---|---|---|
created | Order created; awaiting the customer’s MXN deposit to the depositClabe | Show the customer the depositClabe to pay; mark the order pending |
funded | MXN deposit received and confirmed | Optionally surface “payment received, delivering tokens” |
completed | Tokens delivered to the wallet (confirmedTxSignature has the tx hash) | Mark fulfilled, credit the user, send confirmation |
failed | Order couldn’t be completed | Notify the customer; reconcile |
refunded | Deposit didn’t match the order amount; MXN returned | Reconcile and tell the customer funds were returned |
canceled | Canceled before funding | Close the order out in your system |
Offramp — customer sells tokens for MXN
Offramp — customer sells tokens for MXN
Subscribe to
order_updated.| Status | What happened | What your app does |
|---|---|---|
created | burnTransaction is ready for the customer to sign | Prompt the customer to sign and submit it (or use anchor mode on Stellar) |
funded | The customer’s transaction is confirmed on-chain | Surface “selling, sending MXN” |
completed | MXN sent to the customer’s bank account | Mark the payout as sent |
finalized | Reversal window has passed — funds can no longer be returned | Finalize your accounting for the order |
failed | Couldn’t be completed | Notify the customer; reconcile |
Swap — token to token
Swap — token to token
Subscribe to
Reading the payload (not the status sequence):
swap_updated.| Status | What happened | What your app does |
|---|---|---|
created | sendTransaction is ready for the customer to sign | Prompt the customer to sign and submit it |
funded | The source transaction is confirmed on-chain | Surface “swap in progress” |
completed | Target tokens delivered to the wallet | Update the user’s balances |
failed | Couldn’t be completed | Notify the customer; reconcile |
sendTransaction is included only while you still owe the source funds — sign and submit it. Once the funds are received it’s dropped from later payloads. On completion you get two hashes: sendTransactionHash (the customer’s send to Etherfuse) and receiveTransactionHash (Etherfuse’s delivery to the wallet). Which intermediate statuses fire varies by chain (some emit a distinct funds_received update, others don’t), so key your logic off the fields present in the payload rather than expecting a particular status to arrive.Onboarding & compliance — KYC, KYB, bank accounts
Onboarding & compliance — KYC, KYB, bank accounts
Subscribe to
Gating access on these events is the most common compliance pattern: don’t let a customer onramp, offramp, or swap until you’ve received
kyc_updated, customer_updated, and bank_account_updated.| Status | What happened | What your app does |
|---|---|---|
kyc_proposed | KYC data submitted, awaiting review | Show “verification pending” |
kyc_approved / customer_verified | The customer is cleared | Unlock their ability to transact |
kyc_rejected | KYC rejected (payload includes updateReason) | Block transacting; show the reason; prompt resubmission |
bank_account_active | Bank account verified and usable | Enable offramps/payouts to that account |
kyc_approved (or customer_verified) for them.How delivery works
Register an endpoint
Call POST /ramp/webhook with your HTTPS URL and the event type. The response includes a signing
secret, returned only once — store it securely.Receive the event
When the event fires, Etherfuse sends a
POST with the JSON payload to your URL, plus an X-Signature header.Verify the signature
Recompute the HMAC-SHA256 signature with your secret and compare. See Verifying Webhooks for Node and Python code.
Event types
| Event | Fires when |
|---|---|
order_updated | An onramp/offramp order changes status |
swap_updated | A swap changes status |
quote_updated | A quote’s status changes |
customer_updated | A customer’s verification status changes |
kyc_updated | A programmatic KYC submission is reviewed |
bank_account_updated | A bank account’s verification status changes |
Reliability & best practices
- Retries. Failed deliveries (a non-
2xxresponse or connection error) are retried up to 3 times with 5-second delays. Return a2xxpromptly to avoid them. - Acknowledge fast, process async. Hand the payload to a queue and return
2xxright away; don’t block the response on downstream work. - Handle events idempotently. The same event can arrive more than once (e.g. a retry after your
2xxwas lost). Dedupe on the resource ID plus its status so reprocessing is harmless — this pairs naturally with the client-generated UUIDs you already use for orders. - Don’t rely on ordering. Drive your logic off the
statusin the payload, not the order in which deliveries arrive. - Expose a public HTTPS endpoint. For local development, use a tunnel such as ngrok so Etherfuse can reach your handler.
Verifying signatures
Every delivery is signed so you can confirm it’s authentic:X-Signature: sha256={hex}, computed as HMAC-SHA256 over the RFC 8785-canonicalized JSON body using your webhook secret. Full walkthrough with Node/Python code: Verifying Webhooks.
Managing webhooks
- Create a subscription —
POST /ramp/webhook(returns the one-time secret) - List subscriptions —
POST /ramp/webhooks - Get a subscription —
GET /ramp/webhook/{id} - Delete a subscription —
DELETE /ramp/webhook/{id}
If a transaction expires before the customer signs it, fetch a fresh one with POST /ramp/order/{id}/regenerate_tx or POST /ramp/swap/{id}/regenerate_tx.