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

# Hyperliquid compatibility

> Every Hyperliquid request type the facade accepts, what it maps to, and every difference an unmodified client will meet.

The facade at `https://api.gains.trade/hl/{chain}` (`https://api-testnet.gains.trade/hl/arbitrum-sepolia` on testnet, `wss://api.gains.trade/hl/{chain}/ws` for the stream) speaks Hyperliquid's `POST /info`, `POST /exchange` and WebSocket protocol, verifies Hyperliquid's own signing scheme, and forwards to the native Gains API. It never renames a Hyperliquid field. Gains-only information appears as extra fields that a Hyperliquid client ignores.

<Info>
  Only the subset that integrators actually use is implemented. Anything else returns a Hyperliquid-shaped empty result or error, never a different schema.
</Info>

## Before the first order

1. `approveAgent` (user-signed, `HyperliquidTransaction:ApproveAgent`) registers the agent with full trading scope. The response is Hyperliquid's `{"status":"ok","response":{"type":"default"}}` plus one extra field, `delegationTx`.
2. The master wallet sends `delegationTx` (`setTradingDelegate(relayer)` on the Gains Diamond, once per chain). Until it is mined, L1 actions answer `{"status":"err","response":"L1 error: API Wallet 0x... is not yet the on-chain delegate of its user. ..."}` with `delegationTx` repeated.
3. The master wallet approves the Diamond for USDC once.

This on-chain step does not exist on Hyperliquid and cannot be hidden: Gains is non-custodial and the delegation is the trader's own transaction. The facade is the one place Gains relays and pays gas, because Hyperliquid SDKs only sign typed data; native integrations broadcast their own transactions. `hyperliquidChain` may be `Mainnet` or `Testnet`: an SDK pointed at a custom base URL signs as `Testnet`, and the facade accepts it.

## Conventions

| Hyperliquid  | On the facade                                                                                                                                                                       |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Asset id `a` | The Gains `pairIndex`, identical to `meta.universe` index.                                                                                                                          |
| `coin`       | `BTC`, `ETH`, ... for USD-quoted markets; `EUR-JPY` style for other quotes.                                                                                                         |
| `szDecimals` | `min(sizePrecision, 6)` of the market. Prices are accepted up to the market's `pricePrecision`; more decimals answer the Hyperliquid error `Price must be divisible by tick size.`. |
| Nonce        | Millisecond timestamp, unique per agent, inside the Hyperliquid window (2 days back, 1 day ahead).                                                                                  |
| `oid`        | The native order `id` as a number. The same id works on `GET /v1/{chain}/orders/{id}`.                                                                                              |
| Leverage     | Set with `updateLeverage` per asset before ordering. Unset means the market's minimum leverage. Cross (`isCross: true`) answers an error.                                           |
| Collateral   | USDC.                                                                                                                                                                               |

## `POST /info`

| `type`                                  | Backed by                           | Notes                                                                                                                                                                                                                                                                    |
| --------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `meta`, `metaAndAssetCtxs`              | `GET /markets`, prices, 24 h trades | `marginTables` has one table per distinct max leverage; `onlyIsolated: true`, `marginMode: "noCross"` on every asset. `dayNtlVlm` and `dayBaseVlm` from the last 24 h of executed trades; `openInterest` in base units; `funding` is the hourly long rate as a fraction. |
| `allMids`                               | `GET /prices`                       | Mark prices.                                                                                                                                                                                                                                                             |
| `l2Book`                                | `GET /markets/{symbol}/book`        | The virtual book, 20 levels per side, `n: 1` on every level. `nSigFigs` and `mantissa` are accepted and ignored.                                                                                                                                                         |
| `candleSnapshot`                        | `GET /markets/{symbol}/candles`     | Intervals `1m 5m 15m 30m 1h 4h 1d`; others return `[]`. `v: "0.0"`, `n: 0`.                                                                                                                                                                                              |
| `clearinghouseState`                    | account + positions                 | Isolated positions in `assetPositions[]`; `crossMarginSummary` zeroed; `withdrawable` is the wallet balance in collateral.                                                                                                                                               |
| `openOrders`, `frontendOpenOrders`      | `GET /account/{address}/orders`     | Pending market requests are listed with `orderType: "Market"`.                                                                                                                                                                                                           |
| `userFills`, `userFillsByTime`          | `GET /account/{address}/fills`      | 500 most recent; `fee: "0.0"` (fees are in `closedPnl`), `startPosition: "0.0"`.                                                                                                                                                                                         |
| `orderStatus`                           | `GET /orders/{id}`                  | `oid` as number or cloid. Statuses: `pending`, `open`, `filled`, `rejected`, `timedOut`, `canceled`. `pending` and `timedOut` do not exist on Hyperliquid.                                                                                                               |
| `historicalOrders`                      | order history                       | Orders placed through the API.                                                                                                                                                                                                                                           |
| `userFunding`                           |                                     | Always `[]` in v1.                                                                                                                                                                                                                                                       |
| `fundingHistory`                        | `GET /markets/{symbol}/funding`     | One entry with the current rate.                                                                                                                                                                                                                                         |
| `userRateLimit`, `userFees`, `referral` | gateway, fee tier, referrer         | Shapes preserved, values from Gains.                                                                                                                                                                                                                                     |
| `spotMeta`, `spotClearinghouseState`    |                                     | `{"tokens":[],"universe":[]}` and `{"balances":[]}`.                                                                                                                                                                                                                     |
| `subAccounts`, `vaultDetails`           |                                     | `null`, as Hyperliquid returns when there are none.                                                                                                                                                                                                                      |

