Skip to main content
Webhooks are how your application reacts to what happens at Etherfuse. A transaction settles, a customer passes KYC, a bank account goes active — Etherfuse sends a signed 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.
Subscribe to order_updated.
Subscribe to order_updated.
Subscribe to swap_updated.Reading the payload (not the status sequence): sendTransaction is always present in the payload. It contains the transaction the customer needs to sign and submit — once signed, the field remains but is no longer actionable. 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.
Subscribe to kyc_updated, customer_updated, and bank_account_updated.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_approved (or customer_verified) for them.

How delivery works

1

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.
2

Receive the event

When the event fires, Etherfuse sends a POST with the JSON payload to your URL, plus an X-Signature header.
3

Verify the signature

Recompute the HMAC-SHA256 signature with your secret and compare. See Verifying Webhooks for Node and Python code.
4

Respond 2xx, then do the work

Acknowledge with a 2xx immediately, then run your business logic asynchronously. A slow handler triggers unnecessary retries.

Event types

Payloads

Every webhook payload is a JSON object with a single key matching the event type; the value is the entity that changed, signed with your webhook secret (see Verifying Webhooks). The full schema and a worked example for each event live on its reference page, linked from the Event types table above. Fields are omitted when null or not applicable to the entity’s current state, so drive your logic off the fields present in the payload rather than expecting a fixed shape. A few specifics worth calling out:
  • order_updated carries burnTransaction, depositClabe, and confirmedTxSignature only when relevant to the order type and status. For embedded (non-custodial) wallets it also carries the pending approval object (approvalMessageId, approvalMessage, summary) while the order awaits the owner’s signature; there is no separate embedded-wallet transaction event. Re-read the order right before signing so the approvalMessage timestamp is fresh.
  • swap_updatedsendTransaction is always present (the transaction to sign; it stays in the payload but is no longer actionable once signed); receiveTransactionHash appears only on completion.
  • bank_account_updated: the bank is usable once its status is active; earlier statuses (bank_account_pending, bank_account_awaiting_deposit_verification) mean the SPEI provider hasn’t accepted it yet (see Bank account status).
  • kyc_updated — on approval, approved is true and updateReason / needsWork / userMessage are omitted.
  • kyb_updated carries the business’s organizationId and status. It fires only when the status actually changes, never on individual answer edits. The approved / submitted / notStarted / total counts cover the customer-facing requirements only, and approvedAt is set once the business is approved.

Reliability & best practices

  • Retries. Failed deliveries (a non-2xx response or connection error) are retried up to 3 times with 5-second delays. Return a 2xx promptly to avoid them.
  • Acknowledge fast, process async. Hand the payload to a queue and return 2xx right 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 2xx was 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 status in 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

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.