Stream market data
This guide walks you through streaming live quotes from tastytrade's quote provider (dxFeed) over the DXLink WebSocket. You mint a short-lived token from the REST API, open the socket, run the handshake, subscribe to symbols, and read the feed.
For background on how the two tastytrade streamers differ and the full event catalog, see the concept page at /docs/concepts/streaming. This guide is the step-by-step task.
1. Get an API quote token
Call GET /api-quote-tokens with your OAuth access token. Access tokens last 15 minutes — mint a fresh one with POST /oauth/token if needed — and remember the required User-Agent: product/version header on every REST call. See /docs/get-started for the auth flow.
curl https://api.tastyworks.com/api-quote-tokens \
-H "Authorization: Bearer <access token>" \
-H "User-Agent: my-app/1.0.0"
The response gives you the token and the dxlink-url to connect to:
{
"data": {
"token": "<redacted>",
"dxlink-url": "wss://dxlink.example.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. (Sandbox uses https://api.cert.tastyworks.com; production uses https://api.tastyworks.com.) In the sandbox, an account with a customer record got "level": "demo" and a dxlink-url ending in /delayed; the quote age was not measured, and a user without a customer record was not tested.
2. Open the DXLink WebSocket
Open a WebSocket connection to the dxlink-url returned above. Message order matters — send the frames below in sequence.
3. SETUP
This is the first frame. It negotiates the protocol version and keepalive timeout on channel 0.
{ "type": "SETUP", "channel": 0, "version": "0.1-DXF-JS/0.3.0", "keepaliveTimeout": 60, "acceptKeepaliveTimeout": 60 }
DXLink replies with its own SETUP, then sends an AUTH_STATE with state: UNAUTHORIZED.
4. AUTH
When you see AUTH_STATE / UNAUTHORIZED, send your API quote token. DXLink replies with AUTH_STATE / AUTHORIZED.
{ "type": "AUTH", "channel": 0, "token": "<redacted>" }
5. CHANNEL_REQUEST — open a channel
A channel is a virtual sub-connection. Use separate channels to organize subscriptions (for example, equities on one channel, futures on another). Pick any number to identify it.
{ "type": "CHANNEL_REQUEST", "channel": 3, "service": "FEED", "parameters": { "contract": "AUTO" } }
DXLink replies with CHANNEL_OPENED for that channel.
6. FEED_SETUP — configure fields
Tell DXLink which fields you want for each event type, and request COMPACT data so events arrive as positional arrays rather than verbose objects.
{
"type": "FEED_SETUP",
"channel": 3,
"acceptAggregationPeriod": 0.1,
"acceptDataFormat": "COMPACT",
"acceptEventFields": {
"Quote": ["eventType", "eventSymbol", "bidPrice", "askPrice", "bidSize", "askSize"],
"Trade": ["eventType", "eventSymbol", "price", "dayVolume", "size"],
"Greeks": ["eventType", "eventSymbol", "volatility", "delta", "gamma", "theta", "rho", "vega"],
"Summary": ["eventType", "eventSymbol", "openInterest", "dayOpenPrice", "dayHighPrice", "dayLowPrice", "prevDayClosePrice"]
}
}
DXLink replies with FEED_CONFIG confirming the format and aggregation period.
7. FEED_SUBSCRIPTION — subscribe to symbols
Subscribe to one or more event types for one or more symbols in a single frame. DXLink keeps streaming these until you unsubscribe. The event types are listed under Available events below.
{
"type": "FEED_SUBSCRIPTION",
"channel": 3,
"reset": true,
"add": [
{ "type": "Quote", "symbol": "SPY" },
{ "type": "Trade", "symbol": "SPY" },
{ "type": "Summary", "symbol": "SPY" }
]
}
Subscribe with DXLink-formatted symbols. tastytrade provides these in the streamer-symbol field on instrument responses (for example, futures /6AM3 exposes streamer-symbol: "/6AM23:XCME"). Prefer that field over hand-building symbols. To stop a symbol, send another FEED_SUBSCRIPTION with a remove array of the same event/symbol pairs.
Available events
These are event types defined by dxFeed's DXLink protocol; use the exact name as the type value. This is not a guarantee that every type is served to you: which types a given feed returns depends on the feed and the token you connect with. The sandbox, for example, returned a delayed demo feed (see step 1).
- Quote
- Trade
- Summary
- Greeks
- TimeAndSale (Time and Sale)
- Profile
- Candle
To try the protocol interactively, dxFeed hosts a third-party dxLink protocol and test page. It is not operated by tastytrade; paste the API quote token from step 1 when it asks for one.
8. Parse FEED_DATA
In COMPACT form, data is a flat array: an event-type label followed by one positional row per event, with values in the order you requested in FEED_SETUP.
{ "type": "FEED_DATA", "channel": 3, "data": [ "Trade", [ "Trade", "SPY", 559.36, 13743299, 100.0 ] ] }
DXLink publishes events only as they occur. A connected, heartbeating socket that receives nothing usually means the symbol has no current trading activity — that is normal, not a bug.
9. Keep the connection alive
If DXLink does not receive a keepalive within its 60-second timeout, it closes the connection. Send a KEEPALIVE on channel 0 about every 30 seconds to hold it open indefinitely.
{ "type": "KEEPALIVE", "channel": 0 }
Next steps
- Reconnect with backoff on drops and respect the 60-second keepalive timeout — see
/docs/guides/rate-limits-and-backoff. - For Candle (historical aggregate) events, symbology details, and the account streamer, see
/docs/concepts/streaming. - Token-endpoint errors (
401/429) are documented in/reference/errors; browse all endpoints in/reference. - For an agent integration that hands off to both streamers (quote-token tool + streaming protocol reference), see
/docs/sdks-and-tools/mcp-server.