Unknown `type` answers `422` with the text `Failed to deserialize the JSON body into the target type`, like Hyperliquid. An unknown `coin` answers `200` with `null`.

## `POST /exchange`

Envelope `{action, nonce, signature, vaultAddress?, expiresAfter?}`. L1 actions are hashed exactly as the Hyperliquid Python SDK does (msgpack of the action in key order, nonce, vault marker, optional `expiresAfter`) and verified as the phantom agent `Agent{source, connectionId}` on chain id 1337, `source` `a` on mainnet chains and `b` on testnet. User-signed actions use the `HyperliquidSignTransaction` domain with the client's `signatureChainId`. The verification is tested against the official SDK's signing vectors.

| `action.type`                                                                             | Native call                          | Notes                                                                                                                                                                                                                                                                                                                                                                           |
| ----------------------------------------------------------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `order`                                                                                   | `POST /orders`                       | `Ioc`/`FrontendMarket`, or `Gtc` at a marketable price, become market orders with `slippage` derived from `p`. Non-marketable `Gtc` becomes a limit order; `Alo` at a marketable price answers the post-only error. `t.trigger` with `r: true` or `grouping: positionTpsl` sets the position's SL or TP; a non-reduce-only trigger becomes a stop order. `c` is the `clientId`. |
| `cancel`, `cancelByCloid`                                                                 | `DELETE /orders/{id}`                | `f` accepted.                                                                                                                                                                                                                                                                                                                                                                   |
| `modify`, `batchModify`                                                                   | `PATCH /orders/{id}`                 | Price only; size changes answer an error.                                                                                                                                                                                                                                                                                                                                       |
| `updateLeverage`                                                                          | preference + `PATCH /positions/{id}` | Stored per asset for later orders; applied to an open position on that asset. `isCross: true` answers an error.                                                                                                                                                                                                                                                                 |
| `updateIsolatedMargin`                                                                    | `PATCH /positions/{id}`              | `ntli` in USDC millionths, positive adds, negative removes.                                                                                                                                                                                                                                                                                                                     |
| `approveAgent`                                                                            | `POST /agents`                       | Full scope, name and `valid_until` expiry honoured.                                                                                                                                                                                                                                                                                                                             |
| `approveBuilderFee`, `setReferrer`, `scheduleCancel`                                      |                                      | Accepted, answer `default`. Dead man's switch is not enforced in v1.                                                                                                                                                                                                                                                                                                            |
| `twapOrder`, `twapCancel`                                                                 |                                      | `{"status":"err","response":"TWAP orders are not supported yet on Gains."}`                                                                                                                                                                                                                                                                                                     |
| `usdSend`, `withdraw3`, `spotSend`, `usdClassTransfer`, `sendAsset`, vaults, sub-accounts |                                      | `{"status":"err","response":"Gains is non-custodial: ..."}`. Funds never leave the wallet.                                                                                                                                                                                                                                                                                      |

### Responses

Order statuses use Hyperliquid's shapes with one addition for the oracle step:

```json theme={null}
{"status":"ok","response":{"type":"order","data":{"statuses":[
  {"pending":{"oid":5316911983139663,"txHash":"0x...","cloid":"0x..."}},
  {"resting":{"oid":5316911983139664}},
  {"error":"Order must have minimum value of $10."}
]}}}
```

`filled` appears on `orderStatus` and `orderUpdates` once the oracle answers, never synchronously: a market order on Gains is `pending` for a few seconds.

## WebSocket

`{"method":"subscribe","subscription":{...}}`, `unsubscribe`, `ping`/`pong` (`{"channel":"pong"}`) and `post` (info and action) as on Hyperliquid. Subscriptions: `allMids`, `l2Book`, `bbo`, `trades`, `candle`, `activeAssetCtx`, `orderUpdates`, `userEvents` (delivered on channel `user`), `userFills` (with `isSnapshot`), `userFundings` (empty snapshot), `notification`, `clearinghouseState`, `openOrders`. `webData2`/`webData3`, `twapStates`, `userNonFundingLedgerUpdates`, `activeAssetData`, spot and vault channels are not available.

`orderUpdates` carries `status: "pending"` then `filled` or `timedOut`.

## Differences at a glance

|                                                           | Hyperliquid                       | Facade                                                                       |
| --------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------- |
| Execution                                                 | Matching engine, synchronous fill | Oracle fill within seconds; `pending` first                                  |
| Agent approval                                            | `approveAgent` only               | `approveAgent` plus one on-chain `setTradingDelegate` by the master wallet   |
| Cross margin, vaults, sub-accounts, spot, transfers, TWAP | Yes                               | No (isolated only; custody stays in the wallet)                              |
| Book                                                      | Real                              | Virtual, from depth bands                                                    |
| `userFunding` history                                     | Yes                               | Empty in v1                                                                  |
| Rate limits                                               | Address-based on volume           | Per IP and per agent, see [Errors and limits](/developer/trading-api/errors) |
