WS Events
Every frame the maker stream can deliver
Connect to wss://<host>/maker/stream with X-API-Key on the upgrade
request (for example, the Node ws package's headers option). Browser-native
WebSocket cannot set that header and cannot authenticate this maker stream.
Every frame is a JSON object:
{ "type": "rfq.created", "payload": { … } }On connect the server replays a snapshot of your current state and then streams live events; reconnecting is how you resync. The exact snapshot contents and the reconnect discipline are in Subscribe to RFQs.
Event catalog
type | payload | When |
|---|---|---|
rfq.created | RfqDto | You are invited to a new RFQ (and once per open RFQ in the snapshot) |
rfq.closed | {rfqId} | The RFQ ended — cancelled by the taker, or filled. Alone it does not say which; with a live quote on it you also get quote.status: lost on a fill by another maker, cancelled on a cancel |
rfq.expired | {rfqId} | The deadline passed with no trade |
quote.created | QuoteDto | Your quote was recorded (live, and in the snapshot); as taker, a quote on your RFQ went live — its allocations landed |
quote.status | {quoteId, rfqId, status} | won / lost when a trade settles; revoked on re-quote, DELETE, a failed settlement or unsigned actions that expired; cancelled when the taker cancels; expired |
quote.anchored | {quoteId, rfqId, anchorCids} | Your quote's allocations landed — it is live and visible to the taker |
trade.step | {tradeId, rfqId, step, refs} | Settlement phase completed; refs = contract ids the phase created. allocated = every allocation of the trade is committed; the atomic batch follows |
trade.settled | TradeDto | The atomic settle executed; ledger.updateId + receiptCids are the proof |
trade.failed | {tradeId, rfqId, reason} | Settlement failed (the taker could not fund its leg, the settlement window expired, or the maker's allocation is gone) — nothing moved; the quote is revoked and the RFQ stays open until its deadline |
sign.requested | SignActionDto | An action now waits on your signature — one a call of yours returned, or one the desk queued for a trade you accepted; the push form of GET /tx/pending (sign queue) |
sign.completed | {actionId} | The action left the queue — executed, expired or cancelled |
history.recorded | RfqHistoryDto | As taker: one of your RFQs closed without a trade (expired, cancelled, or its settlement failed) |
resync | {} | Server state was reset — reconnect and consume the fresh snapshot |
Forward compatibility: ignore unknown types
Events are routed by party, not by socket kind: if the same party is also open in a browser somewhere, both sockets see the same frames — and new event types may be added at any time. A robust bot validates each frame and silently skips types it does not know:
const frame = safeJson(data); // your own parse, e.g. a zod schema of the events you handle
if (frame === undefined || !HANDLED.has(frame.type)) return; // never crash, never log-spamErrors
The only auth failure is close code 4401: a missing or unknown X-API-Key
at connect, or — mid-stream — the key the socket opened with was rotated. The
server pings every 30 seconds and drops a socket that missed the previous pong.
Anything else is operational — reconnect with backoff.