Skip to main content
GET
Get bridge intent status
Alpha Preview — Endpoints and response shape may change without notice.
Two endpoints share this page:
  • GET /api/2/bridge/status/{id} — returns the current row immediately.
  • GET /api/2/bridge/status/{id}/wait — long-polls server-side until the intent reaches a terminal state (or the timeout elapses).

Path parameter

id accepts any of these — pass whichever you have:
  • intentId from /quote (format xxxxxxx-xxxxxxx-xxx).
  • The on-chain bytes32 intent ID (EVM only, emitted by MobulaBridge).
  • The deposit TX hash.
  • The fill TX hash.
If nothing matches, the response is not an error — it’s
This is the expected state right after the deposit is broadcast but before the solver has indexed it. Keep polling.

Response

latencyMs is the deposit-detected → fill-confirmed delta. settleTxHash / timestamps.settled populate only once the solver has been reimbursed on the origin chain — that step is async and can lag the user-visible fill. On a slippage refund, failureReason.code is "slippage" and a human-readable message field is added telling the user to raise their slippage. fillTxHashPending is true when the fill is already complete (status: "filled") but its canonical destination tx hash hasn’t been indexed yet — the case for Hyperliquid destinations, whose L1 hash is assigned a moment after the funds move. While it’s true, fillTxHash is null. Treat the bridge as done as soon as you see filled; fetch the hash separately (see the best practice below).

Status lifecycle

The statuses the solver actually writes: On deposit detection the solver writes filling directly — there is no intermediate deposited status. (deposited and retrying exist in the underlying type enum but are not currently emitted; retries are tracked in a separate queue and the intent stays in filling.) A relaying intent resolves to filled (or refunded) like any other; the terminal row then carries isRelayFallback: true and a relayRequestId. Treat any non-terminal status as “keep waiting,” and any unknown status defensively. The terminal set is filled, settled, failed, refunded. Stop polling once you see one of them.

GET /status/{id}/wait

Long-poll variant. Blocks server-side until the intent reaches filled, settled, failed, or refunded, then returns the same shape as /status/{id}. If the window elapses first, you get the current (non-terminal) row and should call again.

Query parameter

How it actually waits

The server holds the request open and resolves it the moment your intent reaches a terminal state (filled, settled, failed, or refunded) — the result is always current, with no client-side polling interval to tune. In practice, fills are delivered with the latency of the destination chain — typically a few hundred ms. The 30 s default is just an upper bound; you almost always return earlier.
Pass the key as the ?apiKey= query param (not an Authorization header). Don’t add a client-side sleep — the server already blocks until something happens; firing again with no delay keeps one open long-poll waiting for the next state change.

Stale-response handling

If you start a new bridge while a previous /wait is still in flight, the previous response will arrive after your new intentId is active. Track the active intent ID client-side and discard any /wait result that doesn’t match it — otherwise you’ll attach an old fill TX to the new attempt.

Best practice: don’t block completion on the fill hash (Hyperliquid)

A Hyperliquid-destination fill is final the instant the funds leave HL, but HL only assigns the canonical L1 transaction hash a moment later. The solver therefore marks the intent filled immediately and patches fillTxHash in afterward — so a filled response can briefly carry fillTxHash: null with fillTxHashPending: true. Show the user “bridge complete” as soon as status is filleddo not wait on the hash. Then, only if you want an explorer link, make a second long-poll with ?waitForFillTxHash=true and update your UI when the hash lands:
Every other destination returns a real fillTxHash up front (fillTxHashPending: false), so the second call returns immediately and this branch is a no-op.

Live updates over WebSocket

bridge-status is the push equivalent of this endpoint: subscribe to an intent and the server sends its status now, then again on every transition — including the intermediate ones (pendingfillingfilled) that a one-shot long-poll can’t report. It’s a channel on the standard Mobula gateway (wss://api.mobula.io), so the subscribe / unsubscribe contract is the same as every other stream and one connection can carry bridge tracking alongside your market subscriptions.

Subscribe

Frames

data is byte-for-byte the data of GET /status/{id} — same fields, same fillTxHashPending semantics, same failureReason. A frame is sent only when something actually changed, so an intent that sits in filling stays quiet rather than repeating itself. Frames are pushed, not polled: the solver announces each transition the moment it commits it and the server forwards it straight to your socket. Expect a frame within a few milliseconds of the state change on-chain — ahead of what /status/{id}/wait can return, and far ahead of any client-side polling loop. final is true on the last frame an intent will ever produce — its status reached filled, settled, refunded or failed. The server then stops tracking that id: there is nothing left to unsubscribe from, and re-subscribing to it simply replays the terminal row. If the id has no row yet (deposit broadcast but not yet indexed) you get no frame until one exists — the subscription is live and waiting, exactly like the pending reply on the REST endpoint.

Unsubscribe

Omit subscriptionId to drop every bridge-status subscription on the connection. Everything is released automatically when the socket closes.

Example

WebSocket or /wait?

Both are push — neither makes you poll. Use the WebSocket when you want the progress (a status bar that moves through filling), when you’re following several bridges at once, or when you already hold a gateway connection. Use /status/{id}/wait when a single request that returns the finished bridge is all you need — a script, a server-side flow, a backend with no socket to spare.

Example

See the Bridge Implementation guide for the full no-sleep while(true) polling loop and how to handle stale responses when running multiple bridges in parallel.

Path Parameters

id
string
required

Intent ID (0x + 64 hex), deposit TX hash, or fill TX hash.

Response

200 - application/json

Bridge intent status. Returns status="pending" with a message when the intent has not yet been detected on-chain.

data
object
required