/v2/chain/{symbol} The option chain for one underlying
chain_getChain
Every listed contract of one underlying from a single capture, with quotes, open interest, volume, implied volatility and greeks. Use it for a full or filtered chain snapshot, live or at a past time with at=.
Path parameters
symbolstring requiredUnderlying symbol, e.g.
SPY
Query parameters
atstring epoch msPoint in time to read instead of the live capture: epoch-ms, or a
YYYY-MM-DD/YYYY-MM-DDTHH:MM[:SS]string interpreted intz.tzstringIANA timezone for a string
at(defaultAmerica/New_York).expirystring ISO dateKeep one expiry, ISO
YYYY-MM-DD.strike_gtestring 1/1000 $Strike lower bound, integer thousandths (inclusive).
strike_ltestring 1/1000 $Strike upper bound, integer thousandths (inclusive).
Details
Every row is valued against the one spot of the capture, so rows are consistent with each other. Fields the capture did not report are omitted from the row. partial: true means the capture is known to be incomplete.
Units
strikeis in integer thousandths of a dollar (765000= $765.00);strike_gte/strike_lteuse the same unit.spot,bid,ask,lastandfmvare dollars (option prices per share);thetais dollars per day.ivis annualized, as a fraction (0.126= 12.6%).oi(open interest) andvolumeare contracts;shares_per_contractis 100 for standard contracts.captured_atis epoch milliseconds.
Freshness
A live read (no at=) is served from a shared capture that is re-taken at most every 30 seconds per symbol; while a refresh runs, the previous capture is served for up to 5 minutes. captured_at says when the served capture was taken, and meta.cache is hit, stale, miss or coalesced. The first read of a symbol can take a few seconds (SPY has thousands of contracts); filters apply to the cached capture, so they cost nothing extra.
Limits
No per-operation limit applies to requests with an API key.
Empty results
A symbol with no listed options returns 200 with rows: [].
Example
GET /v2/chain/SPY?expiry=2026-10-02&strike_gte=700000&strike_lte=700000{
"data": {
"spot": 772.05,
"captured_at": 1790493741321,
"partial": false,
"rows": [
{
"contract": {
"underlying": "SPY",
"expiry": "2026-10-02",
"right": "call",
"strike": 700000
},
"oi": 507,
"volume": 256,
"bid": 71.57,
"ask": 72.83,
"last": 71.92,
"fmv": 72.201,
"iv": 0.4379,
"delta": 0.9666,
"gamma": 0.0018,
"theta": -0.3226,
"vega": 0.0924,
"shares_per_contract": 100
},
{
"contract": {
"underlying": "SPY",
"expiry": "2026-10-02",
"right": "put",
"strike": 700000
},
"oi": 10522,
"volume": 358,
"bid": 0.05,
"ask": 0.06,
"last": 0.06,
"fmv": 0.055,
"iv": 0.3144,
"delta": -0.0054,
"gamma": 0.0005,
"theta": -0.0408,
"vega": 0.0196,
"shares_per_contract": 100
}
]
},
"meta": { "cache": "miss", "row_count": 2, "underlying": "SPY" }
}Response
Prices are dollars, timestamps epoch milliseconds, strikes integer thousandths of a dollar; null means unknown. Units →
200application/jsonapplication/x-protobuf
{spot, captured_at, partial, rows} in data; provenance in meta. Under Accept: application/x-protobuf the same capture is served as the public protobuf body (/v2/rest-protocol.proto); JSON stays the default for every other Accept.
object
A successful response: the payload consumers parse plus response metadata. data shapes are the platform types — never reshaped by the envelope.
data object required
The contract chain view: one spot for the whole capture, the capture instant, a partial flag, and the per-contract rows.
captured_at integer · int64 nullable epoch ms Capture instant, epoch-ms.
partial boolean required The capture is knowingly incomplete (partial ingest / convert drops).
rows array<ChainSnapshotRow> required
ask number · double nullable bid number · double nullable contract object required
A single listed option contract, identified the way the OSI does: root symbol, expiry date, right, strike.
underlying is the OSI root (e.g. SPXW for SPX weeklies), stored unpadded and uppercase.
expiry string · date required ISO date right string required Call or put.
callputstrike integer · int64 required 1/1000 $ Strike in integer thousandths of a dollar (exact OSI unit)
underlying string required delta number · double nullable fmv number · double nullable Vendor fair-market/model value — kept as captured, provenance only.
gamma number · double nullable iv number · double nullable Vendor implied volatility.
last number · double nullable Last trade price.
oi integer · int64 nullable Open interest (vendor-daily; None = not reported).
shares_per_contract integer · int32 Contract multiplier; 100 for standard contracts (S5: carried per row because adjusted/mini contracts differ).
theta number · double nullable vega number · double nullable volume integer · int64 nullable Day volume at capture.
spot number · double nullable The one spot the whole capture is valued against.
meta object required
Response metadata.
caps object nullable
meta.caps — the entitlement caps that shaped this response. applied lists the caps that actually changed it (for example range_clamped).
applied array<string> required Which caps actually shaped this response (e.g. range_clamped). Empty = nothing was clamped.
darkpool boolean nullable Whether this account can use Off-Exchange in the site.
flow boolean nullable Whether the OPRA option-flow capability (flow) is granted to this principal in the app: site Pro plus a CBOE non-professional attestation (never on an itm_ key). Emitted explicitly — true and false — by the account endpoints, so the app reads the grant instead of inferring it from tier and attestation; absent on routes that do not report it.
gexDepth string nullable GEX data depth when the route reports it. Camel-cased to match the browser capability bundle; absent on unrelated routes.
tier string required The tier the request was served under.
cursor string nullable Opaque continuation cursor (pass back as ?cursor=); absent when there is nothing more to read.
plane string nullable Which serving tier answered the read (meta.plane). Informational provenance: treat it as an opaque label, because new values may appear.
Send Accept: application/x-protobuf for a protobuf body instead of JSON — see Protobuf. Errors stay JSON.
Errors
Every error is the JSON error envelope; branch on error.code.
| Status | Meaning |
|---|---|
| 400 |
|
| 401 |
|
| 403 |
|
| 502 |
|
| 503 |
|