- Polling — query the
GET /depositsendpoint filtered by transaction hash. Simple and stateless. - Webhooks — receive push notifications as deposits move through each stage. Real-time and event-driven.
Polling
Query theGET /deposits endpoint with the txHash parameter to look up a deposit by its source transaction hash.
Response
Each item in thedeposits array has the following shape:
Polling loop
Poll until the deposit reaches a terminal status (completed, failed, rejected, refunded, or ignored):
Webhooks
The deposit service sends webhook notifications to your configured endpoint as deposits move through the processing pipeline. All webhooks arePOST requests with Content-Type: application/json.
Configure your webhook URL and optional secret via the POST /setup endpoint.
Payload envelope
Every webhook request body follows the same envelope structure:Event types
deposit-received
Sent when an incoming token transfer is detected on a registered account.
deposit-rejected
Sent when a detected deposit will not be bridged because it violates the account’s deposit whitelist — the token isn’t allowed, or the amount is outside the configured minimum/maximum. It always follows a deposit-received event for the same deposit and is terminal: no bridging is attempted and there is no retry. This is a deliberate rejection, not a processing failure — use it to record the outcome on your side. See error codes for the full list.
Compare
deposit.amount (what was deposited) against limits (the configured bound) to surface the shortfall or overage to your users.
deposit-delayed
Sent when a deposit is temporarily held because sponsoring the bridge right now would exceed one of the per-intent sponsorship caps configured for the account — the overall sponsored amount, the sponsored gas fees, or the sponsored bridge fees. These are USD caps on how much sponsorship a single intent may consume; there are no gas-price or gas-amount limits. It follows a deposit-received event and is not terminal: the deposit enters the "delayed" status and is re-quoted automatically on a backoff. Because the sponsored cost varies over time (gas and bridge fees fluctuate) and the cap can be raised, a later quote may fit — then it proceeds as normal (bridge-started → bridge-complete). The deposit is held patiently through sustained congestion (up to a hold window, ~24h by default); only if it still hasn’t cleared when that window elapses does it end as bridge-failed with error code SPONSORSHIP-1.
Fired once, when the deposit first enters the delayed state — not on every retry. No action is required on your side; use it to surface a “waiting to settle” state to your users, and check limitKey if you want to raise the relevant cap. Distinct from bridge-delayed, which means a bridge already claimed funds and a refund is pending.
bridge-started
Sent when a bridging intent is created and submitted to the Orchestrator.
bridge-complete
Sent when tokens have arrived on the target chain.
bridge-delayed
Sent when the bridge provider has not filled the intent within the expected window. A refund is expected on the source chain; the subsequent deposit-refunded event confirms the funds returned.
bridge-failed
Sent when a bridging operation fails. See error codes for the full list and retry behavior.
deposit-refunded
Sent when funds from a deposit are returned to a recipient on the source chain. Typically follows a bridge-delayed event.
onramp-order
Sent when a fiat or CEX on-ramp order moves through its lifecycle. Unlike the other events, it is tied to a Swapped order rather than a deposit — once the purchased crypto lands on-chain, the regular deposit events take over. Correlate transactionId here with transactionHash on the subsequent deposit-received.
onramp-order is delivered at-least-once and only ever moves forward through the order lifecycle — you may receive a duplicate for the same stage, never an earlier one. Dedupe on eventId.
error
Sent when an unexpected, unhandled error occurs while processing a deposit — the catch-all in the settlement pipeline. It is not part of the normal lifecycle ordering and may arrive at any point. It carries whatever deposit / account / intent context was available at the point of failure; the optional fields are present only when that context was known.
Treat
error as a signal that a deposit needs manual attention. Correlate on deposit.transactionHash / intentId and reconcile by polling GET /deposits.
Signature verification
If you provided awebhookSecret during setup, every webhook request includes an X-Webhook-Signature header:
- Read the raw request body as a string (before JSON parsing)
- Compute the HMAC-SHA256 of the raw body using your webhook secret
- Compare the result with the value in the
X-Webhook-Signatureheader (strip thesha256=prefix) - Use a constant-time comparison to prevent timing attacks
Delivery behavior
- Retries — failed deliveries are retried multiple times before the event is marked
failed. Events that exhaust their retries can still be replayed on demand viaPOST /webhooks/events/{id}/resend, which reuses the originaleventId. - Ordering — events for a single deposit are sent in lifecycle order:
deposit-received→bridge-started→bridge-completewhen it proceeds, ordeposit-received→deposit-rejectedwhen it won’t be bridged. Adeposit-delayedmay appear afterdeposit-received(beforebridge-started) when the deposit is held under a sponsorship cap; it still resolves tobridge-completeor, on expiry,bridge-failed.onramp-orderevents are likewise ordered per order and only move forward. There is no global ordering guarantee across deposits or orders. - URL validation — the webhook URL must use HTTPS and must not target internal or private network addresses.
- Idempotency — use
eventIdfrom the envelope as the canonical dedupe key.
Backfilling missed events
If your receiver was offline or rejected events, replay them through the events API. Every dispatched webhook is persisted regardless of delivery outcome. List events delivered (or attempted) to your URL, newest first:eventId is reused so dedupe still holds:
GET /webhooks/events and POST /webhooks/events/{id}/resend.
Conventions
- EVM addresses and token addresses are lowercase. Non-EVM addresses (Solana, Tron) preserve their original case.
- Token amounts are strings in raw token units (not human-readable). Fiat amounts are decimal strings (e.g.
"101.75"). The one crossover:onramp-order.cryptoAmountis reported by Swapped as a decimal string, not raw units. - Chains use CAIP-2 identifiers (e.g.
"eip155:8453"for Base).