> ## Documentation Index
> Fetch the complete documentation index at: https://api.unusualwhales.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> API requests use the base URL https://api.unusualwhales.com and require a bearer token in the `Authorization` header (`Authorization: Bearer <API_KEY>`). Create and manage API tokens at https://unusualwhales.com/dashboard/api.
> For live market data inside an AI tool, use the Unusual Whales MCP server at https://unusualwhales.com/public-api/mcp.
> Instructions for agents using Unusual Whales tools: https://unusualwhales.com/skill.md

# WebSocket

Stream live data over a WebSocket connection. Requires the Advanced tier or above.

You can find fully-functional streaming examples here:

* Stream Greeks by Strike and by Expiry to a DuckDB Database (python): [https://github.com/unusual-whales/api-examples/tree/main/examples/ws-stream-spot-greeks-by-strike-by-expiry](https://github.com/unusual-whales/api-examples/tree/main/examples/ws-stream-spot-greeks-by-strike-by-expiry)
* Stream Flow Alerts to a SQLite Database (python): [https://github.com/unusual-whales/api-examples/tree/main/examples/ws-stream-flow-alerts-to-sqlite](https://github.com/unusual-whales/api-examples/tree/main/examples/ws-stream-flow-alerts-to-sqlite)
* Stream Periscope Greek Exposure to a Partitioned Parquet Store (python): [https://github.com/unusual-whales/api-examples/tree/main/examples/ws-stream-periscope-greek-exposure](https://github.com/unusual-whales/api-examples/tree/main/examples/ws-stream-periscope-greek-exposure)
* Stream Multiple Channels to Multiple Outfiles (python): [https://github.com/unusual-whales/api-examples/tree/main/examples/ws-multi-channel-multi-output](https://github.com/unusual-whales/api-examples/tree/main/examples/ws-multi-channel-multi-output)
* Stream Multiple Channels to Multiple Outfiles (javascript): [https://github.com/unusual-whales/api-examples/tree/main/examples/ws-multi-channel-multi-output-nodejs](https://github.com/unusual-whales/api-examples/tree/main/examples/ws-multi-channel-multi-output-nodejs)

If you are an AI agent or working with an AI agent there is a websocket Skill available at: [https://unusualwhales.com/skills/websocket.md](https://unusualwhales.com/skills/websocket.md)

## Connecting

Connect to the socket with your API token on the query string, then join a channel.

```
wss://api.unusualwhales.com/socket?token=YOUR_API_KEY
```

Join a channel by sending:

```json theme={null}
{ "channel": "option_trades:SPY", "msg_type": "join" }
```

A successful join is acknowledged with:

```json theme={null}
["option_trades:SPY", { "response": {}, "status": "ok" }]
```

Data frames then arrive as `["<channel>", { ... }]`. Send a real `User-Agent` on the handshake.

Scope a channel to a ticker with a colon, for example `gex_strike:SPY`. See [Channels](#channels) for every channel.

### Connect with websocat

For a python example script that streams gex by ticker (gex:TICKER), flow alerts (flow-alerts), and all TSLA option trades (option\_trades:TSLA), see our "examples" repo on Github: [https://github.com/unusual-whales/api-examples/tree/main/examples/ws-multi-channel-multi-output](https://github.com/unusual-whales/api-examples/tree/main/examples/ws-multi-channel-multi-output)

We will use [websocat](https://github.com/vi/websocat) to demonstrate how to connect to the WebSocket server.

```bash theme={null}
websocat "wss://api.unusualwhales.com/socket?token=<YOUR_API_TOKEN>"
{"channel":"option_trades","msg_type":"join"}
```

The server will then reply with

```bash theme={null}
["option_trades",{"response":{},"status":"ok"}]
```

indicating that the connection was successful.

You will then receive data in the following format:

```bash theme={null}
[<CHANNEL_NAME>, <PAYLOAD>]
```

during market hours.

To receive the trades only for a specific ticker, use the following command:

```bash theme={null}
{"channel":"option_trades:TSLA","msg_type":"join"}
```

You can join multiple channels with the same websocket connection:

```bash theme={null}
websocat "wss://api.unusualwhales.com/socket?token=<YOUR_API_TOKEN>"
{"channel":"option_trades","msg_type":"join"}
["option_trades",{"response":{},"status":"ok"}]
{"channel":"option_trades:JPM","msg_type":"join"}
["option_trades:JPM",{"response":{},"status":"ok"}]
```

## Channels

The following channels are available:

| Channel | Description |
| - | - |
| [`option_trades`](/docs/websocket/option-trades) | Receive live option trades throughout the trading session. Expect 6-10M records per day. |
| [`option_trades:TICKER`](/docs/websocket/option-trades) | Similar to `option_trades` but receive all trades only for the specified ticker. |
| [`flow-alerts`](/docs/websocket/flow-alerts) | Receive live flow alerts (all of them unfiltered). This data can be used to build views like [https://unusualwhales.com/option-flow-alerts](https://unusualwhales.com/option-flow-alerts). |
| [`price`](/docs/websocket/price) | Receive live price updates for every ticker at once. |
| [`price:TICKER`](/docs/websocket/price) | Receive live price updates for the given ticker. |
| [`news`](/docs/websocket/news) | Receive live headline news (Truth Social posts + aggregator news). |
| [`lit_trades`](/docs/websocket/lit-trades) | Receive live lit (exchange-based) trades throughout the trading session. |
| [`off_lit_trades`](/docs/websocket/off-lit-trades) | Receive live off-lit (dark pool) trades throughout the trading session. |
| [`gex`](/docs/websocket/gex) | Receive live gex updates for every ticker at once. |
| [`gex:TICKER`](/docs/websocket/gex) | Receive live gex update for the given ticker. |
| [`gex_strike`](/docs/websocket/gex) | Receive live gex strike updates for every strike of every ticker. |
| [`gex_strike:TICKER`](/docs/websocket/gex) | Receive live gex strike updates for every strike of the given ticker. |
| [`gex_strike_expiry`](/docs/websocket/gex) | Receive live gex strike updates for every strike & expiry of every ticker. |
| [`gex_strike_expiry:TICKER`](/docs/websocket/gex) | Receive live gex strike updates for every strike & expiry of the given ticker. |
| [`periscope`](/docs/websocket/periscope) | Receive live periscope market-maker greek exposures (gamma/charm/vanna) per strike & expiry for every index ticker (SPX, VIX, XSP, NANOS). Not available on the enterprise and enterprise startup plans. |
| [`periscope:TICKER`](/docs/websocket/periscope) | Receive live periscope market-maker greek exposures per strike & expiry for the given index ticker. Not available on the enterprise and enterprise startup plans. |
| [`greeks`](/docs/websocket/greeks) | Receive live per-contract option greeks (first- and second-order) for every contract of every underlying. |
| [`greeks:TICKER`](/docs/websocket/greeks) | Receive live per-contract option greeks (first- and second-order) for every contract of the given underlying. |
| [`market_tide`](/docs/websocket/market-tide) | Receive live updates of both the market tide and the otm market tide. |
| [`otm_market_tide`](/docs/websocket/market-tide) | Receive live updates of only the otm market tide. It carries the `otm_net_*` values of `market_tide` under unprefixed names. |
| [`net_flow:TICKER`](/docs/websocket/net-flow) | Receive live net call/put premium and volume aggregates for the specified ticker to build a net prem view. |
| [`interval_flow`](/docs/websocket/ticker-interval-flow) | Receive per interval option flow statistics for a ticker (sweeps, floors, multilegs, Greek flows, IV, net prem). Use this to build alert systems to spot spikes in tickers |
| [`contract_screener`](/docs/websocket/contract-screener) | Receive live option contract snapshots (Greeks, side volumes, OI growth indicators). This your entry point to build a screener on top of option contracts. |
| [`trading_halts`](/docs/websocket/trading-halts) | Receive live trading state changes (halts, resumes, LULD pauses) for individual tickers. |
| [`custom_alerts`](/docs/websocket/custom-alerts) | Receive notifications matching the alert configurations on your own Unusual Whales account. |
| `futures_trades` | Receive live CME futures trade prints across all contracts. Available on the Advanced API tier, or with the `futures` add-on — email [oskar@unusualwhales.com](mailto:oskar@unusualwhales.com), [enterprise@unusualwhales.com](mailto:enterprise@unusualwhales.com) or [nastja.petrovic@unusualwhales.com](mailto:nastja.petrovic@unusualwhales.com) for access. |
| `futures:TICKER` | Similar to `futures_trades` but only for the specified dated contract, e.g. `futures:ESU6`. Available on the Advanced API tier, or with the `futures` add-on. |
| [`futures_blocks`](/docs/websocket/futures-block-trades) | Receive live CME block trades in futures contracts and multi-leg futures strategies, across all symbols. Available on the Advanced API tier, or with the `futures` add-on. |
| [`futures_blocks:SYMBOL`](/docs/websocket/futures-block-trades) | Similar to `futures_blocks` but only for the specified contract or strategy symbol, e.g. `futures_blocks:ESZ6`. Available on the Advanced API tier, or with the `futures` add-on. |
| [`interpolated_iv`](/docs/websocket/interpolated-iv) | Receive live interpolated IV and expected move updates at fixed horizons (1-365 days) for every ticker at once. |
| [`interpolated_iv:TICKER`](/docs/websocket/interpolated-iv) | Receive live interpolated IV and expected move updates at fixed horizons for the given ticker. |
| [`iv_term_structure`](/docs/websocket/iv-term-structure) | Receive live ATM IV and expected move updates per real option expiry for every ticker at once. |
| [`iv_term_structure:TICKER`](/docs/websocket/iv-term-structure) | Receive live ATM IV and expected move updates per real option expiry for the given ticker. |
| [`risk_reversal_skew`](/docs/websocket/risk-reversal-skew) | Receive live 25- and 10-delta risk reversal skew (put IV minus call IV) per expiry for every ticker at once. |
| [`quotes`](/docs/websocket/stock-quotes) | Receive live best bid and ask (top of book) updates for every ticker at once. This is a high volume firehose - prefer `quotes:TICKER` unless you need the full tape. |
| [`quotes:TICKER`](/docs/websocket/stock-quotes) | Receive live best bid and ask (top of book) updates for the given ticker. |
| [`greek_flow`](/docs/websocket/greek-flow) | Receive live delta & vega flow from option trades for every ticker at once, bucketed to the minute and updated about once a second. |
| [`greek_flow:TICKER`](/docs/websocket/greek-flow) | The same for the given ticker. Silent while that ticker has no option trades. |
| [`greek_flow_expiry`](/docs/websocket/greek-flow-by-expiry) | Same as `greek_flow`, additionally broken out by option expiry, for every ticker at once. |
| [`greek_flow_expiry:TICKER`](/docs/websocket/greek-flow-by-expiry) | Per-minute delta & vega flow broken out by option expiry for the given ticker. |
| [`stock_screener`](/docs/websocket/stock-screener) | Receive the live stock screener row of every ticker (option flow, price, volatility, open interest, GEX, fundamentals, quote and daily technical indicators). |

The `option_trades` channel will stream all 6,000,000 option trades in real-time, `option_trades:<TICKER>` will stream
all option trades for the given ticker in real-time.

`flow-alerts` will stream from the alerts [page](https://unusualwhales.com/option-flow-alerts?limit=50)

## Using a client

If you are using Python, you can use the [websocket-client](https://github.com/websocket-client/websocket-client) library to connect to the server.

```python theme={null}
import websocket
import time
import rel
import json

def on_message(ws, msg):
    msg = json.loads(msg)
    channel, payload = msg
    print(f"Got a message on channel {channel}: Payload: {payload}")

def on_error(ws, error):
    print(error)

def on_close(ws, close_status_code, close_msg):
    print("### closed ###")

def on_open(ws):
    print("Opened connection")
    msg = {"channel":"option_trades","msg_type":"join"}
    ws.send(json.dumps(msg))

if __name__ == "__main__":
    websocket.enableTrace(False)
    ws = websocket.WebSocketApp("wss://api.unusualwhales.com/socket?token=<YOUR_TOKEN>",
                              on_open=on_open,
                              on_message=on_message,
                              on_error=on_error,
                              on_close=on_close)

    ws.run_forever(dispatcher=rel, reconnect=5)  # Set dispatcher to automatic reconnection, 5 second reconnect delay if connection closed unexpectedly
    rel.signal(2, rel.abort)  # Keyboard Interrupt
    rel.dispatch()
```

## Connections

Connect each API token from a single machine. The same token connected from more than one machine at a time is not supported and results in dropped connections. Use a separate token per host.

## Buffering

Buffer incoming messages and write them on an interval rather than once per message. A consumer that writes to storage on every payload will fall behind on high-volume channels and be dropped as a slow client. Flush on a timer, for example once per second, or after a set number of records, whichever comes first.

Reference consumers:

* Buffer to SQLite, flush once per second: [ws-stream-flow-alerts-to-sqlite](https://github.com/unusual-whales/api-examples/tree/main/examples/ws-stream-flow-alerts-to-sqlite)
* Buffer to DuckDB, flush every second or every 500 records, whichever comes first: [ws-stream-spot-greeks-by-strike-by-expiry](https://github.com/unusual-whales/api-examples/blob/main/examples/ws-stream-spot-greeks-by-strike-by-expiry/ws_stream_spot_greeks_by_strike_by_expiry.py)

## Recovery

The stream has no replay, resume, or sequence numbers. Messages missed during a disconnect are not redelivered on reconnect. For delivery guaranteed across gaps, use Kafka which has a retention period of 72h. The `gex_strike` data has no intraday REST backfill, so capture it live.

## Historic data

To download/access historic data, use the endpoint [/api/option-trades/full-tape](https://api.unusualwhales.com/docs/operations/PublicApi.OptionTradeController.full_tape)

## The `price` channel

Subscribe to `price` with no ticker to receive live prices for all tickers on one connection. `price:{TICKER}` streams a single ticker. To follow many tickers, subscribe once to `price` rather than opening a `price:{TICKER}` subscription per symbol.

## Periscope values

On the `periscope` channels, the streamed `gamma`, `charm`, and `vanna` are net Market Maker greek exposure, not the dollarized `*_per_one_percent_move_oi` values returned by the REST spot-exposures endpoints. They are on different scales, so do not compare them directly.
