Historical API: Point-in-Time Replay
Ask what GEX, gamma flip, VRP, narrative, max pain, or the full stock summary looked like at any minute in history - returned in the same response shape as the live API. Backed by 6.7 B option rows since April 2018.
What's different from the live API
Every endpoint you already know on the live API is mirrored here. Point your existing SDK at a different host, add one query parameter, and you have a backtest-ready data source. No new response shapes to learn - GEX, gamma flip, regime labels, narrative text, VRP percentiles, SVI surfaces and everything else come back in the exact same JSON you already parse.
The analytics run through the same code path as live - so any fix or refinement that lands on api.flashalpha.com shows up here on the next deploy. The only difference is the data store underneath: minute-level quotes and greeks going back to April 2018 instead of the live feed.
historical.flashalpha.com
X-Api-Key as live. Alpha tier on every endpoint.The at parameter
Every analytics endpoint takes a required at query parameter - the as-of timestamp. Treated as ET wall-clock (same clock as the stored data). Do not shift by UTC offset.
| Format | Example | Semantics |
|---|---|---|
yyyy-MM-ddTHH:mm:ss | 2026-03-05T15:30:00 | Minute-level as-of |
yyyy-MM-dd | 2026-03-05 | Defaults to 16:00 ET (session close) |
Intraday-accurate vs EOD-stamped
Not every underlying series is minute-resolution. Here's what moves at the minute you ask for, and what's stamped at the close of that trade day:
| Data layer | Granularity | Notes |
|---|---|---|
| Option quotes + greeks (bid, ask, iv, δ, γ, θ, ν, ρ, vanna, charm) | 1 minute (9:30 → 16:00 ET) | Last value per contract at or before at |
| Stock spot (bid, ask, mid) | 1 minute | Same |
| Open interest | EOD | One value per trade day, applied to all intraday at= on that day |
| SVI params, forward prices | EOD | |
| Macro: VIX, VVIX, SKEW, MOVE, SPX, VIX9D/3M/6M, DGS10 | EOD | |
| Realized-vol lookback closes (HV20/HV60) | EOD | Last tick per day |
Why this is OK: intraday GEX / DEX / VEX / CHEX shifts are driven by greek + spot changes; OI is dealer-positioning context and barely moves intraday anyway.
Coverage: GET /v1/tickers
The only historical-specific endpoint. Lists every symbol with historical coverage, the date range, and any gaps. Regenerated after every backfill run, so whatever comes back is the current ground truth for what you can query.
Auth: required (X-Api-Key, Alpha tier)
Query params: symbol=SPY (optional) - returns a single object instead of the wrapped list
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://historical.flashalpha.com/v1/tickers"
Response 200:
{
"count": 1,
"tickers": [
{
"symbol": "SPY",
"coverage": {
"first": "2018-04-16",
"last": "2026-04-02",
"total_days": 2909,
"healthy_days": 1972
},
"tables": {
"stocks_days": 2009,
"options_days": 1972,
"option_eod_days": 2006,
"svi_days": 1972
},
"gaps": {
"missing_eod": 3,
"missing_svi": 36,
"uncovered_calendar": 3
},
"updated_at": "2026-04-14T07:07:36.55353"
}
]
}
| Field | Meaning |
|---|---|
coverage.first / coverage.last | Date range where every data layer is healthy - you can query any minute inside this window |
coverage.healthy_days | Trading days on which every data layer has data |
tables.*_days | Per-layer day counts - useful when a single layer is lagging |
gaps.missing_eod | Days where EOD option data hasn't been pulled yet (usually resolves on the next backfill) |
gaps.missing_svi | Days without an SVI fit |
gaps.uncovered_calendar | NYSE trading days that were never pulled (genuine exchange-closed days like 2018-12-05 Bush funeral, 2025-01-09 Carter funeral) |
updated_at | UTC timestamp of the last coverage refresh |
Available symbols. SPY is fully backfilled from 2018-04-16 through 2026-04-02 and extended on every refresh. Additional symbols are backfilled on demand - ask us to prioritize what you need. Live coverage is always queryable at GET /v1/tickers.
Analytics endpoints
Every live analytics endpoint is mirrored with the addition of a required at. Paths, query params, and response shapes are identical to the live docs - don't re-document them here. Click through for the per-endpoint reference:
VRP date-bounding matters. VRP percentile and z-score only consider history prior to at, so at any historical point the percentile reflects only what was knowable at that moment. No future leakage in backtests.
Example: replay March 16, 2020 (COVID crash, -12% close)
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://historical.flashalpha.com/v1/exposure/summary/SPY?at=2020-03-16T15:30:00"
{
"symbol": "SPY",
"underlying_price": 246.01,
"as_of": "2020-03-16T15:30:00",
"gamma_flip": 270.92,
"regime": "negative_gamma",
"exposures": {
"net_gex": -2633970601,
"net_dex": -169419489077,
"net_vex": 152461756844,
"net_chex": -13122349
},
"interpretation": {
"gamma": "Dealers short gamma - moves amplified, trend following likely",
"vanna": "Vol up = dealers buy delta - downside dampened if vol spikes",
"charm": "Time decay pushing dealers to sell - pressure into close"
}
}
Real dealer positioning, at 15:30 ET on the day SPY closed -12%. Not a re-derived reconstruction - these are the minute-level greeks as they were at that moment, run through today's analytics.
Data freshness
Every field is one of three kinds: minute-level (changes every bar), EOD-stamped (one value per trade day applied to all intraday at= queries), or not stored at minute granularity (returns 0 or null).
| Field | Granularity | Sample value at intraday at= |
|---|---|---|
| Stock and option bid / ask / mid / last | 1 minute | real number |
| Implied vol per contract (BSM) | 1 minute | real number |
| Greeks (delta, gamma, theta, vega, rho, vanna, charm) | 1 minute | real number |
| Open interest | EOD | real integer (most recent EOD snapshot) |
svi_vol per contract | EOD-aligned at= only; intraday returns null - use implied_vol | null with svi_vol_gated: "backtest_mode" |
| SVI parameters, forward prices, ATM IV, RV ladder | EOD | real number (most recent EOD) |
| Macro (VIX, VVIX, SKEW, MOVE, SPX, VIX9D/3M/6M, DGS10) | EOD | real number (most recent EOD) |
| VRP percentile / z-score | EOD; first ~60 trading days of any new window return null by design (leak-free) | real number after warm-up; null inside warm-up |
| Contract and aggregate volume | Not stored | 0 (integer) |
bidSize, askSize on optionquote | Not stored | 0 (integer) |
Prior-day OI deltas (oi_change) | Not stored | null |
narrative.data.top_oi_changes | Not stored | [] (empty array) |
vrp.macro.hy_spread | Not stored historically | hard-coded 3.5 |
| CME VIX futures, CNN Fear & Greed | Not stored | null |
The Sample value column is what codegen consumers and JSON-shape-aware code (test fixtures, mocks, OpenAPI schemas) should expect when binding against the response. For 0DTE analytics (gamma walls, pin probability, full greek coverage on near-zero-DTE chains), call at=YYYY-MM-DD for the EOD snapshot. Intraday minute-level greeks for very-short-DTE contracts are sparse, so aggregate exposures may read as 0 at minute resolution; the EOD call returns the close-of-session 0DTE picture in full.
How coverage grows
New trading days and new symbols are added by a gap-aware backfill on a schedule. The coverage window on /v1/tickers reflects what you can query right now; it extends forward on each refresh. To verify a specific date inside the window, hit any analytics endpoint at that date — a 200 confirms the day is queryable.
Latency & caching
Point-in-time reads are fast (~50–300 ms typical). Composite endpoints that rebuild surfaces on demand - /v1/adv_volatility and /v1/stock/{symbol}/summary - can take ~500–1500 ms on a cold request for a new (symbol, at). Cache at your proxy or client for repeat queries on the same tuple - responses are deterministic for a given at, so they're safe to cache indefinitely.
Try it live
Point-and-replay - pick an endpoint, pick a minute in history, hit Replay. Works with your existing API key.
Ready to build?
Get your free API key and start pulling live options data in 30 seconds.