> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gains.trade/llms.txt
> Use this file to discover all available pages before exploring further.

# Orders and positions

> Order types, units and precision, the oracle-backed lifecycle, and how to manage open positions.

## Units

| Field               | Unit                                         | Example                                                                                                                                                                                                     |
| ------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `size`              | Base asset of the market, decimal string     | `"0.25"` BTC on `BTC/USD`                                                                                                                                                                                   |
| `price`, `sl`, `tp` | Quote currency of the market, decimal string | `"65000.5"`                                                                                                                                                                                                 |
| `leverage`          | Multiplier, decimal string                   | `"10"`                                                                                                                                                                                                      |
| `slippage`          | Percent, decimal string                      | `"1"` means 1 %                                                                                                                                                                                             |
| `collateral`        | Collateral token symbol                      | `"USDC"`, `"DAI"`, `"WETH"`, `"GNS"` where the chain supports it. Omitted: USDC where the chain lists it, otherwise the chain's single active collateral (`GET /v1/{chain}/markets` lists `collaterals[]`). |

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

| `type`   | `price`                                             | Behaviour                                                                                     |
| -------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `market` | optional expected price, defaults to the mark price | Sent to the oracle at once. Filled at the oracle price, bounded by `slippage` around `price`. |
| `limit`  | required trigger price                              | Rests on-chain. A long triggers when the price falls to `price`, a short when it rises to it. |
| `stop`   | required trigger price                              | Rests on-chain. A long triggers when the price rises to `price`, a short when it falls to it. |

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

```json theme={null}
{
  "order": { "id": "5316911983139663", "status": "prepared", "expiresAt": 1788857728819, "...": "..." },
  "transaction": {
    "to": "0xFF162c694eAA571f685030649814282eA457f169",
    "data": "0x737b84cd...",
    "value": "0",
    "chainId": 42161,
    "gas": "1807117",
    "expiresAt": 1788857728819
  }
}
```

`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 ──► prepared ──► pending ──► filled
              (you sign and     │           (fill: price, size, collateral, feeCollateral, positionId, txHash)
               broadcast)       ├──► rejected   (reason: SLIPPAGE, EXPOSURE_LIMITS, PRICE_IMPACT, MAX_LEVERAGE, ...)
                                └──► timed_out  (reclaim with DELETE /orders/{id}; reclaimTxHash on the order)

POST /orders (limit, stop) ──► prepared ──► open ──► filled | canceled

prepared, never broadcast before expiresAt ──► expired
```

`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:

| Reason                               | Meaning                                                                        |
| ------------------------------------ | ------------------------------------------------------------------------------ |
| `SLIPPAGE`                           | The oracle price left the `slippage` band around the expected price.           |
| `EXPOSURE_LIMITS`                    | The market's open-interest cap would be exceeded.                              |
| `PRICE_IMPACT`                       | The price impact of the size exceeds the market's limit.                       |
| `MAX_LEVERAGE`                       | Leverage above the market's maximum at execution.                              |
| `TP_REACHED`, `SL_REACHED`           | The attached take profit or stop loss was already past the execution price.    |
| `NO_TRADE`, `WRONG_TRADE`, `NOT_HIT` | Close or trigger requests that no longer match an open trade or a hit trigger. |

Anything rejected *before* the transaction is sent (precision, scope, simulation) comes back as an HTTP error, see [Errors](/developer/trading-api/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.

| Endpoint                                                                       | Effect                                                                                                                                                                                                                   |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `POST /positions/{id}/close`                                                   | Market close. `size` (base asset) for a partial close, omit for a full close. Returns the prepared close transaction and a `prepared` close order; after broadcast and submit it is `pending` until the oracle fills it. |
| `PATCH /positions/{id}` with `sl` and/or `tp`                                  | Moves the stop loss and take profit.                                                                                                                                                                                     |
| `PATCH /positions/{id}` with `leverage`                                        | Changes the leverage; the contracts pull or return collateral to keep the notional.                                                                                                                                      |
| `PATCH /positions/{id}` with `collateral: {action: "add" \| "remove", amount}` | Adds or removes collateral while keeping the notional, which is the same operation expressed as an amount.                                                                                                               |

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