Cessio Docs
Guides

Subscribe to RFQs

The WebSocket stream, snapshot semantics, and the REST fallback

The stream

import WebSocket from "ws";

const ws = new WebSocket("wss://<host>/maker/stream", {
  headers: { "X-API-Key": process.env.API_KEY },
});

The key rides the X-API-Key upgrade header. Browser-native WebSocket cannot set upgrade headers and therefore cannot authenticate this maker stream; use a Node client such as ws. A missing or unknown key closes the socket with code 4401 before you receive anything; so does rotating the key the socket opened with.

Every frame is JSON {type, payload} — the full catalog is on WS Events.

Snapshot: reconnect IS resync

On connect the server immediately replays the current state:

  1. rfq.created for every open RFQ you are invited to;
  2. quote.created + quote.status for your live quote on each.

Then live events follow. This means you never need a separate bootstrap call and never need to persist state across reconnects — drop your local state on disconnect and rebuild it from the snapshot:

ws.on("close", () => {
  tracked.clear();               // stale by definition
  setTimeout(connect, 1000);     // snapshot rebuilds everything
});

If the server itself loses state it sends resync {} — treat it exactly like a disconnect: close, reconnect, consume the fresh snapshot.

REST fallback for simple bots

The socket is not just a feed — it is also presence: the desk only offers a taker your hint while your /maker/stream socket is open, so a bot with no open socket is never invited and /rfq/incoming stays empty forever, no error, nothing to catch. Keep the socket connected even if you drive everything off REST; then, if reacting to events is inconvenient, poll instead of parsing frames:

curl -H "X-API-Key: $API_KEY" $API_URL/rfq/incoming

It returns every open RFQ you are invited to — plus those that closed in the last 10 minutes (open: false), whose myQuote shows your quote's outcome (won, lost, …). Quote the entries with open: true whose myQuote is null or no longer pending (it expired or was revoked). The honest trade-offs: polling latency eats into the RFQ deadline, and settlement progress (trade.step) is stream-only — settled trades land in GET /maker/trades. The WebSocket is the canonical path.

On this page