Streaming
tastytrade exposes two independent WebSocket streamers. They serve different purposes, use different tokens, and connect to different hosts:
- The DXLink market-data streamer pushes live quotes, trades, Greeks, and candles from tastytrade's quote provider (dxFeed).
- The account streamer pushes one-directional notifications about your account state (orders, balances, positions) plus non-account data: public watchlists and user-level quote alerts.
Both let you subscribe to real-time updates instead of polling REST endpoints. Streaming is for staying in sync; the REST API in /reference remains the source of truth and the only way to take action (place orders, etc.).
DXLink market-data streamer
1. Get an API quote token
Request a token with GET /api-quote-tokens. The token is tied to the customer identified by your OAuth access token, and the response includes the dxlink-url to connect to:
{
"data": {
"token": "<redacted>",
"dxlink-url": "wss://tasty-openapi-ws.dxfeed.com/realtime",
"level": "api"
},
"context": "/api-quote-tokens"
}
API quote tokens expire after 24 hours — refresh before they lapse. You must be a fully onboarded tastytrade customer; a username/password-only registration is rejected with quote_streamer.customer_not_found_error.
2. Connect and exchange messages
Open a WebSocket to the returned dxlink-url. Message order matters; the high-level handshake is:
SETUP— initiate the connection (negotiate version and keepalive timeout).AUTH— after the server sendsAUTH_STATEwithstate: UNAUTHORIZED, authorize with your API quote token.CHANNEL_REQUEST— open a channel (a virtual sub-connection; use separate channels to organize subscriptions, e.g. equities vs. futures).FEED_SETUP— configure which event fields to receive on the channel.FEED_SUBSCRIPTION— subscribe to (orremove) events for one or more symbols.KEEPALIVE— send periodically to hold the connection open.
A SETUP plus AUTH exchange looks like this:
{ "type": "SETUP", "channel": 0, "version": "0.1-DXF-JS/0.3.0", "keepaliveTimeout": 60, "acceptKeepaliveTimeout": 60 }
{ "type": "AUTH", "channel": 0, "token": "<redacted>" }
A channel configured for COMPACT data (requested via FEED_SETUP's acceptDataFormat) delivers events as positional arrays rather than verbose objects:
{ "type": "FEED_SUBSCRIPTION", "channel": 3, "reset": true, "add": [ { "type": "Quote", "symbol": "SPY" }, { "type": "Trade", "symbol": "SPY" } ] }
{ "type": "FEED_DATA", "channel": 3, "data": [ "Trade", [ "Trade", "SPY", 559.36, 13743299, 100.0 ] ] }
Common event types include Quote, Trade, Greeks, Summary, Profile, and Candle. Candle events return historical aggregates (open/high/low/close) — you supply a period and type in the symbol (for example AAPL{=5m}) plus a fromTime Unix-epoch timestamp.
Keepalive and quiet feeds
If DXLink does not receive a keepalive within its 60-second timeout, it closes the connection. Sending KEEPALIVE every ~30 seconds keeps it open indefinitely:
{ "type": "KEEPALIVE", "channel": 0 }
DXLink only publishes events as they occur. A connected, heartbeating socket that receives nothing usually means the symbol simply has no trading activity — that is normal, not a bug.
Symbology
You must subscribe using DXLink-formatted symbols. tastytrade provides these on instrument responses in the streamer-symbol field — for example a futures contract /6AM3 exposes streamer-symbol: "/6AM23:XCME". The same field is available across the instruments endpoints (GET /instruments/equities/{symbol}, GET /instruments/futures, GET /instruments/cryptocurrencies, GET /option-chains/{symbol}, GET /futures-option-chains/{symbol}). Prefer it over hand-building symbols. For more on tastytrade symbology (/ futures, ./ future options, OCC options, crypto pairs), see /reference.
Account streamer
The account streamer is a one-directional WebSocket that publishes notifications when your account data changes. Instead of re-fetching an order to learn it went from Routed to Filled, you receive a push message as the status changes.
Hosts
| Environment | WebSocket host |
|---|---|
| Sandbox | wss://streamer.cert.tastyworks.com |
| Production | wss://streamer.tastyworks.com |
These pair with the REST hosts https://api.cert.tastyworks.com (sandbox) and https://api.tastyworks.com (production).
Authentication
Every message includes an auth-token — your tastytrade OAuth access token, the same value you send in the Authorization header for REST calls. Access tokens last 15 minutes (mint a fresh one with POST /oauth/token — see Get started for the auth flow), so refresh and re-authenticate over the long-lived socket as needed.
Connect, then heartbeat
Perform these steps in order — if you heartbeat before connecting you may get a not implemented error:
- Open the WebSocket connection.
- Send a
connectmessage to subscribe to account updates. - Send
heartbeatmessages on a 2s–1m interval.
{ "action": "connect", "value": [ "5WT00000", "5WT00001" ], "auth-token": "<access token>", "request-id": 2 }
{ "action": "heartbeat", "auth-token": "<access token>", "request-id": 1 }
The optional request-id is echoed back in the server's response so you can correlate messages. Other actions include public-watchlists-subscribe and quote-alerts-subscribe (note: quote alerts are scoped to the user, not an account).
Receiving notifications
Notifications use the same JSON object representations as the REST API and always contain the full object — never a partial or differential update. Each message carries a type and a data payload:
{
"type": "Order",
"data": {
"id": 1,
"account-number": "5WT00000",
"status": "Live",
"underlying-symbol": "AAPL",
"ext-client-order-id": "67890"
},
"timestamp": 1688595114405
}
Note the dasherized JSON keys (account-number, ext-client-order-id), consistent with the rest of the API.
Streaming and orders
The account streamer reports order state — it does not place orders. Submit orders over REST, dry-run first (validate against POST /accounts/{account_number}/orders/dry-run), then send the live order with your own unique external-identifier so you can recognize an order you already submitted — the server does not deduplicate retries, and there is no idempotency-key header. On an uncertain outcome (timeout, 5xx), check GET /accounts/{account_number}/orders (or /orders/live) for that identifier before resubmitting. See Idempotency & retries. You then watch the streamer for Order notifications as the status advances.
Operational notes
- Always send the
User-Agent: product/versionheader on the REST calls that mint your tokens. - Reconnect with backoff on drops; respect the 60-second DXLink keepalive timeout and the account-streamer heartbeat window. See Rate limits & backoff.
- Token errors (
401/403) and other HTTP error codes (400/404/422/429/5xx) on the token endpoints are documented in /reference/errors. - For an end-to-end client that wraps both streamers, see MCP Server.
Machine-readable spec
Both streamers are described in an AsyncAPI 2.6 document — download it as JSON or YAML.