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

# REST API

> Market data, trading, account, and wallet endpoints with parameters, examples, and response fields

Every endpoint is served through the gateway at `https://{API_BASE}`. Bodies are
JSON; prices and sizes are decimal strings. The auth tier for each endpoint is
noted inline — see [API overview](/api-reference/overview#authentication) for how
each tier works.

<Info>
  Enums used throughout: `side` = `buy | sell`; order `type` = `limit | market`;
  `timeInForce` = `gtc | ioc | fok`; `marginMode` = `isolated | cross`.
  `postOnly` rejects an order that would take liquidity; `reduceOnly` prevents an
  order from increasing your position.
</Info>

## Market data

Public — no credentials required.

### List markets

<ParamField query="—" type="none">
  `GET /perps/markets` (alias `GET /markets/linear`) — all linear markets: spot,
  perpetual, and dated futures. Expired dated futures are auto-excluded.
</ParamField>

<ResponseField name="[]" type="array">
  <Expandable title="market">
    <ResponseField name="id" type="string" />

    <ResponseField name="symbol" type="string" />

    <ResponseField name="marketType" type="string">`spot` | `perp` | `future`</ResponseField>

    <ResponseField name="baseSymbol" type="string" />

    <ResponseField name="quoteSymbol" type="string" />

    <ResponseField name="markPrice" type="string" />

    <ResponseField name="priceDecimals" type="number" />

    <ResponseField name="sizeDecimals" type="number" />

    <ResponseField name="expiry" type="string">Present on dated futures only.</ResponseField>
    <ResponseField name="indexMarketId" type="string">The market this one is indexed to.</ResponseField>
  </Expandable>
</ResponseField>

<CodeGroup>
  ```bash cURL theme={null}
  curl -s "https://{API_BASE}/perps/markets"
  ```

  ```js JavaScript theme={null}
  const markets = await fetch(`https://${API_BASE}/perps/markets`).then(r => r.json());
  ```
</CodeGroup>

```json Response theme={null}
[
  {
    "id": "BTC-PERP",
    "symbol": "BTC-PERP",
    "marketType": "perp",
    "baseSymbol": "BTC",
    "quoteSymbol": "USDC",
    "markPrice": "68210.5",
    "priceDecimals": 2,
    "sizeDecimals": 4,
    "indexMarketId": "BTC-USDC-SPOT"
  }
]
```

### Order book snapshot

<ParamField path="marketId" type="string" required>
  `GET /perps/orderbook/{marketId}` — aggregated book snapshot for a perp/linear
  market.
</ParamField>

<ParamField query="depth" type="number">
  Number of levels to return. Defaults to the full book.
</ParamField>

```json Response theme={null}
{ "bids": [["68200.0", "1.25"], ["68190.0", "3.00"]], "asks": [["68220.0", "0.80"]] }
```

For options and spot instruments, use `GET /orderbook/{marketId}` (alias
`GET /options/orderbook/{marketId}`), which returns the same `{ bids, asks }`
shape.

### Market stats

<ParamField query="marketId" type="string" required>
  `GET /perps/market-stats` — 24h ticker for one market.
</ParamField>

<ResponseField name="markPrice" type="string" />

<ResponseField name="change24hPct" type="string" />

<ResponseField name="volume24hUsd" type="string" />

<ResponseField name="openInterestUsd" type="string" />

<ResponseField name="funding1hPct" type="string">Current 1h funding rate as a percent.</ResponseField>

```bash theme={null}
curl -s "https://{API_BASE}/perps/market-stats?marketId=BTC-PERP"
```

### Candles (OHLCV)

<ParamField query="symbol" type="string" required>
  `GET /perps/ohlc` — candlestick history, TradingView-shaped. e.g. `BTC-PERP`.
</ParamField>

<ParamField query="resolution" type="string">`1 | 5 | 15 | 30 | 60 | 240 | D` (default `15`).</ParamField>
<ParamField query="from" type="number">Unix seconds. Range capped to 90 days.</ParamField>
<ParamField query="to" type="number">Unix seconds.</ParamField>

```json Response theme={null}
{ "s": "ok", "t": [1719878400], "o": ["68000"], "h": ["68300"], "l": ["67900"], "c": ["68210"], "v": ["120.5"] }
```

### Fees, insurance fund & DVOL

<ResponseField name="GET /perps/fees" type="endpoint">
  Perp fee-tier schedule: array of `{ min30dVolumeUsd, makerBps, takerBps }`. A
  negative maker bps is a rebate. Your personal tier is reflected in order
  preview.
</ResponseField>

<ResponseField name="GET /options/fees" type="endpoint">
  Options fee schedule.
</ResponseField>

<ResponseField name="GET /perps/insurance-fund" type="endpoint">
  Public insurance-fund balance and summary.
</ResponseField>

<ResponseField name="GET /markets/dvol" type="endpoint">
  30-day implied-volatility index. Query `underlying` (default `BTC`). Returns
  `{ underlying, dvol, tenorDays: 30, computedAt, sourceTimestamp }`.
</ResponseField>

### Options board

The option board is the single source for the chain and its implied-volatility
surface — every strike carries its mark, IV and Greeks, so there is no separate
surface endpoint.

<ParamField query="underlying" type="string">
  `GET /markets/board` — full option chain for an underlying with per-strike
  quotes, IV and Greeks. e.g. `BTC`. Omit for the primary underlying.
</ParamField>

<ResponseField name="underlyingPrice" type="string" />

<ResponseField name="underlyingSymbol" type="string" />

<ResponseField name="expiries" type="string[]" />

<ResponseField name="expiryForwards" type="object">
  Per-expiry `{ forwardPrice, futuresMarketId }` — each expiry is priced off its
  own forward.
</ResponseField>

<ResponseField name="options" type="array">
  <Expandable title="option">
    <ResponseField name="id" type="string" />

    <ResponseField name="type" type="string">`call` | `put`</ResponseField>

    <ResponseField name="strike" type="string" />

    <ResponseField name="expiry" type="string" />

    <ResponseField name="bid" type="string" />

    <ResponseField name="ask" type="string" />

    <ResponseField name="mark" type="string" />

    <ResponseField name="iv" type="string" />

    <ResponseField name="delta" type="string" />
  </Expandable>
</ResponseField>

<Note>
  Board `mark`, `iv`, and `delta` are OCX reference marks, published for pricing
  and risk. The tradable prices are always the order book. See
  [Options pricing](/methodology/options) for the concept.
</Note>

## Trading — perpetuals & futures

Perps and dated futures share one order API (a dated future is just a market
with an `expiry`).

### Place an order

<ParamField body="marketId" type="string" required />

<ParamField body="side" type="string" required>`buy` | `sell`</ParamField>

<ParamField body="quantity" type="string" required />

<ParamField body="type" type="string">`limit` (default) | `market`</ParamField>
<ParamField body="price" type="string">Required for `limit`.</ParamField>
<ParamField body="timeInForce" type="string">`gtc | ioc | fok`</ParamField>

<ParamField body="postOnly" type="boolean" />

<ParamField body="reduceOnly" type="boolean" />

<ParamField body="marginMode" type="string">`isolated | cross`</ParamField>

<ParamField body="clientOrderId" type="string" />

<ParamField body="stopPrice" type="string" />

<ParamField body="takeProfitPrice" type="string" />

<ParamField body="stopLossPrice" type="string" />

`POST /perps/orders` — **Session.** Returns the order object with resulting
fills and position.

<CodeGroup>
  ```bash cURL theme={null}
  curl -s -b cookies.txt -X POST "https://{API_BASE}/perps/orders" \
    -H "Content-Type: application/json" \
    -d '{
      "marketId": "BTC-PERP", "side": "buy", "type": "limit",
      "price": "68000", "quantity": "0.5", "timeInForce": "gtc", "postOnly": true
    }'
  ```

  ```js JavaScript theme={null}
  await fetch(`https://${API_BASE}/perps/orders`, {
    method: "POST",
    credentials: "include",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      marketId: "BTC-PERP", side: "buy", type: "limit",
      price: "68000", quantity: "0.5", timeInForce: "gtc", postOnly: true,
    }),
  });
  ```
</CodeGroup>

### Preview an order

`POST /perps/orders/preview` — **Session or API key.** Dry-run an order: margin
required, estimated fee, and approval, with no side effects. Same body shape as
a live order.

<ResponseField name="notional" type="string" />

<ResponseField name="marginRequired" type="string" />

<ResponseField name="estFee" type="string" />

<ResponseField name="feeBps" type="string" />

<ResponseField name="feeRole" type="string">`maker` | `taker`</ResponseField>
<ResponseField name="user30dVolume" type="string">Drives your fee tier.</ResponseField>

<ResponseField name="approved" type="boolean" />

<ResponseField name="reason" type="string">Present when `approved` is false.</ResponseField>

### Quotes and bulk quoting

<ResponseField name="POST /perps/quotes" type="endpoint">
  **Session.** Place a two-sided quote in one market:
  `{ marketId, bid?: { price, quantity, clientOrderId? }, ask?: { ... }, quoteId? }`.
</ResponseField>

<ResponseField name="POST /perps/quotes/bulk" type="endpoint">
  **Session or API key.** Replace a whole ladder atomically — the market-maker
  path. Set `cancelAll: true` to cancel your prior quotes and place the new set
  in one operation.
</ResponseField>

```json POST /perps/quotes/bulk theme={null}
{
  "marketId": "BTC-PERP",
  "quoteId": "mm-cycle-000123",
  "cancelAll": true,
  "quotes": [
    { "side": "buy",  "price": "67990", "quantity": "0.50", "postOnly": true },
    { "side": "sell", "price": "68010", "quantity": "0.50", "postOnly": true }
  ]
}
```

### Cancel and close

<ResponseField name="POST /perps/orders/{id}/cancel" type="endpoint">**Session.** Cancel one resting order.</ResponseField>

<ResponseField name="POST /perps/orders/cancel-all" type="endpoint">
  **Session or API key.** Cancel all your orders, optionally scoped by
  `{ marketId?, quoteId?, clientOrderId?, marginMode? }`. Wire this to your
  kill-switch.
</ResponseField>

<ResponseField name="POST /perps/positions/close" type="endpoint">
  **Session.** Close a position fully or partially:
  `{ marketId, quantity?, marginMode?, orderType?, price?, timeInForce? }`. Omit
  `quantity` to close fully.
</ResponseField>

## Trading — options & spot

Options and spot run on the central limit order-book engine. Single-instrument
orders use `/orders`; multi-leg strategies use `/orders/strategy`. Each path has
an `/options/…` alias.

### Single order

`POST /orders` (alias `POST /options/orders`) — **Session.**

<ParamField body="marketId" type="string" required />

<ParamField body="side" type="string" required>`buy` | `sell`</ParamField>

<ParamField body="quantity" type="string" required />

<ParamField body="price" type="string" required />

<ParamField body="type" type="string">`limit` (default) | `market`</ParamField>
<ParamField body="timeInForce" type="string">`gtc | ioc | fok`</ParamField>

<ParamField body="postOnly" type="boolean" />

<ParamField body="reduceOnly" type="boolean" />

<ParamField body="clientOrderId" type="string" />

```json POST /orders theme={null}
{ "marketId": "BTC-2026-05-15-40000-C", "side": "buy", "type": "limit",
  "price": "1240", "quantity": "5", "timeInForce": "gtc" }
