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

# Positions and accounts

> Read open positions, account balances, account settings, and adjust leverage

Read your position state, account balances, and per-market settings across every connected exchange.

<Info>
  **Prerequisites:** an active VOOI API token and at least one connected exchange. See [API Tokens](/docs/tokens) and [Use your own keys](/docs/exchanges) if you don't have them yet.
</Info>

## Positions

[`GET /exchange/positions`](/docs/api-reference/exchange/get-open-positions) — open positions across every connected exchange, including entry price, leverage, liquidation price, and unrealized PnL. `fundingFee` is a nullable position field returned on every venue. `liquidationPrice` is also nullable on every venue, and on every venue it is an **estimate**. VOOI normalizes it so that a cross-margin position's figure reflects the rest of the account rather than that market in isolation, so it can differ from the number the venue's own interface shows. Treat it as indicative — never as the exact price at which the venue will liquidate.

## Account balances

[`GET /exchange/accounts`](/docs/api-reference/exchange/get-account-balances) — one row per sub-account with total balance, available margin, margin in use, withdrawable amount, and the quote token denominating those balances. Aster, Lighter, Robinhood, Extended, Binance, MEXC, and Ondo return a single `"perps"` row per connection. Bybit returns one `"perps"` row per settle coin it holds (USDT and USDC). Hyperliquid returns spot rows for USDC and USDH plus a row per perp DEX; the row set depends on the [abstraction mode](/docs/hyperliquid-account#account-abstraction-mode). Read `type`, `token`, and `exchange` together to identify a row.

### Field semantics

Every amount is a decimal string in the quote token reported on the same row — read `token` to know which one.

* `totalBalance` — the venue's notion of account value: free funds plus funds locked by open orders and positions. This is the right field to show as the account's bottom-line "equity". The API does not expose a separate `equity` field.
* `marginInUse` — the portion of `totalBalance` currently locked as initial margin behind open positions and resting orders.
* `availableMargin` — what the venue will let you use to open **new** positions. Roughly `totalBalance − marginInUse`, but each venue applies its own haircuts.
* `withdrawable` — what the venue will let you **withdraw right now**. This is usually smaller than `availableMargin` — venues reserve extra margin behind open positions, pending funding, and in-flight transfers. Showing `withdrawable` as "free" in a portfolio UI overstates what the user can actually deploy into a new trade; use `availableMargin` for that and reserve `withdrawable` for a withdraw screen.
* `token` — the quote token denominating the four balance fields above. Aster always reports `"USDT"` for the whole account (including positions on its USD1 pairs); Lighter and Robinhood report `"USDC"`; Extended reports `"USD"`; MEXC reports `"USDT"`; Ondo reports `"USDC"`; Bybit reports the settle coin of the row (`"USDT"` or `"USDC"`). Hyperliquid reports `"USDC"` for USDC-quoted buckets (default perp DEX and the [HIP-3 DEXes](/docs/trading-markets#hyperliquid-hip-3-dexes) it currently surfaces, plus USDC spot) and `"USDH"` for the USDH spot row. Don't sum balances across rows with different `token` values without converting — they're different units.
* `type` — row classification within the exchange. Aster, Lighter, Robinhood, Extended, Binance, Bybit, MEXC, and Ondo return `"perps"`. Hyperliquid returns `"perps"` (default USDC perp DEX), `"perps:xyz"` ([trade.xyz](/docs/trading-markets#hyperliquid-hip-3-dexes)), `"perps:mkts"`, or `"spot"` for a Hyperliquid spot balance. Treat unknown values as opaque.

### How many rows to expect on Hyperliquid

| Abstraction mode | Rows |
| - | - |
| `disabled`, `default`, `portfolioMargin`, `dexAbstraction` | Two `"spot"` rows (USDC and USDH) plus one row per perp DEX (`"perps"`, `"perps:xyz"`, `"perps:mkts"`). |
| `unifiedAccount` | Two `"spot"` rows (USDC and USDH). Spot balances back perp positions on every DEX — no separate perp rows. |

Any mode other than `unifiedAccount` — including `default` (never explicitly set) — returns the per-DEX perp rows.

Unfunded buckets still appear with zero balances. The `(exchange, type, token)` triple uniquely identifies each row across both REST and SSE. To track "Hyperliquid total equity" across modes, sum `totalBalance` per `token` and treat the result as USDC-equivalent (USDH is pegged 1:1).

Unrealized PnL does **not** live on the account row — it's a per-position figure, returned by [`GET /exchange/positions`](/docs/api-reference/exchange/get-open-positions). Funding accruals are already reflected in the venue's balance numbers by the time you read them; there is no separate funding-accrual field on the account.

### Which venues appear

Only **connected** venues show up. A venue the user has not connected — via [Use your own keys](/docs/exchanges) or one of the [registration flows](/docs/exchanges#registration-flows) — contributes no rows at all, not a zero row. If your UI always wants a placeholder per supported venue, render the missing ones on the client.

## Account settings

[`GET /exchange/account-info`](/docs/api-reference/exchange/get-account-settings-aster-returns-hedge-mode-margin-type-multi-assets-margin-hyperliquid-returns-the-abstraction-mode-extended-returns-the-applied-referral-code-bybit-returns-the-margin-mode-unified-account-balances-and-the-account-upgrade-status-lighter-and-robinhood-return-the-account-fee-tier-and-the-fees-it-charges) — venue-shaped account configuration. Required `exchange` query parameter selects the venue; the response shape depends on the value:

* **Aster** — hedge-mode flag, multi-assets margin flag, and the per-market margin type map (`cross` or `isolated`).
* **Hyperliquid** — `abstractionMode` controlling spot + perp collateral. See [Hyperliquid account](/docs/hyperliquid-account#account-abstraction-mode) for the four modes and how to change them.
* **Extended** — the applied referral code.
* **Lighter** and **Robinhood** — the account's fee tier (`accountTier`) and the maker and taker fees that tier currently charges, in bps. See [Account fee tier](#account-fee-tier) below.
* **Bybit** — the margin mode applied to the whole unified account (`cross` or `isolated`) and `unifiedMarginStatus`, Bybit's account upgrade status. Only unified statuses are tradable.

## Account fee tier

Lighter and Robinhood run their accounts on fee tiers. Read the current tier from [`GET /exchange/account-info`](/docs/api-reference/exchange/get-account-settings-aster-returns-hedge-mode-margin-type-multi-assets-margin-hyperliquid-returns-the-abstraction-mode-extended-returns-the-applied-referral-code-bybit-returns-the-margin-mode-unified-account-balances-and-the-account-upgrade-status-lighter-and-robinhood-return-the-account-fee-tier-and-the-fees-it-charges) and change it with [`POST /exchange/lighter/account-tier`](/docs/api-reference/exchange-lighter/set-the-account-fee-tier), which takes `{ exchange, tier }` — `exchange` selecting the deployment (`lighter` or `robinhood`).

| Tier | Charges | Available on |
| - | - | - |
| `standard` | No fees | Lighter, Robinhood |
| `premium` | Stake-tiered fees on Lighter, volume-tiered on Robinhood | Lighter, Robinhood |
| `plus` | Flat fees, in exchange for higher rate limits | Lighter only |

The tier is tied to your L1 address, so sub-accounts inherit it.

<Note>
  A tier change the venue refuses — most often the 24-hour cooldown between changes, or a tier that deployment doesn't run — comes back as a `503` with the venue's reason in `message`, not a `400`. A `404` means that deployment isn't connected for this user.
</Note>

## Market settings

* [`GET /exchange/market-settings`](/docs/api-reference/exchange/get-current-user-settings-for-a-market) — current leverage and margin mode for one `(exchange, asset)` pair.
* [`POST /exchange/leverage`](/docs/api-reference/exchange/set-leverage-for-a-market) — change leverage for a market.
* [`POST /exchange/margin-mode`](/docs/api-reference/exchange/set-margin-mode-for-a-market) — switch between `cross` and `isolated` margin for a market. Not supported on Lighter — the call is rejected there.

[`POST /exchange/leverage`](/docs/api-reference/exchange/set-leverage-for-a-market) accepts any positive number, not just an integer. Extended and Lighter honor fractional values (for example `12.5`); Hyperliquid still requires an integer and rejects fractional leverage.

<Note>
  **There is no `GET /exchange/leverage`.** Leverage and margin mode are read together from [`GET /exchange/market-settings`](/docs/api-reference/exchange/get-current-user-settings-for-a-market). If you're porting from Binance, Bybit, OKX, or another venue where reads and writes share the `/leverage` path, this is the only mapping that differs — the two writes (`POST /exchange/leverage`, `POST /exchange/margin-mode`) keep the names you expect.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Orders" icon="list" href="/docs/trading-orders">
    Place and cancel orders
  </Card>

  <Card title="Quotes and slippage" icon="calculator" href="/docs/trading-quotes">
    Simulate trades before placing them
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.