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

# Options chain

> Per-contract data (greeks, OI, IV, bid/ask) plus aggregate stats. Filters supported:

* `expiries` — CSV of tokens (e.g. `28MAR25,25APR25`).
* `dte_min` / `dte_max` — days-to-expiry bounds.
* `oi_min` / `oi_max` — open interest bounds.
* `delta_min` / `delta_max` — applied to |delta| (0..1).
* `strike_min` / `strike_max` — absolute strike bounds.
* `moneyness_min` / `moneyness_max` — strike / spot ratio bounds,   e.g. `0.9..1.1` keeps strikes within ±10% of spot. Useful for   cross-symbol screens since it normalises the strike grid.
* `option_type` — `call`, `put`, or `both`.

Two layers of projection:

* `fields` (top-level): comma-sep subset of `aggregates,available_expiries,contracts` — drops whole sections of the   response, e.g. `?fields=contracts` to skip aggregates.
* `include` (per-contract): comma-sep subset of `bid_ask,gex,greeks,iv,oi,volume` — keeps only the   named sub-sections of each contract dict. Core identity fields (`strike,expiry,dte,type`) are always present. Default   is every section, matching v1 shape.

Payload is capped at `?max_contracts=` (default 2000, hard ceiling 5000). On overflow the response is truncated to the closest-to-spot subset and `truncated=true` is set with `total_matching_count` so the client knows to narrow the filter.

Response is cached for 30s keyed by the exact filter combination, so repeated calls with identical filters are sub-millisecond.

Filtered chain with two-layer projection (`?fields=` top-level, `?include=` per-contract) and a payload cap (`?max_contracts`). Cached 30s per filter combination.

## See also

<CardGroup cols={2}>
  <Card title="Greeks beyond delta" href="/concepts/greeks" icon="bookmark" />
</CardGroup>


## OpenAPI

