Skip to main content

Units

The API derives the collateral amount from size × price / leverage, converted to the collateral token at its USD price. Fills report the executed size, price and collateral in the same units. Precision is published per market in GET /markets: pricePrecision and sizePrecision are the maximum number of decimals. A value with more decimals is rejected with 422 PRECISION_ERROR; nothing is rounded for you. minPositionUsd is the smallest notional the contracts accept.

Order types

sl and tp attach a stop loss and take profit to the resulting position. reduceOnly: true with a market order closes (fully or partially) the position on the opposite side of the same market instead of opening; there is no reduce-only resting order on Gains, use sl/tp on the position for that.

Signing and broadcasting

Every write answers with a transaction object and never sends anything itself: the agent key (or the trader’s wallet) signs it, pays the gas and broadcasts it. The object is the shape wallets and the 0x or Uniswap trade APIs use, so walletClient.sendTransaction(transaction) is all it takes; the SDK does it for you when it is built with a sender.
value is always zero: fees come out of the collateral. Do not fill a nonce or fee fields, the wallet does. The agent needs ETH on the chain for gas; the API tells you when it cannot estimate (gas: null), which usually means an empty agent.

Lifecycle

POST /orders validates the order, checks the agent scope, simulates it from the agent and answers 201 with the order in prepared state under its final id, plus the transaction to sign and broadcast: to (the Diamond), data, value: "0", chainId, a gas estimate (null when the agent has no ETH yet) and expiresAt. Broadcast it with the agent key, then POST /orders/{id}/submit with the hash: the order becomes pending (market) or open (limit, stop), and the receipt is checked, so a reverted transaction reads rejected. The API watches the chain too: a transaction that lands without the submit call still moves the order on, and if the Diamond assigned another index than predicted the order is re-keyed to it. A prepared order not broadcast before expiresAt reads as expired; prepare it again. The oracle answers within seconds (~60 seconds is the on-chain timeout). Track the id with:
  • GET /v1/{chain}/orders/{id}, which returns the same object with the current status;
  • the orders WebSocket channel, which pushes every transition and the fills channel, which pushes fills only;
  • order.waitForFill() in the SDK, which polls and throws on any terminal state other than filled.
The id is stable for the whole lifecycle and identical on the native API and on the Hyperliquid facade (oid). Once filled, fill.positionId is the id of the open position.

Idempotency

Pass a clientId (up to 64 characters). Re-sending the same order with the same clientId returns the existing order instead of placing a second one; sending a different order with a used clientId answers 409 IDEMPOTENCY_CONFLICT. clientId is part of the signed body, so it cannot be forged.

Rejections

reason on a rejected order is the on-chain cancel reason: Anything rejected before the transaction is sent (precision, scope, simulation) comes back as an HTTP error, see Errors, and never creates an order.

Updating and cancelling orders

PATCH /v1/{chain}/orders/{id} prepares the update of a resting limit or stop order: price, sl, tp, slippage. Changing the size means cancel and re-create. PATCH /v1/{chain}/positions/{id} prepares sl, tp, leverage or collateral changes the same way and returns the position with the transaction. DELETE /v1/{chain}/orders/{id} prepares the cancel of a resting order, or the reclaim of a pending market request once the oracle timeout has elapsed (409 ORDER_NOT_MODIFIABLE before that, with reclaimableAtBlock in the details). The agent broadcasts it; the status follows the chain event (canceled, or timed_out with reclaimTxHash). Nobody reclaims for you: a request that timed out keeps its collateral locked until this transaction is sent. A prepared order that was never broadcast is withdrawn without a transaction (transaction: null, status expired).

Positions

GET /v1/{chain}/account/{address}/positions returns every open position with live markPrice, liquidationPrice, unrealizedPnl, fundingFee and borrowingFee, computed with the same SDK math the trading interface uses. Position ids are derived from the trader and the on-chain trade index, so they are stable across API restarts and match the positionId of the fill that opened them.

Limits worth knowing

  • Isolated margin only in v1 (onlyIsolated: true on every market).
  • Position size increases go through POST /orders on the same market and side; the contracts merge them into the existing position.
  • Markets outside crypto close according to their session (isOpen on the market); orders on a closed market answer 422 MARKET_CLOSED.