Sequence/docs

Real-Time Streams

Sequence streams every kind of real-time event through a single multiplexed WebSocket: /v1/stream. You subscribe to topics, you get JSON envelopes, you cancel by topic, you keep one connection open.

For consumers who only want one specific feed (TCA reports, alert triggers, prediction-market lifecycle), there are dedicated endpoints listed near the bottom of this page.

Tip

If you're integrating for the first time, start with /v1/stream and subscribe to the topics you need. One connection serves prices, books, orders, fills, TCA, fair price, traces, and funding rates.


Authentication

All streams require Authorization: Bearer seq_live_....

For browser clients that can't set headers on a WebSocket connect, exchange your bearer token for a short-lived ticket first:

code
GET /v1/ws/ticket
→ {"ticket": "wst_abcd1234..."}

# Then connect:
wss://api.sequencemkts.com/v1/stream?ticket=wst_abcd1234...

Tickets expire after 30 seconds and are consumed on first use.

Warning

Query-parameter auth (?api_key=...) was removed for security. Use the Authorization: Bearer header for non-browser clients, or ?ticket= for browsers.


Unified Stream

GET/v1/stream

A single WebSocket. Subscribe to topics. Receive JSON envelopes shaped:

json
{"channel": "<topic>", "data": { ... }}

Subscribe / unsubscribe

json
// Subscribe to one or more topics
{"subscribe": ["prices:BTC-USD", "book:BTC-USDT", "orders", "fair_price:BTC"]}
 
// Unsubscribe
{"unsubscribe": ["prices:BTC-USD"]}

The server responds with an ack listing accepted topics and any rejections:

json
{"subscribed": ["prices:BTC-USD", "book:BTC-USDT", "orders", "fair_price:BTC"], "rejected": []}
Warning

Subscription is a WS message, not a URL parameter. A URL like wss://api.sequencemkts.com/v1/stream?symbols=BTC-USD&book=1&prices=1 will connect successfully but stream zero events — the server ignores query parameters on /v1/stream and waits for a JSON {"subscribe": [...]} message after the WS upgrade. If you see the connection succeed but get nothing back, this is the first thing to check.

Note

A successful subscribe always returns {"subscribed": [...], "rejected": [...]} as the first message after you send the subscribe payload. If you don't see that envelope, your subscribe message wasn't parsed — verify it's valid JSON sent over the WS data channel.

Topic catalog

TopicSourcePayload
prices:<symbol>NBBO updates (best bid/ask across all venues)One mid + best per side, per update
book:<symbol>TopBook L2 updates per venueUp to 10 levels per side, per venue, per update
ordersOrder lifecycle (snapshots when state changes)Full order shape: id, status, qty, fills, etc.
fillsPer-fill events from every venueqty, price, fee, venue, timestamps
tcaPost-completion TCA report per orderSlippage, IS, savings, achieved vs benchmark
traces:<deployment_id>Per-callback traces from a deployed native strategyFunction/payload/timing, scoped to one deployment
funding / funding:<venue> / funding:<venue>:<symbol>Perp funding rate updatesRate bps/hr, predicted, mark, OI, next-settlement
fair_price / fair_price:<underlying>Cross-venue Chainlink-style consolidated reference pricecomposite mid, spot/perp legs, basis_bps, contributors

prices:, book:, funding:, fair_price:, traces: accept a suffix to filter; subscribing to funding (no suffix) means "all venues, all symbols", subscribing to fair_price means "all underlyings".

Example: prices + book + fair_price

python
import asyncio, json, websockets
 
async def main():
    headers = {"Authorization": f"Bearer {API_KEY}"}
    async with websockets.connect(
        "wss://api.sequencemkts.com/v1/stream",
        additional_headers=headers,
    ) as ws:
        await ws.send(json.dumps({
            "subscribe": ["prices:BTC-USD", "book:BTC-USDT", "fair_price:BTC"]
        }))
        async for msg in ws:
            evt = json.loads(msg)
            print(evt["channel"], evt["data"])
 
asyncio.run(main())

Topic payload shapes

prices:<symbol> — NBBO updates:

