DocsMessage types

Message types

Every message is a single JSON object with a type string. Every quote and trade frame carries its event time in ts (unix ms) on every channel; numeric field encoding still differs by asset family.

system

Control frames sent by the server in response to connection events and client actions.

  • event: "ready" — sent immediately after a successful upgrade. Includes ts (unix ms). Wait for this before sending subscribe.
  • event: "subscribed" — echoes normalized channels and symbols.
  • event: "unsubscribed" — echoes the removed channels and symbols.
  • event: "pong" — reply to a client JSON { "action": "ping" }, includes server ts.
  • event: "disconnect" — server is closing the socket (for example code: "HEARTBEAT_TIMEOUT" after missed native WebSocket pongs, or code: "SERVER_RESTART" right before a release closes the stream with code 1012).
ready frame
{
  "type": "system",
  "event": "ready",
  "ts": 1743512400000
}

quote

Emitted on *.quotes channels. Every frame carries ts (event time, unix ms) and asset. Numeric field encoding depends on the asset family:

  • Crypto, forex, stocks — numeric fields as strings (for example "bid": "189.12").
  • Indices, ETFs, commodities — numeric fields as numbers on most frames; some tick-driven ETF and index frames arrive through a faster internal path that encodes the same fields as strings. Decode these channels tolerantly (accept both; a single frame never mixes the two). These channels also carry timestamp, a mirror of ts kept for clients built against their original shape. Read ts in new code.

Size fields (bid_size, ask_size, trade size) are number | null (string-encoded on the string channels): null appears when the consolidated feed has no size at that moment.

Frames replayed from cache right after subscribe are marked "snapshot": true. You will see them on the stocks, ETFs, indices and commodities channels; crypto and forex streams are continuously live, so replayed frames rarely, if ever, occur there. See Subscriptions for the snapshot behavior, the "snapshot": false opt-out and the "snapshot": "always" opt-in that keeps a cached value while a market is closed.

crypto.quotes
{
  "type": "quote",
  "channel": "crypto.quotes",
  "asset": "crypto",
  "symbol": "BTCUSD",
  "bid": "84210.12",
  "ask": "84210.45",
  "bid_size": "1.2",
  "ask_size": "0.8",
  "ts": 1743512400000
}
stocks.quotes
{
  "type": "quote",
  "channel": "stocks.quotes",
  "asset": "stocks",
  "symbol": "US:AAPL",
  "bid": "189.12",
  "ask": "189.18",
  "bid_size": "100",
  "ask_size": "200",
  "ts": 1743512400000
}
indices.quotes
{
  "type": "quote",
  "channel": "indices.quotes",
  "asset": "indices",
  "symbol": "US500",
  "bid": 4788.12,
  "ask": 4788.12,
  "bid_size": 62,
  "ask_size": 58,
  "ts": 1743512400000,
  "timestamp": 1743512400000
}
commodities.quotes
{
  "type": "quote",
  "channel": "commodities.quotes",
  "asset": "commodities",
  "symbol": "XAUUSD",
  "bid": 2318.1,
  "ask": 2318.74,
  "bid_size": 58,
  "ask_size": 48,
  "ts": 1743512400000,
  "timestamp": 1743512400000
}

Entitlements may omit a channel until coverage is enabled for the account.

trade

Emitted on *.trades channels. Same rules as quotes: ts and asset on every frame, string numerics on crypto/forex/stocks, and the legacy timestamp mirror plus mostly-number numerics (decode tolerantly) on indices/ETFs/commodities:

crypto.trades
{
  "type": "trade",
  "channel": "crypto.trades",
  "asset": "crypto",
  "symbol": "BTCUSD",
  "price": "84215.42",
  "size": "0.53",
  "ts": 1743512400000
}
etfs.trades
{
  "type": "trade",
  "channel": "etfs.trades",
  "asset": "etfs",
  "symbol": "US500ETF",
  "price": 718.66,
  "size": 90,
  "ts": 1743512400000,
  "timestamp": 1743512400000
}

size may be omitted or null when the tape has no lot size.

rate

Emitted on bonds.quotes: the latest published government bond yield for a subscribed CC:TENOR symbol. Bond yields are daily official curve observations, not ticks, so this channel delivers the current observation as a snapshot frame right after you subscribe and then one frame per symbol whenever a new observation is published, in practice once per business day. A quiet hour on this channel is normal. Numeric fields are numbers, and the fields match GET /bond/snapshot.

bonds.quotes
{
  "type": "rate",
  "channel": "bonds.quotes",
  "asset": "bonds",
  "symbol": "US:10Y",
  "rate": 4.79,
  "unit": "percent",
  "date": "2026-09-02",
  "prev_rate": 4.76,
  "prev_date": "2026-09-01",
  "change": 0.03,
  "change_bps": 3,
  "change_percent": 0.6303,
  "ts": 1788307200000,
  "timestamp": 1788307200000
}
  • ts and timestamp are the observation date (UTC midnight of date), never the send time. Compare date with prev_date for the interval the change covers.
  • change is in percentage points, change_bps in basis points, change_percent relative to prev_rate. The prev_* and change fields are null when only one observation is available.
  • The replayed frame on subscribe carries "snapshot": true; frames for a newly published observation do not.

status

Emitted on stocks.status: trading halt and resume events for US-listed equities. Subscribe with explicit symbols (US:KO) or, with the market wildcard add-on enabled on your account, US:* for every US listing. Events are delivered live from subscribe time forward; this channel never replays a snapshot, because a cached status is a claim about the present that may no longer hold.

stocks.status
{
  "type": "status",
  "channel": "stocks.status",
  "asset": "stocks",
  "symbol": "US:KO",
  "status": "halted",
  "reason": "news_pending",
  "ts": 1743512400000
}
  • status is one of four lifecycle values: halted (trading halted), paused (volatility, limit-up/limit-down pause), quoting (quotations resumed while trading is still halted, the intermediate step before some resumptions), resumed (trading resumed).
  • reason is our aggregation layer's classification of why: volatility, market_wide, news_pending, news_released, information_requested, regulatory, corporate_action, operational or ipo. It is omitted when no classification applies, and new values may be added over time, so decode it tolerantly.

Both fields are derived classifications produced by our aggregation layer, consistent with the data notice that applies to every TickerLayer feed. Only halt-lifecycle events are published: auction imbalances, price indications and short sale restriction notices are not part of this channel. Coverage is US equities; other markets do not emit on this channel yet.

error

Sent when a client action fails validation or a limit is breached after the connection is open. Subscribe failures use event: "subscribe_failed" (or subscribe_partial_failed). There is no details object — rejected symbols appear in rejected when present.

subscribe_failed (symbol cap)
{
  "type": "error",
  "event": "subscribe_failed",
  "code": "SYMBOL_LIMIT_EXCEEDED",
  "message": "rate limit exceeded"
}
subscribe_failed (invalid symbols)
{
  "type": "error",
  "event": "subscribe_failed",
  "code": "INVALID_SYMBOL",
  "message": "invalid symbol",
  "channel": "stocks.quotes",
  "rejected": [
    { "symbol": "NOTREAL", "reason": "unknown" }
  ]
}

For the full list of error codes, see the Errors & troubleshooting page.