WebSocket streaming

Connection lifecycle and message formats.

Delayed quote streaming

WebSocket URL
wss://api.ohlc.io/v1/stream

Authenticate within 10 seconds. Wait for authenticated, then subscribe. Send ping within every 120-second session lease. Quotes are snapshots: exchange listings are delayed at least 15 minutes, and crypto and currency pairs are undelayed snapshots up to about 10 minutes old. This stream is not real-time.

Client messages
{"type":"authenticate","key":"YOUR_API_KEY"}
{"type":"subscribe","symbols":["XNAS:AAPL"]}
{"type":"ping"}
{"type":"unsubscribe","symbols":["XNAS:AAPL"]}

Server messages

Authentication returns authenticated. Subscribe, unsubscribe and ping return ack. Each includes timezone: UTC. Quote frames have type: quotes, timezone, data and meta using the REST quote schema. There is no channel or sequence field.

Synthetic quote frame
{
  "type": "quotes",
  "timezone": "UTC",
  "data": [
    {
      "security_id": "01JEXAMPLESECURITY0000000000",
      "instrument_id": "01JEXAMPLESECURITY0000000000",
      "symbol": "XNAS:AAPL",
      "exchange_mic": "XNAS",
      "currency_code": "USD",
      "last_price": "227.63",
      "bid_price": "227.62",
      "ask_price": "227.64",
      "bid_size": "100",
      "ask_size": "100",
      "last_at": null,
      "bid_at": null,
      "ask_at": null
    }
  ],
  "meta": {
    "timezone": "UTC",
    "as_of": "2026-09-18T20:01:00Z",
    "next_cursor": null
  }
}

A quote frame is sent when a new snapshot changes a subscribed quote, so frames reflect snapshots, never live trading. Subscription changes accept at most 100 symbols per message. The plan symbol limit counts the union of symbols across all of the account's connections and API keys: 250 symbols on Pro, 1,000 on Commercial and unlimited on Scale. Each account may hold up to 5 simultaneous stream connections, and authenticating, subscription changes and pings count against its request rate. Entitlements, licensing and network policy are rechecked during delivery.

Disconnects

A refused message, subscription or session produces an error frame, {"type":"error","code":1008,"detail":"...","timezone":"UTC"}, whose code is the WebSocket close code that follows and whose detail says why; it carries no problem code or HTTP status. A missed 10-second authentication deadline closes with 1008, and a client whose send buffer fills because it reads too slowly gets 1013. A connection refused at capacity or before the handshake closes without a frame. Any refused subscribe closes the whole connection. Reconnect with backoff, authenticate and resubscribe. No replay or exactly-once delivery is provided.