```

Preview with `POST /orders/preview` (alias `/options/orders/preview`), amend a
resting order with `POST /options/orders/{id}/modify` (`{ price?, quantity? }`),
and cancel with `POST /orders/{id}/cancel` or `POST /orders/cancel-all`.

### Multi-leg strategy

`POST /orders/strategy` (alias `/options/orders/strategy`) — **Session.** Place a
combo (spread, straddle, …). Combos are **all-or-none-immediate**: every leg must
fully fill or the whole strategy is rejected (per-leg `timeInForce` is accepted
but ignored — combos are FOK).

<ParamField body="strategyName" type="string" />

<ParamField body="allOrNone" type="boolean" />

<ParamField body="cancelOnFailure" type="boolean" />

<ParamField body="legs" type="array" required>
  2–8 legs, each `{ market, side, quantity, price }`.
</ParamField>

```json POST /orders/strategy theme={null}
{
  "strategyName": "call-spread",
  "legs": [
    { "market": "BTC-2026-05-15-40000-C", "side": "buy",  "quantity": "5", "price": "1240" },
    { "market": "BTC-2026-05-15-45000-C", "side": "sell", "quantity": "5", "price": "430"  }
  ]
}
```

<ResponseField name="strategyId" type="string" />

<ResponseField name="fullyFilled" type="boolean" />

<ResponseField name="legs" type="array">Each `{ orderId, fills }`.</ResponseField>

Dry-run first with `POST /orders/strategy/preview`. Two-sided option quotes use
`POST /quotes` and `POST /quotes/bulk` (the bulk path accepts an API key).

## Account

Read your own orders, positions, trades, and portfolio. **Session** unless noted.

| Endpoint                  | Returns                                                               |
| ------------------------- | --------------------------------------------------------------------- |
| `GET /perps/orders`       | Your perp orders (`limit`, `marketId`, `marginMode`).                 |
| `GET /perps/orders/open`  | Your resting perp orders.                                             |
| `GET /perps/positions`    | Open positions: size, entry, mark, uPnL, liquidation price, leverage. |
| `GET /perps/trades`       | Your recent perp fills.                                               |
| `GET /orders/me`          | Your option/spot orders (alias `/options/orders/me`).                 |
| `GET /positions/me`       | Your option/spot positions.                                           |
| `GET /options/trades/me`  | Your option fills.                                                    |
| `GET /portfolio/me`       | Unified cross-venue portfolio (perps + options + balances).           |
| `GET /portfolio/balances` | Unified balance summary across venues.                                |

For live account state, prefer the streams — `GET /perps/stream/events`,
`GET /options/stream/events`, and `GET /portfolio/balances/stream` — documented
in [Streaming](/api-reference/websockets).

## Wallet

Funds live in four buckets: `wallet` (deposit/withdraw source), `perps`,
`options`, and `spot`. Move funds between buckets before trading in a venue.
All **Session**.

### Balances

<ResponseField name="GET /wallet/balance" type="endpoint">
  `{ onchainDepositTotal, walletBalance, perpsBalance, optionsBalance, pendingWithdrawalTotal }` — decimal strings.
</ResponseField>

<ResponseField name="GET /wallet/assets" type="endpoint">
  Per-asset inventory: array of `{ asset, bucket, available, locked, total }`.
</ResponseField>

<ResponseField name="GET /perps/balances" type="endpoint">
  Perp-venue balance and margin view.
</ResponseField>

### Transfer between buckets

<ParamField body="from" type="string" required>`wallet | perps | options | spot`</ParamField>
<ParamField body="to" type="string" required>A distinct bucket.</ParamField>
<ParamField body="amount" type="string" required>Positive; cannot exceed the source balance.</ParamField>

`POST /wallet/transfer` — atomic and double-entry ledgered.

```json POST /wallet/transfer theme={null}
{ "from": "wallet", "to": "perps", "amount": "500" }
→ { "walletBalance": "1500.00", "perpsBalance": "500.00", "optionsBalance": "0" }
```

### Withdraw

<ParamField body="amount" type="string" required>
  Must be ≤ your `wallet` balance. Transfer back from perps/options/spot first.
</ParamField>

`POST /wallet/withdraw` → `{ "withdrawalId": "…" }`. The amount is debited from
`wallet` immediately and the on-chain payout proceeds asynchronously.

### History & settlements

| Endpoint                       | Returns                                                                       |
| ------------------------------ | ----------------------------------------------------------------------------- |
| `GET /wallet/history`          | Ledger entries `{ id, type, amount, txHash, createdAt }`, newest first.       |
| `GET /wallet/settlements`      | Settlements; filter `kind` (`deposit`/`withdraw`), `status`, `limit` (1–200). |
| `GET /wallet/settlements/{id}` | One settlement record.                                                        |

Settlement `status` values: `pending`, `processing`, `sent`, `confirmed`,
`failed`, `insufficient_liquidity`.

<h2 id="api-keys">
  API keys
</h2>

Session-only — a key cannot manage keys. Scopes: `read`, `trade`.

<ResponseField name="GET /perps/me/api-keys" type="endpoint">
  List your keys (metadata only; secrets are never returned):
  `{ id, name, scope, allowedIps, expiresAt, createdAt, lastUsedAt, status }`.
</ResponseField>

<ResponseField name="POST /perps/me/api-keys" type="endpoint">
  Create a key. Body `{ name, scope, allowedIps?, expiresInDays? }`. Returns the
  metadata **plus the plaintext `secret`, shown once only**.
</ResponseField>

<ResponseField name="DELETE /perps/me/api-keys/{id}" type="endpoint">
  Revoke a key.
</ResponseField>

```json POST /perps/me/api-keys theme={null}
{ "name": "mm-bot-1", "scope": "trade", "allowedIps": ["203.0.113.7"], "expiresInDays": 90 }
→ { "id": "01H…", "name": "mm-bot-1", "scope": "trade",
    "secret": "ocx_sk_…", "message": "Copy this secret now — it will not be shown again." }
```

<Warning>
  The `secret` is returned exactly once at creation and can never be retrieved
  again. Store it in a secret manager immediately; if you lose it, revoke the key
  and create a new one.
</Warning>