````yaml GET /options/chain
openapi: 3.1.0
info:
  title: BackQuant API v2
  description: >-

    # BackQuant API v2


    Options + gamma-exposure focused public API. Built on the same data the

    BackQuant Pro Terminal renders — pre-computed every 30s, served from cache.


    ## What's in v2


    * **Discovery**: `/v2/symbols` (universe + per-symbol freshness + supported
      endpoint list), `/v2/expiries` (active expiry tokens with DTE), `/v2/status`
      (per-symbol-per-category health with thresholds + overall classification).
    * **GEX**: composable levels (HVL / call wall / put support / max-pain /
      expected move / gamma-flip zones), strike profile with typed expiry
      filter, expiry profile, strike × expiry heatmap with downsampling,
      greek time-heatmap with DTE/OI/IV filters, history (cursor-paginated),
      Postgres-backed stress history, **per-expiry max-pain with pain curve**.
    * **Options**: filtered options chain with two-layer projection (top-level
      `?fields=` and per-contract `?include=oi,iv,greeks,bid_ask,volume,gex`)
      plus moneyness filter (`?moneyness_min=0.9&moneyness_max=1.1`), expiry
      summary table, full IV suite (surface / term structure / 25Δ-10Δ skew /
      curves / **single-expiry smile** / IV-RV history / VRP), expected move,
      **Breeden-Litzenberger probability density and surface**, typed greek
      profiles (delta / theta / vanna / charm / vega), strike × time charm/vega
      surfaces, strike × expiry 3D greek surface, OI by expiry + history,
      put/call ratio (intraday or daily), 0DTE & weekly premium tide,
      dated-futures term structure.
    * **Liquidation**: heatmap + leverage-tiered distribution.

    * **Multi**: `/v2/multi/gex/levels` — bundled multi-symbol read across the
      universe in one round-trip, with the same `?include=` model as the
      single-symbol endpoint.

    ## Authentication


    Every v2 route (except `/v2/openapi.json`, `/v2/docs`, `/v2/redoc`, and

    `/v2/health`) requires the `X-API-Key` header.


    ```

    X-API-Key: bq_live_your_api_key_here

    ```


    **Get your API key at
    [backquant.com/api-access](https://backquant.com/api-access).**


    The same key works across v1 and v2 — if you already have a v1 key, no

    re-issuance is needed.


    ## Rate limits


    Per-key, derived from your subscription tier:


    | Tier        | Limit                |

    |-------------|----------------------|

    | Monthly     | 60 requests/min      |

    | Yearly      | 120 requests/min     |

    | Enterprise  | No limit             |


    Headers `X-RateLimit-Limit / -Remaining / -Reset` are included in every

    response, and the same triple is echoed inside `meta.rate_limit` when

    populated by middleware.


    ## Response envelope


    ```json

    {
      "success": true,
      "data": { ... },
      "meta": {
        "version": "2.0",
        "timestamp": "2026-04-29T12:00:00.000Z",
        "request_id": "req_…",
        "symbol": "BTCUSDT",
        "spot_price": 67213.5,
        "computed_at": "2026-04-29T11:59:48.000Z",
        "freshness_seconds": 12.0,
        "source": ["deribit","bybit","okx","binance"],
        "exchanges_filtered": ["deribit","bybit"]
      }
    }

    ```


    ## Errors


    ```json

    {
      "success": false,
      "error": {
        "code": "NOT_FOUND",
        "message": "No data for BTCUSDT"
      },
      "meta": { "version": "2.0", "timestamp": "..." }
    }

    ```


    | Code                  | When |

    |-----------------------|------|

    | `UNAUTHORIZED`        | Missing or invalid API key |

    | `FORBIDDEN`           | Subscription doesn't allow API access |

    | `NOT_FOUND`           | Symbol/expiry/etc. not present in cache |

    | `VALIDATION_ERROR`    | Bad query parameters |

    | `RATE_LIMIT_EXCEEDED` | Per-tier limit hit |

    | `UPSTREAM_ERROR`      | Cache or DB temporarily unreachable |

    | `INTERNAL_ERROR`      | Anything else |
        
  version: 2.0.0
servers: []
security: []
tags:
  - name: Meta
    description: Unauthenticated metadata + endpoint catalog (planning your integration)
  - name: Discovery
    description: Symbol catalog, active expiries, and service status
  - name: GEX
    description: Gamma exposure analytics
  - name: Options
    description: Options chain, IV, greeks, probability, premium tide
  - name: Liquidation
    description: Liquidation heatmap and distribution
  - name: Multi
    description: Bundled multi-symbol endpoints (single round-trip across the universe)
paths:
  /options/chain:
    get:
      tags:
        - Options
      summary: Filtered options chain
      description: >-
        Per-contract data (greeks, OI, IV, bid/ask) plus aggregate stats.
        Filters supported:


        * `expiries` — CSV of tokens (e.g. `28MAR25,25APR25`).

        * `dte_min` / `dte_max` — days-to-expiry bounds.

        * `oi_min` / `oi_max` — open interest bounds.

        * `delta_min` / `delta_max` — applied to |delta| (0..1).

        * `strike_min` / `strike_max` — absolute strike bounds.

        * `moneyness_min` / `moneyness_max` — strike / spot ratio bounds,   e.g.
        `0.9..1.1` keeps strikes within ±10% of spot. Useful for   cross-symbol
        screens since it normalises the strike grid.

        * `option_type` — `call`, `put`, or `both`.


        Two layers of projection:


        * `fields` (top-level): comma-sep subset of
        `aggregates,available_expiries,contracts` — drops whole sections of
        the   response, e.g. `?fields=contracts` to skip aggregates.

        * `include` (per-contract): comma-sep subset of
        `bid_ask,gex,greeks,iv,oi,volume` — keeps only the   named sub-sections
        of each contract dict. Core identity fields (`strike,expiry,dte,type`)
        are always present. Default   is every section, matching v1 shape.


        Payload is capped at `?max_contracts=` (default 2000, hard ceiling
        5000). On overflow the response is truncated to the closest-to-spot
        subset and `truncated=true` is set with `total_matching_count` so the
        client knows to narrow the filter.


        Response is cached for 30s keyed by the exact filter combination, so
        repeated calls with identical filters are sub-millisecond.
      operationId: get_chain_options_chain_get
      parameters:
        - name: symbol
          in: query
          required: false
          schema:
            enum:
              - BTCUSDT
              - ETHUSDT
              - SOLUSDT
              - HYPEUSDT
            type: string
            description: 'Trading symbol: BTCUSDT, ETHUSDT, SOLUSDT, or HYPEUSDT.'
            default: BTCUSDT
            title: Symbol
          description: 'Trading symbol: BTCUSDT, ETHUSDT, SOLUSDT, or HYPEUSDT.'
        - name: expiries
          in: query
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: CSV of expiry tokens (e.g. 28MAR25,25APR25)
            title: Expiries
          description: CSV of expiry tokens (e.g. 28MAR25,25APR25)
        - name: dte_min
          in: query
          required: false
          schema:
            anyOf:
              - type: integer
                maximum: 720
                minimum: 0
              - type: 'null'
            description: Inclusive lower bound on days-to-expiry.
            title: Dte Min
          description: Inclusive lower bound on days-to-expiry.
        - name: dte_max
          in: query
          required: false
          schema:
            anyOf:
              - type: integer
                maximum: 720
                minimum: 0
              - type: 'null'
            description: Inclusive upper bound on days-to-expiry.
            title: Dte Max
          description: Inclusive upper bound on days-to-expiry.
        - name: oi_min
          in: query
          required: false
          schema:
            anyOf:
              - type: number
                minimum: 0
              - type: 'null'
            description: Minimum open interest per contract.
            title: Oi Min
          description: Minimum open interest per contract.
        - name: oi_max
          in: query
          required: false
          schema:
            anyOf:
              - type: number
                minimum: 0
              - type: 'null'
            description: Maximum open interest per contract.
            title: Oi Max
          description: Maximum open interest per contract.
        - name: delta_min
          in: query
          required: false
          schema:
            anyOf:
              - type: number
                maximum: 1
                minimum: 0
              - type: 'null'
            description: Minimum |delta| (0..1).
            title: Delta Min
          description: Minimum |delta| (0..1).
        - name: delta_max
          in: query
          required: false
          schema:
            anyOf:
              - type: number
                maximum: 1
                minimum: 0
              - type: 'null'
            description: Maximum |delta| (0..1).
            title: Delta Max
          description: Maximum |delta| (0..1).
        - name: strike_min
          in: query
          required: false
          schema:
            anyOf:
              - type: number
                minimum: 0
              - type: 'null'
            description: Minimum strike price (absolute).
            title: Strike Min
          description: Minimum strike price (absolute).
        - name: strike_max
          in: query
          required: false
          schema:
            anyOf:
              - type: number
                minimum: 0
              - type: 'null'
            description: Maximum strike price (absolute).
            title: Strike Max
          description: Maximum strike price (absolute).
        - name: moneyness_min
          in: query
          required: false
          schema:
            anyOf:
              - type: number
                maximum: 10
                minimum: 0
              - type: 'null'
            description: Strike/spot lower bound (e.g. `0.9` for ATM-10%).
            title: Moneyness Min
          description: Strike/spot lower bound (e.g. `0.9` for ATM-10%).
        - name: moneyness_max
          in: query
          required: false
          schema:
            anyOf:
              - type: number
                maximum: 10
                minimum: 0
              - type: 'null'
            description: Strike/spot upper bound (e.g. `1.1` for ATM+10%).
            title: Moneyness Max
          description: Strike/spot upper bound (e.g. `1.1` for ATM+10%).
        - name: option_type
          in: query
          required: false
          schema:
            enum:
              - call
              - put
              - both
            type: string
            description: Filter to call, put, or both contract types.
            default: both
            title: Option Type
          description: Filter to call, put, or both contract types.
        - name: max_contracts
          in: query
          required: false
          schema:
            type: integer
            maximum: 5000
            minimum: 1
            description: >-
              Cap on the number of contracts returned (default 2000, hard
              ceiling 5000). When more contracts match the filters, the response
              is truncated to the closest-to-spot subset and `truncated=true` is
              set with `total_matching_count` so the client knows to narrow the
              filter.
            default: 2000
            title: Max Contracts
          description: >-
            Cap on the number of contracts returned (default 2000, hard ceiling
            5000). When more contracts match the filters, the response is
            truncated to the closest-to-spot subset and `truncated=true` is set
            with `total_matching_count` so the client knows to narrow the
            filter.
        - name: fields
          in: query
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: 'Top-level projection: aggregates,available_expiries,contracts'
            title: Fields
          description: 'Top-level projection: aggregates,available_expiries,contracts'
        - name: include
          in: query
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: >-
              Per-contract projection: bid_ask,gex,greeks,iv,oi,volume. Default
              is all sections.
            title: Include
          description: >-
            Per-contract projection: bid_ask,gex,greeks,iv,oi,volume. Default is
            all sections.
        - name: X-API-Key
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            title: X-Api-Key
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChainResponse'
        '401':
          description: Invalid or missing API key
          content:
            application/json:
              example:
                success: false
                error:
                  code: UNAUTHORIZED
                  message: Invalid API key
                meta:
                  version: '2.0'
                  timestamp: '2026-04-29T12:00:00Z'
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V2ErrorEnvelope'
          description: Not Found
        '422':
          description: Validation error on query parameters
          content:
            application/json:
              example:
                success: false
                error:
                  code: VALIDATION_ERROR
                  message: Invalid request parameters
                  details:
                    errors: []
                meta:
                  version: '2.0'
                  timestamp: '2026-04-29T12:00:00Z'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              example:
                success: false
                error:
                  code: RATE_LIMIT_EXCEEDED
                  message: Rate limit exceeded. Try again later.
                meta:
                  version: '2.0'
                  timestamp: '2026-04-29T12:00:00Z'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    ChainResponse:
      properties:
        success:
          type: boolean
          const: true
          title: Success
          default: true
        data:
          $ref: '#/components/schemas/ChainData'
        meta:
          $ref: '#/components/schemas/V2Meta'
      type: object
      required:
        - data
        - meta
      title: ChainResponse
    V2ErrorEnvelope:
      properties:
        success:
          type: boolean
          const: false
          title: Success
          default: false
        error:
          $ref: '#/components/schemas/V2Error'
        meta:
          $ref: '#/components/schemas/V2Meta'
      type: object
      required:
        - error
        - meta
      title: V2ErrorEnvelope
      description: Returned for every non-2xx response.
    ChainData:
      properties:
        contracts:
          anyOf:
            - items:
                $ref: '#/components/schemas/OptionContract'
              type: array
            - type: 'null'
          title: Contracts
        aggregates:
          anyOf:
            - $ref: '#/components/schemas/ChainAggregates'
            - type: 'null'
        available_expiries:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Available Expiries
        truncated:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Truncated
          description: True when the matching set exceeded `max_contracts`.
        total_matching_count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Total Matching Count
          description: Total contracts matching the filters (pre-truncation).
        max_contracts:
          anyOf:
            - type: integer
            - type: 'null'
          title: Max Contracts
      type: object
      title: ChainData
    V2Meta:
      properties:
        version:
          type: string
          const: '2.0'
          title: Version
          description: API version tag.
        timestamp:
          type: string
          title: Timestamp
          description: ISO 8601 wall-clock when the response was built.
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Id
          description: X-Request-ID for tracing across logs / Sentry.
        symbol:
          anyOf:
            - type: string
            - type: 'null'
          title: Symbol
          description: Symbol the response is about, if applicable.
        spot_price:
          anyOf:
            - type: number
            - type: 'null'
          title: Spot Price
          description: Current spot price for the symbol.
        computed_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Computed At
          description: ISO 8601 of when the underlying cache value was last written.
        freshness_seconds:
          anyOf:
            - type: number
            - type: 'null'
          title: Freshness Seconds
          description: '`now - computed_at` in seconds; useful for staleness alarms.'
        source:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Source
          description: Upstream venue list the data flowed through.
        exchanges_filtered:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Exchanges Filtered
          description: Echo of the `?exchanges=` filter when one was applied.
        rate_limit:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Rate Limit
          description: '`{limit, remaining, reset}` echo of the rate-limit headers.'
        extra:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Extra
          description: Open dict for endpoint-specific metadata (filter_hash, etc.).
      type: object
      required:
        - version
        - timestamp
      title: V2Meta
      description: |-
        The meta block returned alongside every v2 response.

        Every field after `version`/`timestamp` is optional because endpoints
        attach different combinations — e.g. `/v2/status` skips `symbol`, the
        chain endpoint sets `extra.filter_hash`, etc. Listing them here means
        SDKs get a typed accessor for each instead of a generic `meta: dict`.
    V2Error:
      properties:
        code:
          type: string
          title: Code
          description: Stable machine-readable error code (see /v2/meta).
        message:
          type: string
          title: Message
          description: Human-readable description.
        details:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Details
          description: >-
            Optional structured payload — e.g. validation_error returns the
            failing field list.
      type: object
      required:
        - code
        - message
      title: V2Error
    OptionContract:
      properties:
        strike:
          anyOf:
            - type: number
            - type: 'null'
          title: Strike
        expiry:
          anyOf:
            - type: string
            - type: 'null'
          title: Expiry
        dte:
          anyOf:
            - type: integer
            - type: 'null'
          title: Dte
        type:
          anyOf:
            - type: string
              enum:
                - call
                - put
            - type: 'null'
          title: Type
        oi:
          anyOf:
            - type: number
            - type: 'null'
          title: Oi
        iv:
          anyOf:
            - type: number
            - type: 'null'
          title: Iv
        mark:
          anyOf:
            - type: number
            - type: 'null'
          title: Mark
        bid:
          anyOf:
            - type: number
            - type: 'null'
          title: Bid
        ask:
          anyOf:
            - type: number
            - type: 'null'
          title: Ask
        volume:
          anyOf:
            - type: number
            - type: 'null'
          title: Volume
        notional_volume:
          anyOf:
            - type: number
            - type: 'null'
          title: Notional Volume
        trade_count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Trade Count
        delta:
          anyOf:
            - type: number
            - type: 'null'
          title: Delta
        gamma:
          anyOf:
            - type: number
            - type: 'null'
          title: Gamma
        theta:
          anyOf:
            - type: number
            - type: 'null'
          title: Theta
        vega:
          anyOf:
            - type: number
            - type: 'null'
          title: Vega
        vanna:
          anyOf:
            - type: number
            - type: 'null'
          title: Vanna
        charm:
          anyOf:
            - type: number
            - type: 'null'
          title: Charm
        gex:
          anyOf:
            - type: number
            - type: 'null'
          title: Gex
      type: object
      title: OptionContract
      description: Per-contract row. Optional fields reflect ?include= projection.
    ChainAggregates:
      properties:
        net_gex:
          type: number
          title: Net Gex
        call_gex:
          type: number
          title: Call Gex
        put_gex:
          type: number
          title: Put Gex
        total_oi:
          type: number
          title: Total Oi
        call_oi:
          type: number
          title: Call Oi
        put_oi:
          type: number
          title: Put Oi
        pcr:
          anyOf:
            - type: number
            - type: 'null'
          title: Pcr
        atm_iv:
          anyOf:
            - type: number
            - type: 'null'
          title: Atm Iv
        contract_count:
          type: integer
          title: Contract Count
      type: object
      required:
        - net_gex
        - call_gex
        - put_gex
        - total_oi
        - call_oi
        - put_oi
        - contract_count
      title: ChainAggregates
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: Your BackQuant API key (same key as v1)

````