Skip to main content
The HTTP endpoints return historical and current state. For a live feed — used by the dashboard, paper trader, and arb tracker — connect to the WebSocket at:
wss://api.polyquantlab.com/v1/stream
One connection per client is plenty. The server multiplexes every subscribed market across the single socket.

Authentication

Pass your API key as the token query parameter on the WebSocket URL. (Browsers don’t allow Authorization headers on WebSocket() calls, so we accept the token in the URL — same secret, different transport.)
wss://api.polyquantlab.com/v1/stream?token=pql_live_…

Subscribe

Once the socket opens, send a subscribe frame:
{
  "type": "subscribe",
  "tickers": ["BTC", "ETH", "SOL"],
  "event_types": ["5m", "15m"]
}
You’ll receive an ack:
{"type": "ack", "subscribed": {"tickers": ["BTC","ETH","SOL"], "event_types": ["5m","15m"]}}
Then snapshot events start flowing whenever the collector receives an update for any market matching the filter.

Snapshot frame

{
  "type": "snapshot",
  "market_id": "0x198001cb01bbcd…",
  "ts": "2026-06-05T02:14:31.892",
  "yes_bids": [{"price": 0.41, "size": 1200}, ...],
  "yes_asks": [{"price": 0.45, "size":  800}, ...],
  "no_bids":  [{"price": 0.54, "size":  900}, ...],
  "no_asks":  [{"price": 0.58, "size": 1100}, ...],
  "underlying_ticker": "BTC",
  "underlying_price": 75123.45
}
Same shape as /v1/snapshots, just delivered via push instead of pull.

Keep-alive

The server sends a {"type": "ping"} every 25 s. If you don’t reply with {"type": "pong"} within 30 s, the connection closes. Your WebSocket library probably does this for you (ws on Node, websockets on Python both handle it transparently).

Reconnect

If you drop, simply reconnect and re-send your subscribe frame. There’s no replay window — snapshots missed during the gap are gone, so backfill via GET /v1/snapshots if you need them.

Example — Python

import asyncio, json, os
import websockets

URI = f"wss://api.polyquantlab.com/v1/stream?token={os.environ['POLYQUANTLAB_API_KEY']}"

async def main():
    async with websockets.connect(URI, ping_interval=25, ping_timeout=30) as ws:
        await ws.send(json.dumps({
            "type": "subscribe",
            "tickers": ["BTC"],
            "event_types": ["5m"],
        }))
        async for raw in ws:
            msg = json.loads(raw)
            if msg["type"] == "snapshot":
                print(msg["market_id"][:12], msg["ts"], msg.get("underlying_price"))

asyncio.run(main())

Example — Node

import WebSocket from "ws";

const ws = new WebSocket(
  `wss://api.polyquantlab.com/v1/stream?token=${process.env.POLYQUANTLAB_API_KEY}`
);

ws.on("open", () => {
  ws.send(JSON.stringify({
    type: "subscribe",
    tickers: ["BTC"],
    event_types: ["5m"],
  }));
});

ws.on("message", (raw) => {
  const msg = JSON.parse(raw);
  if (msg.type === "snapshot") {
    console.log(msg.market_id.slice(0, 12), msg.ts, msg.underlying_price);
  }
});

Rate limit

WebSocket connections count as 1 connection toward your tier’s cap (no per-message rps cost). Free tier allows 1 concurrent connection, Pro allows 4, Plus allows 16. If you need a guaranteed-delivery feed beyond Plus, contact us — we can set up a dedicated NATS / Redis Streams bridge for Enterprise customers.