WebSocket
Endpoint: wss://v4-api.dev.parcllabs.com/v1/ws
The WebSocket provides real-time data: orderbook updates, fills, price changes, and block production. Connect, subscribe to channels, and receive events.
Connecting
const ws = new WebSocket("wss://v4-api.dev.parcllabs.com/v1/ws");The server sends a heartbeat ping every 5 seconds. Send { "type": "ping" } to get a pong back with current block height and latency info.
Subscribing
Send a subscribe message with the channels you want:
{
"type": "subscribe",
"channels": [
{ "channel": "orderbook", "market_id": 0 },
{ "channel": "trades", "market_id": 0 }
]
}Response:
{
"type": "subscribed",
"channels": [
{ "channel": "orderbook", "market_id": 0 },
{ "channel": "trades", "market_id": 0 }
]
}To unsubscribe:
{
"type": "unsubscribe",
"channels": [
{ "channel": "orderbook", "market_id": 0 }
]
}Channels
orderbook
Full orderbook snapshot on subscribe, then incremental updates on every change.
Subscribe: { "channel": "orderbook", "market_id": 0 }
Snapshot (sent immediately on subscribe):
{
"type": "orderbookSnapshot",
"market_id": 0,
"bids": [["58100000000", "500000"], ...],
"asks": [["58200000000", "300000"], ...]
}Updates (on each order/fill/cancel):
{
"type": "orderbookUpdate",
"market_id": 0,
"bids": [["58100000000", "450000"]],
"asks": []
}A size of "0" means that price level was removed.
trades
Recent trades for a market.
Subscribe: { "channel": "trades", "market_id": 0 }
{
"type": "trade",
"market_id": 0,
"price": "58150000000",
"size": "100000",
"side": "Long",
"timestamp": 1712345678000
}fills
Your fills (requires your account ID). Fires when your orders get filled.
Subscribe: { "channel": "fills", "account_id": 12 }
{
"type": "fill",
"market_id": 0,
"price": "58150000000",
"size": "100000",
"side": "Long",
"fee": "203000",
"order_id": 42,
"timestamp": 1712345678000
}orders
Your order updates (placed, canceled, modified).
Subscribe: { "channel": "orders", "account_id": 12 }
positions
Your position changes.
Subscribe: { "channel": "positions", "account_id": 12 }
funding
Funding rate updates for a market. Fires hourly when funding settles.
Subscribe: { "channel": "funding", "market_id": 0 }
{
"type": "funding",
"market_id": 0,
"funding_rate": "-15800",
"timestamp": 1712345678000
}oracle / oracleUpdates
Oracle price updates for a market.
Subscribe: { "channel": "oracleUpdates", "market_id": 0 }
{
"type": "oracleUpdate",
"market_id": 0,
"price": "58035000000",
"previous_price": "57890000000",
"valid_until": 1712433900
}explorer
Block production info. Fires on every finalized block.
Subscribe: { "channel": "explorer" }
{
"type": "blockFinalized",
"height": 73001,
"hash": "abc123...",
"proposer": "e1e7af3f...",
"timestamp": 1712345678943,
"tx_count": 3
}Ping/pong
Send a ping to measure latency and get current block info:
{ "type": "ping" }Response:
{
"type": "pong",
"blockHeight": 73001,
"blockTimeMs": 198,
"timestamp": 1712345678943
}Example: full orderbook bot
const WebSocket = require("ws");
const ws = new WebSocket("wss://v4-api.dev.parcllabs.com/v1/ws");
let bids = new Map(); // price -> size
let asks = new Map();
ws.on("open", () => {
ws.send(JSON.stringify({
type: "subscribe",
channels: [{ channel: "orderbook", market_id: 0 }],
}));
});
ws.on("message", (data) => {
const msg = JSON.parse(data);
if (msg.type === "orderbookSnapshot") {
bids = new Map(msg.bids.map(([p, s]) => [p, s]));
asks = new Map(msg.asks.map(([p, s]) => [p, s]));
console.log(`Snapshot: ${bids.size} bids, ${asks.size} asks`);
}
if (msg.type === "orderbookUpdate") {
for (const [price, size] of msg.bids) {
if (size === "0") bids.delete(price);
else bids.set(price, size);
}
for (const [price, size] of msg.asks) {
if (size === "0") asks.delete(price);
else asks.set(price, size);
}
const bestBid = [...bids.keys()].sort().pop();
const bestAsk = [...asks.keys()].sort()[0];
console.log(`Best bid: ${bestBid}, Best ask: ${bestAsk}`);
}
});