Price stream
Live prices and pair books over WebSocket, about once per second, from your backend.
The stream pushes the same pair books as /v2/markets/levels about once per second, so you do not have to poll.
Connect
wss://api.rave-trading.com/api/v2/streamConnect from your backend and send the API key in the Authorization header of the WebSocket handshake. A handshake without a valid key is rejected with HTTP 401 ({ "error": "unauthorized" }) before the upgrade, so an auth message sent after connecting never arrives.
import WebSocket from "ws"; // Backend Node.js only.
const ws = new WebSocket("wss://api.rave-trading.com/api/v2/stream", {
headers: { Authorization: `Bearer ${credential}` }, // credential from your secret manager
});
ws.on("message", (data) => {
const frame = JSON.parse(data);
// frame.type === "price_frame"; merge frame.pairs by frame.pair_chunk.index
});Trial keys cannot open the price stream. Their handshake returns HTTP 403 with { "error": "forbidden" } before the upgrade, even with a valid key. Do not reconnect repeatedly with the same trial key; use the REST access agreed for your trial or contact Rave for stream access.
Browser WebSocket cannot set headers, so expose the stream to browsers through your own authenticated backend relay.
The server supports standard permessage-deflate compression (RFC 7692) when your client offers it. Decompressed frames are identical to uncompressed ones.
Frames
In the default full mode, every frame has type: "price_frame" and schema_version: 2. Delta mode uses different frames.
| Field | Meaning |
|---|---|
prices[] | Flat per-asset prices: symbol, address, bid, ask, max_size, min_size, updated_at. Raw base-unit strings. Filled on the first chunk of each snapshot, empty on the rest |
pairs[] | Pair books, same shape as levels: pair_id, chain_id, bid and ask levels, size bounds, quoteability, freshness, valid_until |
pair_chunk | { index, count }. A snapshot with more than 64 pairs is split across count frames sent back to back |
market_open, timestamp | Snapshot state and time |
freshness is { status, fetched_at, age_secs, ttl_secs }. "fresh" means the levels are current. "stale" means the last good levels are carried forward briefly while they refresh. allowance_target is not on the stream; read it from /v2/limits.
Rebuild a snapshot
- Collect frames with
pair_chunk.indexfrom0tocount - 1. - Merge their
pairsinto one list. - Replace your previous snapshot with it.
Reconnect
Every reconnect starts with a complete current snapshot, not a delta. On close or error, stop routing from that connection's cached book, reconnect with exponential backoff and jitter, and collect every chunk with the same timestamp before replacing the book. Never mix chunks from different snapshots or keep routing from an incomplete one.
If a quoting-control read fails, the stream can continue using a retained last-known-good control state while that state remains usable. Only when no usable control state remains does an established connection close with code 1011 and reason current provider controls unavailable. This is a temporary outage, not a healthy empty snapshot; follow the same reconnect and full-snapshot recovery above. Related HTTP refusals are described in Errors. Full-mode frame schemas are in the stream reference; delta frames are described under Delta mode.
Query options
All three query parameters are optional. Without them you get the full-snapshot stream described above.
| Parameter | Values | Effect |
|---|---|---|
mode | full (default) or delta | delta opts into sequenced snapshots and deltas (below). full keeps price_frame snapshots |
chain_id | Positive integer | Only pair books on that chain |
pair_id | 1 to 256 bytes, matched exactly (case-insensitive) | Only that pair book |
chain_id and pair_id combine, and both work in either mode. Invalid values are rejected with HTTP 400 before the upgrade, for example an unsupported mode, a chain_id that is zero or not a positive integer, or an empty or longer-than-256-byte pair_id. Fix the URL; do not retry it unchanged.
wss://api.rave-trading.com/api/v2/stream?mode=delta&chain_id=56Delta mode
With mode=delta, frames use schema_version: 3 and carry a sequence number and the applied scope:
| Frame | When | What to do |
|---|---|---|
price_snapshot | First update after connecting (sequence: 1), then a periodic full resync. Has full_resync: true | Replace your scoped book with the pairs from every chunk of this sequence |
price_delta | Only when something changed. Has base_sequence | Apply only if base_sequence equals the last sequence you fully applied. Upsert pairs, delete removed_pair_ids, drop the top-level prices named in removed_price_symbols, and update prices |
Rules:
- Chunking works as in full mode: collect
pair_chunk.index0tocount - 1for onesequencebefore applying it.pricesand the removal lists arrive on the first chunk. - Quiet ticks send nothing. A delta only lists pairs whose book changed in any field, including freshness and quoteability.
- If
base_sequencedoes not match your last applied sequence, or a sequence is incomplete, discard the book and reconnect. The new connection starts again with a fullprice_snapshot. - A periodic
price_snapshotuses the next sequence number and has nobase_sequence; replace the book with it.
A delta that changes one book and removes another:
{
"type": "price_delta",
"schema_version": 3,
"sequence": 8,
"base_sequence": 7,
"scope": { "chain_id": 56 },
"prices": [{ "symbol": "AAPLon", "address": "0x...", "bid": "...", "ask": "...", "max_size": "...", "min_size": "...", "updated_at": "2026-10-24T08:00:01Z" }],
"pairs": [{ "pair_id": "...", "chain_id": 56 }],
"removed_pair_ids": ["..."],
"removed_price_symbols": ["..."],
"market_open": true,
"timestamp": "2026-10-24T08:00:01Z"
}pairs entries have the full pair-book shape shown under Frames; they are shortened here.
Updated 8 days ago