Unusual Whales API - Option Contract endpoints
Layer mapping: L1 (0DTE) load-bearing. This is the per-contract
substrate. Six endpoints scoped to a single option contract by its
OCC symbol (SPY240120C00500000 etc.) plus one chain-search endpoint
for finding contracts to query.
Together with uw-api-option-trade (flow alerts + full tape) and uw-api-gex-greeks (positional Greeks), this is the working set for the SPY hunter’s signal engine.
1. Base contract
| Property | Value |
|---|---|
| Base URL | https://api.unusualwhales.com |
| Auth | Authorization: Bearer <token> header |
| Response envelope | { "data": [...] } |
| Status codes | 200, 422, 500 |
2. Endpoint matrix
| # | Path | Purpose |
|---|---|---|
| 1 | GET /api/stock/{ticker}/option-contracts | Chain search; find contracts matching filters |
| 2 | GET /api/option-contract/{id}/flow | Trade-level flow on one contract (per-trade Greeks) |
| 3 | GET /api/option-contract/{id}/intraday | Intraday tick/bar data on one contract |
| 4 | GET /api/option-contract/{id}/history | Historical daily summary for one contract |
| 5 | GET /api/option-contract/{id}/volume-profile | Volume-at-price profile for one contract |
| 6 | GET /api/stock/{ticker}/expiry-breakdown | Per-expiry rollup across all of a ticker’s contracts |
Convention. Endpoints 2-5 take an OCC option symbol as {id}
(e.g. TSLA230526P00167500). Endpoints 1 and 6 are ticker-scoped
(at the underlying level).
3. GET /api/stock/{ticker}/option-contracts - Chain search
Find contracts for a ticker matching filter criteria. Use this to get an OCC symbol that you then feed into endpoints 2-5.
Path parameter: ticker (e.g. SPY).
Query parameters:
| Param | Type | Required | Default | Range |
|---|---|---|---|---|
expiry | ISO date | no | - | Filter to one expiration |
option_type | enum | no | - | call, Call, put, Put |
vol_greater_oi | bool | no | - | Only chains where vol > OI |
exclude_zero_vol_chains | bool | no | - | Drop zero-volume contracts |
exclude_zero_dte | bool | no | - | Drop same-day expiry |
exclude_zero_oi_chains | bool | no | - | Drop zero-OI contracts |
maybe_otm_only | bool | no | - | OTM contracts only |
option_symbol[] | array | no | - | Filter to specific OCC symbols |
limit | int | no | 500 | 1 to 500 |
page | int | no | - | 0-indexed |
Response per contract:
| Field | Type | Description |
|---|---|---|
option_symbol | string | OCC symbol |
volume, open_interest, prev_oi | int | Today, current, prior |
bid_volume, ask_volume, mid_volume, cross_volume, floor_volume, no_side_volume | int | Side breakdown |
sweep_volume, multi_leg_volume, stock_multi_leg_volume | int | Trade-type breakdown |
last_price, avg_price, high_price, low_price | decimal | Today’s OHLC |
nbbo_bid, nbbo_ask | decimal | Quote |
implied_volatility | decimal | IV |
total_premium | decimal | $ premium |
MK3 use. Two patterns:
- 0DTE chain discovery: pull
?expiry=TODAY&exclude_zero_vol_chains=trueto get the active 0DTE strikes on SPY. - OTM unusual activity scan:
?vol_greater_oi=true&maybe_otm_only=true&expiry=TODAYto find 0DTE OTM contracts where volume already exceeds OI (a classic “unusual” pattern).
The sweep_volume and floor_volume fields are pre-classified - no
need to derive these from per-trade data.
4. GET /api/option-contract/{id}/flow - Per-contract trade flow
Trade-level flow on one contract with per-trade Greeks (huge value).
Path parameter: id = OCC symbol.
Query parameters:
| Param | Type | Required | Default | Notes |
|---|---|---|---|---|
side | enum | no | ALL | ALL, ASK, BID, MID |
min_premium | int | no | 0 | Min trade premium |
limit | int | no | unlimited | >= 1 |
date | date | no | last trading date | - |
Response per trade:
| Field | Type | Description |
|---|---|---|
id | UUID | Trade ID |
underlying_symbol | string | Underlying |
option_chain_id | string | Chain ID |
expiry | date | Expiration |
strike | decimal | Strike |
option_type | string | call or put |
executed_at | ISO 8601 | Execution time |
price, premium, size | decimal/int | Trade details |
volume, open_interest | int | Contract context at trade |
delta, gamma, theta, vega, rho | decimal | Per-trade Greeks |
implied_volatility | decimal | IV at trade |
nbbo_ask, nbbo_bid | decimal | Quote at trade |
ask_vol, bid_vol, mid_vol, multi_vol | int | Side breakdown |
exchange | string | Venue |
full_name, sector, industry_type | strings | Underlying classification |
marketcap | decimal | Underlying market cap |
tags | array | Classification tags |
canceled | bool | Print canceled |
MK3 use (L1 critical). This is the per-trade Greek substrate for the IMPULSE engine. Per 2026-05-15-mk3-data-foundation-constraint, MK2 never recorded raw UW stream; this endpoint is the path to that recording for MK3 going forward.
Two derived feature families:
| Feature family | What you compute |
|---|---|
| Aggressor flow | side=ASK premium - side=BID premium, rolled to 1-min |
| Greek delta impact | sum(delta * size * 100) (delta-equivalent shares) |
| Greek gamma exposure | sum(gamma * size * 100) (gamma-equivalent shares) |
| Greek vega flow | sum(vega * size) |
Recording warning. Polling this endpoint per-contract with
limit=unlimited and no filter could be huge. For SPY at the
0DTE level, hundreds of strikes have activity per day; conservative
default: min_premium=10000 (cuts noise) and poll the top-20 by
volume only.
5. GET /api/option-contract/{id}/intraday - Intraday data
Intraday tick / bar data for one contract.
Path parameter: id = OCC symbol.
Query parameters (inferred - not fetched in this pass):
date(default last trading date)interval(likely1m,5m, etc.)
Response (inferred): time-bucketed OHLC + volume + premium for the contract. Useful for chart-style analysis of a single option’s intraday behavior. First real fetch needs to update with actual field set.
MK3 use. Secondary. The per-trade flow endpoint (#4) is richer; use intraday for backtest replay where minute-bar resolution is enough.
6. GET /api/option-contract/{id}/history - Daily history
Historical daily summary for one contract.
Response (inferred): per-trading-day rows with daily summary (OHLC, volume, OI, IV closing). For OOS backtest framing of how a specific contract traded over its life.
MK3 use. Lookback at session start - “did this strike see unusual activity yesterday or last week?“. Useful for context, not for real-time decisioning.
7. GET /api/option-contract/{id}/volume-profile - Vol at price
Volume distribution across price levels for one contract.
Response (inferred): array of (price_level, volume) rows.
Helpful for identifying where the contract found acceptance vs
rejection - particularly the strike’s own equilibrium pricing.
MK3 use. Niche. Useful when one strike is suspected of being a liquidity magnet. Not part of the default Setup Hunter feed.
8. GET /api/stock/{ticker}/expiry-breakdown - Per-expiry rollup
Per-expiry summary across all of a ticker’s contracts.
Response (inferred): one row per expiration with aggregate volume, OI, premium, IV per side.
MK3 use. Session-start snapshot. Identifies which expirations are getting flow. For SPY hunter: confirms 0DTE is the heaviest expiration today (it usually is on SPY) and quantifies the dominance ratio (0DTE volume / total volume).
9. Cross-endpoint workflow for SPY hunter
Session start:
-> GET /api/stock/SPY/expiry-breakdown
(which expirations are active today)
-> GET /api/stock/SPY/option-contracts?expiry=TODAY
(today's 0DTE chain with vol/OI per strike)
-> identify top-20 contracts by volume
-> For each top-20 contract:
-> GET /api/option-contract/{id}/history?limit=5
(recent daily context)
RTH polling (every minute on top-20 contracts):
-> GET /api/option-contract/{id}/flow?date=TODAY&min_premium=10000
-> de-dupe by trade id
-> compute per-trade aggressor + Greek-equivalent features
-> publish to MessageBus
10. Nautilus integration shape
- Custom data classes:
UWOptionContract(one-shot from chain search)UWOptionContractTrade(one per trade from /flow)UWOptionContractDailyBar(from /history)UWOptionContractIntradayBar(from /intraday)
- Polling Actors:
UWChainDiscoveryActor- once at session start (chain search)UWOptionFlowActor- per-minute polling on the top-20 chain
- Determinism: per nautilus-custom-data -
ts_eventfromexecuted_at,ts_initfrom receive time.
11. Known gaps
- Intraday / history / volume-profile schemas not fully fetched yet. First real fetch needs to update these sections.
tagstaxonomy on /flow trades not enumerated in the docs./flowhaslimit=unlimitedby default. Footgun for SPY - always pass a cap and amin_premiumfilter.- The IMPULSE engine substrate question. Per 2026-05-15-mk3-data-foundation-constraint, MK2 never recorded per-trade Greek flow. This endpoint provides exactly that data going forward. MK3 should start recording from day-zero of the paper rollout so future OOS validations have it.
12. Source URLs
https://api.unusualwhales.com/docs/operations/PublicApi.OptionContractController.option_contractshttps://api.unusualwhales.com/docs/operations/PublicApi.OptionContractController.flowhttps://api.unusualwhales.com/docs/operations/PublicApi.OptionContractController.intradayhttps://api.unusualwhales.com/docs/operations/PublicApi.OptionContractController.historyhttps://api.unusualwhales.com/docs/operations/PublicApi.OptionContractController.volume_profilehttps://api.unusualwhales.com/docs/operations/PublicApi.OptionContractController.expiry_breakdown
cortana-north-star uw-api-option-trade uw-api-gex-greeks uw-api-tide 2026-05-15-mk3-data-foundation-constraint 2026-05-22-uw-historical-findings 2026-05-15-mk3-setup-hunter-architecture