json
{
  "channel": "prices:BTC-USD",
  "data": {
    "symbol": "BTC-USD",
    "instrument_type": "spot",
    "best_bid_px_1e9": 76410000000000,
    "best_bid_sz_1e8": 12000000,
    "best_bid_venue": "coinbase",
    "best_ask_px_1e9": 76411000000000,
    "best_ask_sz_1e8": 8000000,
    "best_ask_venue": "kraken",
    "spread_bps": 1,
    "ts_ns": 1745979000123456789
  }
}

book:<symbol> — per-venue L2 updates (top 10 levels):

json
{
  "channel": "book:BTC-USDT",
  "data": {
    "symbol": "BTC-USDT",
    "venue": "binance",
    "instrument_type": "spot",
    "bids": [[76410.50, 0.421], [76410.40, 1.2], ...],
    "asks": [[76411.00, 0.155], [76411.10, 0.8], ...],
    "ts_ns": 1745979000123456789,
    "is_snapshot": false,
    "checksum": 1448524378
  }
}

Each tick is one venue's L2 update. The same symbol can stream from multiple venues, multiplexed on the same book:<symbol> topic — differentiate by the venue and instrument_type fields.

FieldSemantics
is_snapshottrue only on the initial book frame after subscribe / reconnect (a fresh full state). false for every subsequent delta. Clients tracking their own L2 state should reset on true and apply incrementally on false.
checksumOptional 32-bit integrity fingerprint, populated for venues that publish one (Polymarket today; truncated SHA-1 of the venue's book hash). Use as an opaque equality check for divergence detection across consecutive ticks of the same state. null for venues that don't report.

fair_price:<underlying> — Chainlink-style consolidated reference (see Market Data → Fair Price for the full payload shape).

json
{
  "channel": "fair_price:BTC",
  "data": {
    "underlying": "BTC",
    "fair_mid_1e9": 76405095000000,
    "spot_mid_1e9": 76407250000000,
    "perp_mid_1e9": 76357950000000,
    "basis_bps": -6,
    "confidence": 0.665,
    "contributors": [
      {"venue": "binance", "instrument_type": "spot", "mid_1e9": 76407250000000, "weight": 0.84, "staleness_ms": 96},
      {"venue": "binance", "instrument_type": "perp", "mid_1e9": 76357950000000, "weight": 0.81, "staleness_ms": 79},
      {"venue": "okx", "instrument_type": "spot", "mid_1e9": 76406500000000, "weight": 0.78, "staleness_ms": 156},
      {"venue": "hyperliquid", "instrument_type": "perp", "mid_1e9": 76354500000000, "weight": 0.65, "staleness_ms": 226}
    ],
    "cc_ts_ns": 1745979000123456789
  }
}

orders — order snapshots:

json
{
  "channel": "orders",
  "data": {
    "node_order_id": "graph:graph_a1b2c3d4:btc_leg:1",
    "client_id": "muhammad",
    "client_order_id": "order-001",
    "symbol": "BTC-USD",
    "side": "buy",
    "qty_1e8": 1000000,
    "filled_qty_1e8": 1000000,
    "status": "COMPLETED",
    "created_unix_ns": 1745979000000000000,
    "updated_unix_ns": 1745979001200000000
  }
}

fills — per-fill events from every venue:

json
{
  "channel": "fills",
  "data": {
    "node_order_id": "graph:graph_a1b2c3d4:btc_leg:1",
    "venue_execution_id": "kraken-8f3a2b1c",
    "symbol": "BTC-USD",
    "side": "buy",
    "qty_1e8": 700000,
    "price_1e9": 76410000000000,
    "fee_1e9": 100000000,
    "edge_id": "venue-edge-kraken",
    "ts_unix_ns": 1745979000498000000
  }
}

venue_execution_id is the venue-assigned execution/trade id — the idempotency key for fill dedup.

tca — post-completion TCA report (also exposed as a dedicated SSE at /v1/tca/stream):

json
{
  "channel": "tca",
  "data": {
    "node_order_id": "graph:graph_…:kalshi_yes:1",
    "client_id": "muhammad",
    "symbol": "BTC-USD",
    "side": "BUY",
    "achieved_vwap_1e9": 76411000000000,
    "expected_fill_1e9": 76410500000000,
    "total_fees_1e9": 7641000,
    "fee_cost_bps": 1,
    "expected_fee_bps": 2,
    "fee_prediction_error_bps": -1,
    "spread_cost_bps": 0,
    "market_impact_bps": -1,
    "implementation_shortfall_bps": 0,
    "savings_vs_benchmark_bps": 1,
    "is_prediction": false,
    "execution_time_ms": 124,
    "num_fills": 1
  }
}

Prediction-market fills carry four extra fields:

FieldMeaning
is_predictiontrue for any prediction-venue fill, false (or omitted) otherwise
achieved_implied_prob_bpsAchieved fill price translated to implied probability (e.g. 300 = 3.00%)
arrival_implied_prob_bpsArrival mid translated the same way
probability_slippage_bpsarrival_implied_prob_bps - achieved_implied_prob_bps (sign-flipped for sells)

funding / funding:<venue> / funding:<venue>:<symbol> — perp funding rate updates:

json
{
  "channel": "funding:binance",
  "data": {
    "venue": "binance",
    "symbol": "BTC-USDT",
    "rate_bps_per_hour": 1,
    "predicted_rate_bps_per_hour": 1,
    "mark_price_1e9": 76410000000000,
    "open_interest_1e8": 12000000000,
    "next_settlement_ns": 1745982600000000000,
    "ts_ns": 1745979000000000000
  }
}

traces:<deployment_id> — per-callback traces from a deployed native strategy, scoped to one deployment.

Prediction-market live book + prices

Polymarket and Kalshi flow through the same prices: / book: channels as CEX symbols. The address forms accepted on the channel suffix:

FormExampleNotes
Venue-prefixed token idpolymarket:71166707665253014908308475311609108419118036985903834861277070930664191157865Recommended. Unambiguous and works for any 77-digit CTF token id.
Bare token id (no prefix)71166707665253014908308475311609108419118036985903834861277070930664191157865Accepted; slug-resolver strips the prefix internally and looks up the same canonical symbol.
Slug + outcomepolymarket:btc-updown-5m-1778715600:yesResolved server-side via Gamma (cached 10 min). Subject to the resolver lag described below.
Kalshi tickerKXBTCZ-26DEC31-T99000:YESDirect, no slug translation.
python
import asyncio, json, websockets
 
YES = "71166707665253014908308475311609108419118036985903834861277070930664191157865"
NO  = "12689298635162541371837661686258341808898518310308696393181273329357280031984"
 
async def main():
    async with websockets.connect(
        "wss://api.sequencemkts.com/v1/stream",
        additional_headers={"Authorization": f"Bearer {API_KEY}"},
    ) as ws:
        await ws.send(json.dumps({"subscribe": [
            f"prices:polymarket:{YES}", f"book:polymarket:{YES}",
            f"prices:polymarket:{NO}",  f"book:polymarket:{NO}",
        ]}))
        ack = json.loads(await ws.recv())  # {"subscribed": [...], "rejected": [...]}
        async for raw in ws:
            evt = json.loads(raw)
            print(evt["channel"], evt["data"])
 
asyncio.run(main())

Cold-start latency: Subscribing to a freshly-minted prediction market — one created seconds before you subscribed — may take up to ~30 seconds before the first event arrives. The typical case is sub-second; tokens already trading on the venue start streaming immediately on subscribe.

Connecting events to underlying questions: the data.symbol field on every event is the canonical token id (77-digit string for Polymarket). To resolve back to a human-readable question or slug, hit GET /v1/markets?venue=polymarket&slug=<token_id> or use the new-market lifecycle stream described later in this page.

Lagged-client semantics

Each client gets a 4096-entry per-topic buffer. A slow consumer that backs up will receive a Gap event indicating how many messages were dropped, then resume from current. Don't write retry-on-gap loops — bring your own ordering or watermark and re-snapshot via REST if you fell behind.


Dedicated SSE Endpoints

These are kept for one-off integrations that don't want a WS connection. Every event published on these is also available as a topic on /v1/stream — prefer the unified WS unless you have a specific reason to use the SSE.

TCA Reports

GET/v1/tca/stream

Same payload as the tca topic on /v1/stream. SSE event name: tca_report.

Alert Triggers

GET/v1/alerts/stream

User-defined rule triggers. SSE event name: alert.


Prediction-Market Lifecycle WebSocket

A separate WebSocket that emits prediction-market lifecycle events as they happen on Polymarket and Kalshi. No subscribe message — connecting is the subscription. Each connection first replays the last 128 events, then streams live.

Events are deduped across multi-region edges by (venue, event_id). The server sends a WS ping every 30 s so idle proxies don't close the connection.

Auth: Authorization: Bearer seq_live_... on the WS upgrade, or ?ticket=... for browsers.

New Markets

GET/v1/ws/new_markets

Every freshly-minted prediction market. The wire payload IS the same Market schema as /v1/markets returns — same field names, same nullability rules — plus kind: "new_market" and observed_at_ns for stream framing. Existing code that handles seq.markets() rows can process new-market events with no field-mapping layer.

For Polymarket, frames are enriched asynchronously via the CLOB endpoint before broadcast so slug, start_date, end_date, neg_risk, etc. arrive populated. BBO and volume fields are null/0 on freshly-minted rows (no orders or trades yet).

json
{
  "kind": "new_market",
  "venue": "polymarket",
  "slug": "will-btc-close-above-100k-on-2026-04-30",
  "symbol": "73428831...",
  "question": "Will BTC close above $100k on April 30, 2026?",
  "outcomes": ["Yes", "No"],
  "outcome_token_ids": ["73428831...", "89131027..."],
  "yes_token_id": "73428831...",
  "no_token_id": "89131027...",
  "event_id": "0xabc123...",
  "neg_risk": false,
  "volume_24h": 0.0,
  "volume_total": 0.0,
  "start_date": "2026-04-30T00:00:00Z",
  "end_date": "2026-05-01T00:00:00Z",
  "url": "https://polymarket.com/event/will-btc-close-above-100k-on-2026-04-30",
  "observed_at_ns": 1745971205123456789
}

Resolved Markets

GET/v1/ws/market_resolved
json
{
  "kind": "market_resolved",
  "venue": "polymarket",
  "event_id": "0xabc123...",
  "winning_outcome": "Yes",
  "winning_token_id": "73428831...",
  "losing_token_id": "89131027...",
  "observed_at_ns": 1745971205123456789
}

Minimal Consumer Example

python
import asyncio, json, websockets
 
async def main():
    url = "wss://api.sequencemkts.com/v1/ws/new_markets"
    async with websockets.connect(
        url, additional_headers={"Authorization": f"Bearer {API_KEY}"}
    ) as ws:
        async for raw in ws:
            evt = json.loads(raw)
            print(evt["venue"], evt["slug"], evt["question"])
 
asyncio.run(main())

SDK wrappers: seq.stream_new_markets() (Python) · stream_new_markets() (Rust).


End-to-End Order Lifecycle Example

Submit an order, then watch its full lifecycle on one WebSocket connection:

python
import asyncio, json, websockets, requests
 
API_BASE = "https://api.sequencemkts.com"
API_KEY = "seq_live_..."
 
# 1. Submit
order = requests.post(
    f"{API_BASE}/v1/orders",
    headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
    json={"client_order_id": "demo-001", "side": "buy", "symbol": "BTC-USD", "qty_1e8": 1_000_000},
).json()
node_order_id = order["node_order_id"]
 
# 2. Watch the lifecycle on one connection
async def watch():
    async with websockets.connect(
        f"{API_BASE.replace('https', 'wss')}/v1/stream",
        additional_headers={"Authorization": f"Bearer {API_KEY}"},
    ) as ws:
        await ws.send(json.dumps({"subscribe": ["orders", "fills", "tca"]}))
        async for raw in ws:
            evt = json.loads(raw)
            ch, data = evt["channel"], evt["data"]
            if data.get("node_order_id") != node_order_id:
                continue
            print(ch, data.get("status") or data)
            if ch == "tca":  # final report — we're done
                return
 
asyncio.run(watch())