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

# Markets & Market Data

> Market catalog, market terms, order books and the exact-number format.

## Exact numbers

Prices, quantities, strikes and amounts are sent as exact fixed-point objects, never as floats:

```json theme={null}
{ "units": "105000123456", "decimals": 6 }
```

`value = units × 10^-decimals`, so the example above is `105000.123456`. `units` is a decimal integer string and may be negative (for example, a short position).

> [!WARNING]
>
> Do not parse `units` with JavaScript `Number` or `parseFloat`. Values can be larger than `Number.MAX_SAFE_INTEGER` (2^53 − 1), and floats lose precision. Use `BigInt`, or a decimal library in other languages.

```ts theme={null}
type Exact = { units: string; decimals: number };

// Exact decimal string, e.g. { units: "-1050", decimals: 2 } -> "-10.50"
function toDecimalString({ units, decimals }: Exact): string {
  const negative = units.startsWith("-");
  const digits = (negative ? units.slice(1) : units).padStart(decimals + 1, "0");
  const whole = digits.slice(0, digits.length - decimals);
  const frac = decimals > 0 ? "." + digits.slice(-decimals) : "";
  return (negative ? "-" : "") + whole + frac;
}

// Rescale to a common scale before comparing or adding
const rescale = (v: Exact, to: number): bigint =>
  BigInt(v.units) * 10n ** BigInt(to - v.decimals); // requires to >= v.decimals
```

Values that are compared with each other do not always share a `decimals`, so rescale before you compare. Balances and premiums are always in USDC atoms (`decimals: 6`).

## Pagination

`/markets`, `/positions`, `/orders` and `/fills` use cursors:

```json theme={null}
{ "markets": [ … ], "nextCursor": "eyJ2Ijox…", "limit": 50, "serverTimeMs": "…" }
```

* Pass `nextCursor` back as `cursor`, unchanged, **with the same filters**. `nextCursor: null` means you have the last page.
* Cursors are opaque. A cursor used with different filters, on another route, or after a cursor format change returns `400 INVALID_CURSOR`. When that happens, drop the cursor and start again from the first page.

