Last updated: Oct 14, 2026
API Changelog
Schema and contract changes to the OptionData data APIs — Market Structure, Option Chain, Realtime WebSocket, and Historical SQL. Breaking changes are marked.
For the current request/response schema, see the API references: Option Chain · Market Structure · Historical SQL · Realtime
34 changes
- ChangedHistorical SQLBreakingUnreleased
Trial Historical SQL: past 7 days, up to 1,000 rows per response
Trialing subscriptions now query a rolling 7-day window (168 elapsed hours, about five trading sessions) and receive up to 1,000 rows per response instead of 10. Trial success responses include meta.lookback_days: 7.
- Trades older than the window are excluded before joins and aggregations, as for paid subscriptions. Trial queries that targeted older dates now return only in-window trades.
meta.cappedstays true for trial responses. Paid access, the 15-minute delay, and synthetic test-mode samples are unchanged.
- AddedGeneralUnreleased
403 SUBSCRIPTION_REQUIRED says why and where to restore access
Option Chain, Market Structure and Historical SQL add reason "NO_ACTIVE_SUBSCRIPTION" and billing_url "/billing" to the HTTP 403 SUBSCRIPTION_REQUIRED body. Option Chain and Market Structure add them inside error; Historical SQL adds them next to errorCode and errorMsg.
- Existing fields and status codes are unchanged.
billing_urlis a path on www.optiondata.io where the account owner can restore Pro access.
- Existing fields and status codes are unchanged.
- FixedRealtime WebSocketUnreleased
AGGREGATED market_cap and updated_timestamp are sent as numbers
In AGGREGATED mode, the realtime stream sent market_cap and updated_timestamp as JSON strings. They are now JSON numbers, as the field reference documents. RAW mode already sent updated_timestamp as a number.
- Values are unchanged. A client that converts either field with a number parser keeps working; a client that handles the raw value as a string must accept a number.
- FixedMarket StructureUnreleased
Retryable 503 when the snapshot service cannot be reached
Market Structure returns HTTP 503 with code UPSTREAM_UNAVAILABLE when its request to the snapshot service fails before any response arrives. These requests previously returned HTTP 500 with INTERNAL_ERROR.
- Retry the same request later. A timeout or an error status from the snapshot service already returned 503.
- FixedGeneralOct 14, 2026
Retryable 503 when an API key cannot be verified in time
Option Chain, Market Structure and Historical SQL return HTTP 503 with code UPSTREAM_UNAVAILABLE and a Retry-After header when the account services cannot confirm an API key in time. These requests previously returned HTTP 500 with INTERNAL_ERROR.
- Retry the same request after the Retry-After seconds. An invalid or revoked key still returns 401 UNAUTHORIZED.
- Option Chain uses { error: { code, message } } and Historical SQL uses errorCode; Market Structure already used UPSTREAM_UNAVAILABLE for an unavailable snapshot service.
- AddedRealtime WebSocketOct 8, 2026
Realtime stream filters by exact expiration date
The WebSocket and SSE stream accepts an expiration_date query parameter: one or more YYYY-MM-DD dates, comma-separated. Existing parameters are unchanged.
- A record passes when its
expiration_dateequals one of the listed dates. Unlikeexpiry_days, the selection does not shift from one session to the next, so symbols,put_call, strike andexpiration_datetogether follow one contract. - Dates must be YYYY-MM-DD; a value in another format matches nothing. The parameter works in AGGREGATED and RAW modes.
- A record passes when its
- ChangedMarket StructureOct 8, 2026
Market Structure fields and freshness documented
The API reference and OpenAPI schema now document RV20/RV30, volatility metadata, expiry scopes, and the separate freshness timestamps. This is a documentation update, not a change to response behavior.
- rv20 and rv30 are annualized realized-volatility decimals from 20 or 30 valid trading-session log returns.
rv_as_ofidentifies the latest completed session included. These fields are optional and can be absent on older snapshots. - Expiry scopes use calendar days from
meta.effective_date:zero_dteis 0 days, weekly is 1–7 days, monthly is 8–31 days, and all includes every unexpired expiration. - Read
meta.structure_as_of,meta.flow_as_of, andmeta.intraday_gex_as_ofseparately. Structural levels follow full-chain snapshot updates; session flow and intraday GEX normally update about every five minutes. An explicit date is never replaced with another session.
- rv20 and rv30 are annualized realized-volatility decimals from 20 or 30 valid trading-session log returns.
- ChangedOption ChainOct 8, 2026
Option Chain freshness and date semantics clarified
The API reference and quickstart now distinguish the latest available session, trade-derived updates, and contract-level freshness. This is a documentation update; the response fields and expected 90-second update interval are unchanged.
- Check
meta.trading_dateandmeta.as_ofbefore treating a response as current.meta.as_ofis the newest contributing chain snapshot or trade time, not a freshness guarantee for every contract. Contracts without newer trades can retain earlier chain values. - An explicit date selects that session’s stored chain, not an intraday replay. Strike filters must be positive; strike cannot be combined with
strike_minorstrike_max.
- Check
- FixedOption ChainOct 2, 2026
Bid and ask filled from session trades
bid and ask are now the best bid and ask recorded with the contract's most recent trade in the session. Previously most contracts returned no quote, and past sessions had none.
- This applies to the latest session and to every past date. A contract that did not trade in the session still returns null for both fields.
- The quote is from the contract's last trade, so a contract that last traded early in the day carries that earlier quote.
- ChangedOption ChainBreakingOct 2, 2026
Invalid dates and missing chains return errors
Requests that cannot return a chain now fail with an error instead of returning another session or an empty 200.
- An impossible calendar date such as 2026-02-30 in date or
expiration_datereturns 400 INVALID_REQUEST. Previously it could return the chain of a later session. - A date with no stored session (weekend, holiday, future, or outside retention) returns 404 SNAPSHOT_NOT_FOUND. A symbol with no chain on the session returns 404 SYMBOL_NOT_FOUND.
- A chain whose filters match no contract still returns 200 with an empty data array.
- An impossible calendar date such as 2026-02-30 in date or
- FixedOption ChainBreakingOct 2, 2026
Unavailable quotes and Greeks are null
bid and ask are null when no quote is stored for a contract, instead of 0. implied_volatility and the Greeks are null together when no model value is available, instead of 0.
- Handle null before arithmetic on these fields. A single 0, such as a bid of 0 with a positive ask, is still a real value.
- AddedHistorical SQLOct 2, 2026
Historical SQL reports truncation and error codes
Successful responses include meta.truncated, which is true when the query produced more rows than meta.row_limit. Every error response now includes errorCode.
meta.cappedis unchanged: it means the trial row cap applies, not that rows were cut off.- New errorCode values: INVALID_REQUEST, INVALID_SQL, UNAUTHORIZED, SUBSCRIPTION_REQUIRED, RATE_LIMITED, and METHOD_NOT_ALLOWED.
- FixedGeneralOct 2, 2026
Unsupported HTTP methods return 405
Calling an HTTP data API with the wrong method returns 405 METHOD_NOT_ALLOWED with an Allow header, instead of the website home page.
- Applies to
/api/option-chainand/api/historical/sql(POST) and/api/v1/market-structure/{symbol} (GET). OPTIONS returns 204 with the Allow header.
- Applies to
- ChangedOption ChainOct 1, 2026
Latest option chains update about every 90 seconds
During U.S. market hours, requests without date return a chain that refreshes about every 90 seconds: contracts that trade receive newer quotes, Greeks, IV, volume, open interest, and last price.
- The request and response contract is unchanged. Poll every one to two minutes at most and compare
meta.as_ofbefore doing new work.
- The request and response contract is unchanged. Poll every one to two minutes at most and compare
- ChangedHistorical SQLBreakingSep 12, 2026
Paid Historical SQL access limited to the past 15 days
Paid (active) subscriptions query only the past 15 days of trades — 360 elapsed hours, including weekends and holidays. The existing 15-minute delay remains.
- Older trades are excluded before joins and aggregations. A query spanning the boundary includes only eligible trades; an older-only row query returns no rows.
- Update queries that use older dates to target recent dates. Paid success responses include
meta.lookback_days: 15. - Trial access, row limits, and synthetic test-mode samples are unchanged.
- FixedRealtime WebSocketAug 19, 2026
Connection-limit retries are now protected
When an API token already has five concurrent realtime connections, a new WebSocket or SSE handshake now returns HTTP 429 with Retry-After while existing connections remain open.
- Respect Retry-After and use exponential backoff before retrying. Close unused connections so one token stays within its five-connection limit.
- The server no longer evicts an existing connection when a sixth handshake arrives.
- FixedHistorical SQLAug 15, 2026
Numeric overflow now returns an actionable query error
Historical SQL expressions that exceed the supported numeric range now return HTTP 422 with errorCode = INVALID_QUERY and reason = NUMERIC_OVERFLOW instead of HTTP 500.
- Cast fixed-precision operands before multiplying or aggregating them; for example, use SUM(toFloat64(price) * size * 100) for premium calculations.
- The response remains privacy-safe and does not include the submitted SQL or database-internal error text.
- FixedHistorical SQLAug 13, 2026
Invalid Historical SQL now returns INVALID_QUERY
Queries with unknown columns, functions, aliases, or incompatible data types now return HTTP 422 with errorCode = INVALID_QUERY instead of HTTP 500.
- The response now includes a privacy-safe reason such as UNKNOWN_IDENTIFIER plus an actionable errorMsg, without exposing database-internal text.
- Correct the SQL before retrying. Use errorCode to distinguish INVALID_QUERY from QUERY_TOO_BROAD, QUERY_TIMEOUT, and INTERNAL_ERROR.
- AddedGeneralAug 10, 2026
Bearer authentication added to HTTP data APIs
Historical SQL and Option Chain now accept API keys through Authorization: Bearer, matching Market Structure.
- Send Authorization: Bearer YOUR_API_KEY using the API key generated in the OptionData portal.
- The
api_keyfield in a JSON or form body remains supported for backward compatibility when the Authorization header is absent. - When Authorization is present, it takes precedence over
api_key. Unsupported authentication schemes or invalid header formatting return HTTP 401.
- ChangedHistorical SQLBreakingAug 10, 2026
Stable Historical SQL execution errors
Historical SQL execution failures now return consistent HTTP statuses, error codes, and messages.
- Queries that scan too much data return HTTP 422 with errorCode = QUERY_TOO_BROAD. Add narrower date, symbol, or other filters before retrying.
- Execution timeouts return HTTP 504 with errorCode = QUERY_TIMEOUT.
- Unexpected execution failures return HTTP 500 with errorCode = INTERNAL_ERROR.
- FixedOption ChainAug 10, 2026
Option Chain as_of timestamp corrected
Option Chain meta.as_of now reports the correct UTC timestamp for the latest data included in the response.
- Previous values could be shifted by four or five hours. The correction applies automatically and requires no client changes.
- The response shape is unchanged:
meta.as_ofremains a nullable UTC ISO 8601 string.
- ChangedHistorical SQLBreakingAug 10, 2026
Minimum 15-minute data delay enforced
Historical SQL now returns only trades whose execution timestamps are at least 15 minutes old.
- The cutoff applies to all Historical SQL queries, including nested queries, joins, and aggregations.
- At 10:00:00 ET, the newest visible execution timestamp is 09:45:00 ET. Data can be older than 15 minutes, but never newer than the minimum delay.
- Success metadata now includes
meta.minimum_data_delay_minutes= 15 and the matchingX-OptionData-Historical-Sql-Minimum-Data-Delay-Minutesresponse header. - Use the Realtime WebSocket API when current-session trades are needed without the historical cutoff.
- AddedMarket StructureJul 27, 2026
Intraday GEX summary and update time
Added a nullable five-minute full-chain GEX summary and its update timestamp to v1 responses.
- Successful responses now include data.
intraday_gex: { spot,call_gex,put_gex} | null andmeta.intraday_gex_as_of: string | null. - During the regular session, flow and intraday GEX can refresh every five minutes. GEX includes zero-trade contracts; flow fields continue to include traded contracts only.
structure_as_ofidentifies when strike GEX, walls, Gamma Flip, Max Pain, OI, and expirations were last calculated. These values do not refresh with the five-minute flow update.- This is an additive v1 schema change; existing structure and flow fields retain their meaning.
- Successful responses now include data.
- AddedMarket StructureJul 24, 2026
Market Structure API response schema v1
Added the v1 success and error contracts for full-chain symbol snapshots.
- New endpoint: GET
/api/v1/market-structure/:symbol. Authenticate with Authorization: Bearer YOUR_API_KEY; add date=YYYY-MM-DD for a retained historical snapshot. - Successful responses use { data: { symbol,
symbol_meta, structure, flow }, meta: {effective_date,structure_as_of,flow_as_of} }. - Errors use { error: { code, message } }. Stable codes include INVALID_REQUEST, UNAUTHORIZED, SUBSCRIPTION_REQUIRED, SNAPSHOT_NOT_FOUND, SYMBOL_NOT_FOUND, RATE_LIMITED, UPSTREAM_UNAVAILABLE and INTERNAL_ERROR.
- The data and meta objects include call/put GEX by strike and expiration, GEX/OI walls, Gamma Flip and Max Pain by scope, plus the latest options-flow metrics.
- Symbol metadata is self-contained: underlying type, description, exchange, sector, market cap, shares, earnings, prices, average volume, historical volatility, IV30, IV Rank/Percentile, skew, butterfly, and term slope.
- Put GEX is signed negative. Net GEX, gross GEX, put/call ratios, and gamma regime are intentionally derivable from the strike data rather than duplicated in the payload.
- New endpoint: GET
- ChangedOption ChainBreakingJul 9, 2026
Option Chain response schema simplified
Breaking change: successful responses now use { data, meta: { trading_date, as_of } }, while errors use { error: { code, message } }.
meta.trading_dateis the returned market session.meta.as_ofis the latest data update represented in the response, formatted as a UTC ISO 8601 timestamp; it can be null when unavailable.- Contract rows removed symbol,
expiry_daysand mark. close was renamed tolast_price; strike andexpiration_dateare now non-null fields. - Removed response fields status,
api_version, beta, notice, entitlement, source, returned, filters and statistics. Thetest_moderequest parameter was also removed. - Errors now provide a stable code and message. Codes include INVALID_REQUEST, UNAUTHORIZED, SUBSCRIPTION_REQUIRED, REQUEST_TOO_BROAD, RATE_LIMITED, INTERNAL_ERROR and QUERY_TIMEOUT.
- Migration: read data directly instead of checking status === "SUCCESS"; replace
meta.datewithmeta.trading_date, and replace close withlast_price. - Requests whose result exceeds the maximum supported chain size return HTTP 422 with REQUEST_TOO_BROAD instead of partial data.
- ChangedHistorical SQLJul 3, 2026
Historical SQL validation rules expanded
Unsupported multi-table and table-function query forms now return validation errors.
- Comma-separated joins such as FROM
table_a,table_bare rejected. - Use the documented table names without a database prefix; references to other databases are rejected.
- Table functions such as url(), remote(), and merge(), plus # comments, are rejected.
- The documented single-table SELECT examples are unaffected.
- Comma-separated joins such as FROM
- AddedOption ChainJul 1, 2026
Strike price filters
Added strike filtering to the Option Chain request.
- New request parameters: strike for an exact match, plus
strike_minandstrike_maxfor an inclusive range. - strike cannot be combined with
strike_minorstrike_max. - Each value can be sent as a number or as a numeric string in a form-encoded request.
- New request parameters: strike for an exact match, plus
- RemovedOption ChainBreakingJun 26, 2026
Removed the limit request parameter
The API no longer accepts a client-supplied limit parameter.
- Use date,
expiration_date,put_call, strike,strike_min, orstrike_maxto narrow a symbol request. - As of July 9, 2026, requests that exceed the maximum response size return an error instead of partial data.
- Use date,
- RemovedOption ChainBreakingJun 25, 2026
Removed strike and expiry range parameters
Removed the older strike and expiry range parameters.
- Removed request parameters:
min_strike,max_strike,min_expiry_days, andmax_expiry_days. - Strike filtering returned on July 1, 2026 through strike,
strike_min, andstrike_max.
- Removed request parameters:
- RemovedOption ChainBreakingJun 25, 2026
Removed flow fields and include_flow
The optional flow fields and the include_flow toggle were removed from the response.
- Removed the
include_flowrequest parameter and the premium, size,trade_count,latest_trade_price,latest_trade_time, andvol_oi_ratioresponse fields. - At the time of this change, close continued to provide the latest trade price for each contract.
- Removed the
- ChangedGeneralBreakingJun 22, 2026
API base URL moved to www
The canonical API host is now the www subdomain.
- The base URL is now
https://www.optiondata.io; it was previouslyhttps://optiondata.io. - Update requests to
POST /api/historical/sqlandPOST /api/option-chainto use the new base URL.
- The base URL is now
- AddedOption ChainJun 21, 2026
Beta metadata in responses
Every Option Chain response now advertises its beta status.
- Responses include
meta.api_version="v1",meta.beta= true, andmeta.notice. - Responses also include
X-OptionData-Option-Chain-Beta: true. - These beta fields were later removed by the July 9, 2026 response schema change.
- Responses include
- FixedRealtime WebSocketMar 5, 2026
Corrected the documented sentiment value
The documented neutral sentiment value is NEUTRAL.
- Use
NEUTRAL. The previous documentation misspelled the value asNEUTRUAL.
- Use
- RemovedRealtime WebSocketBreakingFeb 24, 2026
Removed realtime trade-data fields
Several fields were dropped from real-time trade messages.
- Removed fields:
bid_size,ask_size, vega, theta, rho, and exchange.
- Removed fields:
This changelog covers data-API schema and contract changes. For product, billing, and platform updates, see the blog.