Unusual Whales API - ETF endpoints

Layer mapping: L1 (0DTE) load-bearing. SPY is an ETF. The ETF endpoints describe SPY directly: its holdings (the top-weight names that drive intraday SPY moves), its sector + country composition, its in/outflow tape, and its fund-level metadata. For L2/L3, the same endpoints describe other ETFs the strategy might trade.

Five endpoints, all path-scoped by ETF ticker.

1. Base contract

PropertyValue
Base URLhttps://api.unusualwhales.com
AuthAuthorization: Bearer <token> header
Response envelope{ "data": ... }
Status codes200, 422, 500
Rate limitsNot specified

2. Endpoint matrix

#PathPurposeL1 use
1GET /api/etfs/{ticker}/infoFund metadata (AUM, expense ratio, holdings count, options volume)Once-per-day context
2GET /api/etfs/{ticker}/holdingsPer-constituent holdings list with pricing + options flowDaily; identify top-25 SPY weights
3GET /api/etfs/{ticker}/weightsSector + country weight breakdownDaily; sector regime overlay
4GET /api/etfs/{ticker}/in-outflowDaily in/outflow time series with FOMC flagPer-day flow tape for SPY
5GET /api/etfs/{ticker}/exposureWhich ETFs hold ticker X (inverse lookup)L2 mostly - “which ETFs own AAPL”

Key insight. Endpoints 1-4 use the path ticker as the ETF itself (SPY). Endpoint 5 inverts: the path ticker is the holding (e.g. AAPL), and the response lists ETFs holding it.

3. GET /api/etfs/{ticker}/info

Fund-level metadata.

Path: ticker = ETF symbol (e.g. SPY).

Query: none documented.

Response fields:

FieldTypeDescription
namestringFull ETF name
etf_companystringIssuer (e.g. SPDR / State Street)
descriptionstringProspectus summary
aumstringAssets under management
expense_ratiostringAnnual expense ratio (%)
inception_dateISO dateLaunch date
domicilestringCountry of domicile
websitestringIssuer URL
holdings_countintNumber of constituents
avg30_volumestring30-day average daily share volume
stock_volintToday’s stock volume
has_optionsboolOptions trade
opt_volintToday’s total options volume
call_volintToday’s call volume
put_volintToday’s put volume

MK3 use: session-context. Pull once at session start. The put_vol / call_vol ratio is a real-time put-call indicator at the ETF level (different from the historical UW P/C ratio).

4. GET /api/etfs/{ticker}/holdings

Full constituent list with per-name pricing, options flow, and weights.

Path: ticker = ETF symbol.

Query: none documented.

Response per constituent:

FieldTypeDescription
tickerstringConstituent symbol
name, short_namestringCompany name + abbreviation
sectorstringGICS sector
typestringE.g. "stock"
weightstringPortfolio weight (%)
sharesintNumber of shares held by the ETF
close, open, high, low, prev_pricestringToday’s OHLC + prior close
volume, avg30_volumeint / stringToday’s + 30d avg volume
week52_high, week52_lowstring52-week range
has_optionsboolOptions trade
call_volume, put_volumeintToday’s option volumes
call_premium, put_premiumstringToday’s option premium
bullish_premium, bearish_premiumstringUW-classified directional premium

MK3 use (high value). This is the single most useful endpoint for an SPY hunter:

  1. Identify the top-25 SPY weights. The top ~7 names (AAPL, MSFT, NVDA, AMZN, META, GOOGL, GOOG) typically account for 25%+ of SPY. When they move together, SPY moves; when they diverge, internal index dispersion is high.
  2. Per-constituent option flow. bullish_premium - bearish_premium on the top-25 = a basket-level flow signal. Weighted by weight it approximates a SPY-equivalent flow proxy that’s richer than just looking at SPY’s own options flow.
  3. Dispersion check. If top names have heavy call flow but mid-cap constituents have heavy put flow, SPY is being held up by mega-caps only - thin breadth. Setup Hunter can gate on breadth.

This is also the path to building a “SPY-implied flow tape” feature that improves on the raw flow_alerts for SPY.

