Order lifecycle
Save orderId and sessionId when creating an order. Use customerState for progress and available actions, and status for the overall outcome.
Read the current order
| Order | REST read | Optional WebSocket |
|---|---|---|
| Swap | GET /v2/swaps/{id} | GET /v2/swaps/{id}/events |
| Native bridge | GET /v2/bridges/{id} | GET /v2/bridges/{id}/events |
Send X-Session-ID, or use ?verify=<destination-address> for one read-only order. Missing orders and invalid access proof both return 404. See live updates for WebSockets.
Statuses
| Status | What to show |
|---|---|
awaiting_deposit | Returned funding instructions; check for a partial-deposit notice. |
awaiting_xmr1, awaiting_trx1 | Wrapped-asset funding instructions. |
processing | Progress from customerState; keep tracking. |
completed | Resolved outcome and actual output. |
failed, expired | Failure or expiry, unless customerState supplies a recovery state or action. |
refunded | Refund completed. |
needs_review | Legacy status: treat as processing. |
processing can include an unconfirmed deposit. Use optional confirmations and requiredConfirmations for confirmation progress; do not estimate completion from elapsed time.
Pauses and customer actions
Only customerState.kind: "action_required" enables an action. Its supported actions are coinflip, refund_address, and payout_address. Use the corresponding resource for form data.
A paused state can mean preparing_refund or below_minimum; neither is a completed failure. Continue tracking. A checking notice is informational and requires no separate action.
What arrived versus what was asked
depositAmount is the requested amount. Optional observedDepositAmount on swap reads is what arrived, in the same atomic unit. Use the observed amount for “you sent.” Every transfer to the deposit address counts toward it: a second transfer adds to the first, it is never a separate deposit.
expectedOutput is the quote for the requested amount. When what arrived differs from the request, in either direction, optional fundedExpectedOutput is that quote rescaled to the observed amount, in atomic units of toToken. Use it for “you receive” until actualOutput exists. It is an estimate: the order executes on what arrived at the price at execution time.
expiresAt is the funding deadline: send the deposit before it. For a token deposit it is also the exact moment a short deposit's top-up wait ends, so a countdown to it is precise.
Deposit outcomes
| What arrives | customerState | What happens |
|---|---|---|
At least 99% of depositAmount, or more | processing | The order executes on everything that arrived. An overpayment is swapped in full, not refunded. |
| Token deposit (EVM, Solana, Tron, Bitcoin) under 99% | awaiting_deposit, notice below_expected | The customer can top up the same address until expiresAt. Then the order continues on what arrived; a remainder worth less than $10 expires instead and support returns it. |
| Native-coin deposit (XMR, ZEC) at or above the order minimum | processing once seen | The order executes on what confirms; there is no top-up wait against depositAmount. |
| Native-coin deposit under the order minimum | awaiting_deposit, notice below_minimum | Send the rest to the same address now: a top-up before the deposit confirms joins it, and the order continues once the total reaches notice.minimumDepositAmount. A small deposit that confirms under the minimum on its own is set aside; support returns it. |
| A deposit parked under its minimum | paused, reason below_minimum | When minimumDepositAmount is present, a top-up to the same address that reaches it continues the order automatically. Without it, contact support. |
Nothing by expiresAt | expired | The address stays watched; support recovers a late deposit. |
The notices carry every number a screen needs: observedDepositAmount is what arrived, and the difference to depositAmount or minimumDepositAmount is what is left to send. minimumDepositAmount is in the deposit asset's atomic units. Under 1% of depositAmount is treated as stray dust and shows no notice.
Continuing early
POST /v2/orders/{id}/deposit-wait/close ends a below_expected wait now instead of at expiresAt. Send the owning X-Session-ID, or the confidential x-integrator-key of the integration the order was created with; a browser-embedded key cannot. Offer it only while below_expected is present; otherwise, and always for native-coin deposits, it returns 409. Repeating a close that already succeeded returns 200. It decides nothing by itself: the engine rechecks the deposit and continues on what arrived. You never need to call it — when the window ends, the order continues on its own.
Refund address submission
PUT /v2/orders/{id}/refund-address saves an eligible order's refund address. Show the form while refundRecovery.phase is address_required. That is action refund_address, with one exception: a table_deposit owed by a table that already finished (completed or refunded) keeps that outcome as its customerState, because the deposit it never used is returned on its own. Show the form beside the result. Submission queues automatic recovery. The engine rechecks eligibility and starts the refund once its safety checks pass; keep tracking until the recovery is gone (refunded when it was the order's own outcome). No separate integrator recovery call is needed.
Use refundRecovery (asset, chain, amount, phase) to describe the recovery. Its kind says what is being returned: wrong_chain (a deposit on the wrong chain), source (a source deposit whose route can never run), or table_deposit (a coinflip deposit the table never used: under the minimum stake, or sent after the table closed). When present, suggestedAddress is an address the order already has on file for that chain (for table_deposit, the table's payout address). Prefill the field with it and let the customer confirm or replace it. Nothing is sent to it until it is submitted. The saved destination is immutable. See actions and retries.
Replacement payout address submission
When action is payout_address, call PUT /v2/orders/{id}/payout-address with {"payoutAddress":"..."} and the owning X-Session-ID. The integrator API key alone does not authorize address changes. The replacement is write-once; resubmitting the same address is idempotent.
Both address endpoints queue an immediate recovery check after saving. Eligible recovery proceeds automatically using the saved address, with no operator click or separate integrator call. If checks are blocked or enqueueing is temporarily unavailable, the scheduled reconciler checks again (every 15 minutes by default). Existing broadcast, policy, custody, and output-protection checks still apply; exceptions requiring a separate operator decision remain manual. When both are pending, an explicit refund request takes priority over automatic payout recovery.
A successful address response confirms the save, not a completed payment. Continue polling the order or using its event stream until the terminal outcome is confirmed.
Session lists and bulk reads
GET /v2/orders with X-Session-ID lists the session's orders. Rows omit customerState and can lag behind detail reads: use the per-order endpoint before presenting an action. Bridge rows include optional asset and direction; use product to distinguish swaps and bridges.
Hyperliquid execution hashes
Execution receipts and pagination
Swap details can include up to 200 saved fills in hlFills. Deduplicate by tradeId, not the optional txHash: multiple fills may share a hash. This execution hash is separate from deposit and payout hashes.
hlFillsStatus is pending, complete, or incomplete. Collection runs independently of payouts and retries automatically. Missing hashes are omitted; unavailable historical receipts may remain incomplete.
For older fills, call GET /v2/swaps/:id/fills with the same session or destination proof. It returns { fills, status, nextCursor }. Send nextCursor as before; limit accepts 1–200 and defaults to 200. Order detail exposes the cursor as hlFillsNextCursor.
Pages follow receipt collection order, newest first; each page sorts fills by execution time. A null cursor means no older saved receipts, not completed collection. Use terminal order status and actualOutput for the customer's payout; its unit is deliveredToken when that field is present (a route that delivered a different asset of the same value), otherwise toToken.