Public WebSocket Streams
Public WebSocket streams for real-time order book depth and spot order book data on GaiaEx. No authentication required.
Perp Order Book Stream
WS wss://openapi.gaiaex.com/ws/market/{symbol}
Real-time L2 order book updates for perpetual symbols. No authentication required.
| Parameter | Type | Description |
|---|---|---|
{symbol} | string (path) | Trading symbol — BTC, ETH, xyz:AAPL, vntl:OPENAI, etc. |
Message: orderbook
Sent on every order book change. Contains the full L2 snapshot.
{
"type": "orderbook",
"coin": "BTC",
"levels": [
{
"px": "84250.00",
"sz": "1.2340",
"n": 3
}
],
"time": 1743508800000
}| Field | Type | Description |
|---|---|---|
type | string | Always "orderbook" |
coin | string | Symbol name |
levels | array | Price levels — px (price), sz (size), n (number of orders) |
time | int | Server timestamp in ms |
Message: heartbeat
{
"type": "heartbeat",
"timestamp": 1743508800000
}Message: stale / recovered
Sent when the upstream data feed disconnects or reconnects:
{ "type": "stale", "reason": "upstream disconnected" }
{ "type": "recovered" }Error (invalid symbol)
If the symbol is not found, the server sends an error and closes the connection:
{
"type": "error",
"code": "SYMBOL_NOT_SUPPORTED",
"message": "Symbol 'INVALID' not found."
}Python Example
import asyncio
import websockets
import json
async def stream_orderbook(symbol: str):
uri = f"wss://openapi.gaiaex.com/ws/market/{symbol}"
async with websockets.connect(uri) as ws:
async for message in ws:
data = json.loads(message)
if data["type"] == "orderbook":
top_bid = data["levels"][0] if data["levels"] else None
print(f"{symbol} top: {top_bid}")
elif data["type"] == "heartbeat":
await ws.send("ping")
asyncio.run(stream_orderbook("BTC"))JavaScript Example
const symbol = 'BTC';
const ws = new WebSocket(`wss://openapi.gaiaex.com/ws/market/${symbol}`);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'orderbook') {
console.log(`${data.coin} levels:`, data.levels.length);
}
};
ws.onclose = () => console.log('Disconnected, reconnecting...');
ws.onerror = (err) => console.error('WS error:', err);wscat Example
# Connect to BTC perp order book
wscat -c wss://openapi.gaiaex.com/ws/market/BTC
# Connect to RWA Gold order book
wscat -c wss://openapi.gaiaex.com/ws/market/xyz:GOLDSpot Order Book Stream
WS wss://openapi.gaiaex.com/ws/market/spot/{symbol}
Real-time L2 order book updates for spot tokens. No authentication required.
| Parameter | Type | Description |
|---|---|---|
{symbol} | string (path) | Spot token name — BTC, ETH, PURR, HYPE, etc. |
The message format is identical to the perp order book stream above.
Error (invalid symbol)
{
"type": "error",
"code": "SPOT_SYMBOL_NOT_SUPPORTED",
"message": "Spot symbol 'INVALID' not found. Use /spot/symbols/list."
}Python Example
import asyncio
import websockets
import json
async def stream_spot(symbol: str):
uri = f"wss://openapi.gaiaex.com/ws/market/spot/{symbol}"
async with websockets.connect(uri) as ws:
async for message in ws:
data = json.loads(message)
if data["type"] == "orderbook":
print(f"Spot {symbol}: {len(data['levels'])} levels")
asyncio.run(stream_spot("HYPE"))JavaScript Example
const ws = new WebSocket('wss://openapi.gaiaex.com/ws/market/spot/HYPE');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'orderbook') {
console.log('Spot levels:', data.levels.length);
}
};Ping / Pong
To keep a public WebSocket connection alive, send a text message "ping". The server responds with "pong".
→ "ping"
← "pong"TIP
Most WebSocket libraries handle protocol-level ping/pong frames automatically. The text-based ping/pong above is an additional application-level keepalive mechanism.
Rate Limits
There is no explicit rate limit on public WebSocket connections. However:
- Each connection consumes server resources. Do not open more connections than necessary.
- Use one connection per symbol. Do not rapidly open/close connections.
- If you need multiple symbols, open one connection per symbol and reuse them.
WARNING
Clients that abuse connections (e.g. opening hundreds per second) may be temporarily blocked.
Terminal Walkthrough
Live Test: BTC Perpetual Order Book
# Terminal 1: Connect to BTC
$ wscat -c wss://openapi.gaiaex.com/ws/market/BTC
Connected (press CTRL+C to quit)
< {"type":"orderbook","coin":"BTC","levels":[{"px":"84250.00","sz":"1.234","n":3},{"px":"84249.50","sz":"0.500","n":1}],"time":1712345678000}
< {"type":"orderbook","coin":"BTC","levels":[{"px":"84252.00","sz":"2.100","n":5}],"time":1712345679000}
# Send keepalive
> ping
< pong
# The stream continues with every orderbook change...
# Press CTRL+C to disconnectLive Test: Spot Order Book
# Terminal 2: Connect to ETH spot
$ wscat -c wss://openapi.gaiaex.com/ws/market/spot/ETH
Connected (press CTRL+C to quit)
< {"type":"orderbook","coin":"ETH","levels":[...],"time":...}Live Test: RWA Symbol (Apple Stock)
# RWA symbols use the xyz: prefix
$ wscat -c wss://openapi.gaiaex.com/ws/market/xyz:AAPL
Connected (press CTRL+C to quit)
< {"type":"orderbook","coin":"xyz:AAPL","levels":[{"px":"195.50","sz":"10.0","n":2}],"time":...}Python: Build a Real-Time Spread Monitor
import asyncio
import json
import websockets
async def spread_monitor(symbol: str):
uri = f"wss://openapi.gaiaex.com/ws/market/{symbol}"
async with websockets.connect(uri) as ws:
async for raw in ws:
msg = json.loads(raw)
if msg["type"] != "orderbook" or not msg.get("levels"):
continue
levels = msg["levels"]
# levels is an array of {px, sz, n} objects
# Negative sz = asks, Positive sz = bids
bids = [l for l in levels if float(l["sz"]) > 0]
asks = [l for l in levels if float(l["sz"]) < 0]
if bids and asks:
best_bid = max(bids, key=lambda l: float(l["px"]))
best_ask = min(asks, key=lambda l: float(l["px"]))
spread = float(best_ask["px"]) - float(best_bid["px"])
print(f"{symbol} | Bid: {best_bid['px']} | Ask: {best_ask['px']} | Spread: {spread:.2f}")
asyncio.run(spread_monitor("ETH"))Message Flow Diagram
Client Server
│ │
│──── WSS Connect ────────────────────▶│
│ │
│◀──── orderbook (full snapshot) ──────│
│◀──── orderbook (delta) ──────────────│
│◀──── orderbook (delta) ──────────────│
│ │
│──── "ping" ─────────────────────────▶│
│◀──── "pong" ─────────────────────────│
│ │
│◀──── heartbeat ──────────────────────│ (no changes for a while)
│◀──── orderbook (delta) ──────────────│
│ │
│──── Close ──────────────────────────▶│
│◀──── Close ACK ──────────────────────│