`/executions` does not use cursors. It uses a sequence checkpoint instead (see [Executions](https://docs.d1.exchange/market-makers/executions.md)).

## List markets

`GET /mm/v1/markets`

```bash theme={null}
curl "$D1_API_URL/mm/v1/markets?status=ACTIVE&limit=100" \
  -H "Authorization: Bearer $D1_MM_API_KEY"
```

**limit** `integer` (default: 50)

1–100.

**cursor** `string`

`nextCursor` from the previous page.

**status** `string`

Optional filter: `ACTIVE`, `TRADING_CLOSED`, `EXPIRING` or `SETTLED`.

Returns `{ markets, nextCursor, limit, serverTimeMs }`.

* With no `status` filter, results are sorted by `instrumentId`. Use this for a complete catalog sync.
* With a `status` filter, results are sorted by expiry, then `instrumentId`. A market that changes status while you are paging can be missed, so use the unfiltered listing when you need every market.

### Market fields

| Field | Type | Description |
| - | - | - |
| `instrumentId` | string | Unique, stable market identifier. |
| `underlying` | string | Underlying asset, e.g. `BTC`. |
| `optionType` | string | `CALL` or `PUT`. |
| `exerciseStyle` | string | `EUROPEAN` or `AMERICAN`. |
| `settlementType` | string | `CASH`. |
| `strike` | exact | Strike price, in the quote asset. |
| `expirySeconds` | string | Expiry as Unix seconds. |
| `expiryMs` | string | Expiry as Unix milliseconds. |
| `contractSize` | exact | Units of the underlying per contract. |
| `priceTick` | exact | Minimum price increment. |
| `quantityStep` | exact | Minimum quantity increment, in contracts. |
| `quoteAsset` | string | Asset prices are quoted in (`USDC`). |
| `settlementAsset` | string | Asset the market settles in (`USDC`). |
| `collateralAsset` | string | Collateral asset (`USDC`). |
| `premiumUnit` | string | How `price` is expressed: `QUOTE_PER_CONTRACT` or `QUOTE_PER_UNDERLYING`. |
| `status` | string | Lifecycle status (see below). |
| `tradingPaused` | boolean | `true` while D1 has paused trading on this market. |

### Status and pauses

| `status` | Meaning |
| - | - |
| `ACTIVE` | Open for trading, unless `tradingPaused` is `true`. |
| `TRADING_CLOSED` | The market has reached expiry and trading is closed. Remaining orders are cancelled with reason `EXPIRY`. |
| `EXPIRING` | A settlement price has been accepted and settlement is in progress. |
| `SETTLED` | Settlement is complete. This is a final state. |

`tradingPaused` is separate from `status`. A market can be `ACTIVE` but paused. Treat a paused market as not tradable until `tradingPaused` goes back to `false`. D1 does not publish the reason for a pause.

## Get one market

`GET /mm/v1/markets/{instrumentId}`

```bash theme={null}
curl "$D1_API_URL/mm/v1/markets/$INSTRUMENT_ID" \
  -H "Authorization: Bearer $D1_MM_API_KEY"
```

```json theme={null}
{
  "market": { "instrumentId": "<instrument-id>", "status": "SETTLED", "tradingPaused": false },
  "settlement": {
    "status": "SETTLED",
    "settlementPrice": { "units": "101250", "decimals": 0 },
    "settledAtMs": "1800000360000"
  },
  "serverTimeMs": "1800000400000"
}
```

`market` has the same fields as in the list (shortened above). `settlement` summarizes the accepted settlement:

| `settlement.status` | `settlementPrice` | `settledAtMs` |
| - | - | - |
| `NONE`: no settlement price accepted yet | `null` | `null` |
| `LOCKED`: settlement price accepted, settlement not yet complete | exact | `null` |
| `SETTLED`: settlement complete | exact | string |

An unknown `instrumentId` returns `404 NOT_FOUND`. A malformed one returns `400 MALFORMED_REQUEST`.

## Order book

`GET /mm/v1/markets/{instrumentId}/orderbook`

```bash theme={null}
curl "$D1_API_URL/mm/v1/markets/$INSTRUMENT_ID/orderbook?depth=20" \
  -H "Authorization: Bearer $D1_MM_API_KEY"
```

**depth** `integer` (default: 20)

Price levels per side, 1–50.

```json theme={null}
{
  "instrumentId": "<instrument-id>",
  "status": "ACTIVE",
  "tradingPaused": false,
  "depth": 20,
  "bids": [
    { "price": { "units": "105", "decimals": 0 }, "quantity": { "units": "12", "decimals": 0 },
      "ownQuantity": { "units": "0", "decimals": 0 }, "partial": false }
  ],
  "asks": [
    { "price": { "units": "110", "decimals": 0 }, "quantity": { "units": "8", "decimals": 0 },
      "ownQuantity": { "units": "3", "decimals": 0 }, "partial": false }
  ],
  "truncated": false,
  "serverTimeMs": "1800000000456"
}
```

* `bids` and `asks` are aggregated price levels, **best first**: highest bid first, lowest ask first.
* `quantity` is the total resting quantity at the level. `ownQuantity` is the part of it that belongs to you, or `0` if none.
* The book does not show individual orders or who placed them.

### Partial and truncated books

D1 reads a bounded number of resting orders per side. When a book is very deep:

* **`partial: true`** marks the one level where that bound was reached. Its `quantity` and `ownQuantity` are **lower bounds**: there may be more at that price.
* **`truncated: true`** means more book exists than is shown, either beyond `depth` or beyond the read bound.

The levels before a `partial` level are complete. Do not treat the last level of a truncated book as the full liquidity at that price.


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