5. GET /api/etfs/{ticker}/weights

Sector + country weight breakdown.

Path: ticker = ETF symbol.

Query: none documented.

Response:

{
  "data": {
    "sector": [
      { "sector": "Technology", "weight": "29.71" },
      ...
    ],
    "country": [
      { "country": "United States", "weight": "96.93" },
      ...
    ]
  }
}

MK3 use. Daily session-start pull. Sector weights change slowly, but knowing SPY is ~30% Tech (vs the historical 25%) frames how sector-specific news flows back to the index. Country weights for SPY are nearly 100% US - useful confirmation only.

6. GET /api/etfs/{ticker}/in-outflow

Daily in/outflow time series for the ETF itself.

Path: ticker = ETF symbol.

Query parameters:

ParamTypeRequiredDefault
start_datedatenolast trading date
end_datedatenolast trading date

Response per row:

FieldTypeDescription
dateISO dateTrading date
changeintNet share change (creations minus redemptions)
change_premstringDollar value of the share change
closestringClosing price
volumeintDay’s volume
is_fomcboolFOMC meeting on this date

MK3 use. The is_fomc flag is convenient - it lets you tag flows on FOMC days separately from normal days. Pull a rolling 30-day window at session start; large recent outflows on SPY = real risk-off context that the price tape alone won’t show.

7. GET /api/etfs/{ticker}/exposure

Inverse lookup: which ETFs hold this ticker.

Path: ticker = the constituent symbol (e.g. AAPL), not the ETF.

Query: none documented.

Response per row:

FieldTypeDescription
etfstringETF ticker holding the constituent
full_namestringETF full name
weightstringConstituent’s weight in that ETF
sharesintShares held by that ETF
last_price, prev_pricestringETF prices

MK3 use. Low for L1. For L2 (single-stock swings), this matters: when buying AAPL, knowing it’s in 600+ ETFs means broad-market flow pulls it - reduces alpha vs SPY. Filed for L2.

8. Cross-endpoint workflow for SPY hunter

Session start (08:00 ET):
  -> GET /api/etfs/SPY/info          (one row, AUM + option volumes)
  -> GET /api/etfs/SPY/holdings      (~500 rows, top-25 are the load)
  -> GET /api/etfs/SPY/weights       (sector + country snapshot)
  -> GET /api/etfs/SPY/in-outflow?start_date=T-30  (30d flow tape)

Derived features cached for the session:
  - spy_top25_symbols + weights
  - spy_sector_weights
  - spy_30d_net_flow
  - spy_30d_fomc_flow_delta (FOMC vs non-FOMC)

Intraday:
  -> No further /etfs polling needed for SPY (these are slow-moving)
  -> Use top-25 list to drive per-name option flow + dark-pool queries

9. Nautilus integration shape

  • One-time session-start fetch for endpoints 1-4 against SPY.
  • Cache as a UWEtfContext snapshot in memory.
  • Expose top_25_constituents and sector_weights as queryable attributes for downstream signal Actors.
  • Endpoint 5 (/exposure) is on-demand only - probably not wired into L1 at all.

10. Known gaps

  • No realtime push for in/outflow. Daily only.
  • Holdings cadence not documented - assumed daily, but the weight field changes very slowly (rebalance schedule). Verify how often it refreshes.
  • The “options flow” fields on holdings (bullish_premium, bearish_premium) overlap with uw-api-alerts flow_alerts noti_type - need to confirm whether they aggregate the same source or different.

11. Source URLs

  • https://api.unusualwhales.com/docs/operations/PublicApi.EtfController.info
  • https://api.unusualwhales.com/docs/operations/PublicApi.EtfController.holdings
  • https://api.unusualwhales.com/docs/operations/PublicApi.EtfController.weights
  • https://api.unusualwhales.com/docs/operations/PublicApi.EtfController.in_outflow
  • https://api.unusualwhales.com/docs/operations/PublicApi.EtfController.exposure

cortana-north-star uw-api-gex-greeks uw-api-darkpool uw-api-alerts 2026-05-15-mk3-setup-hunter-architecture