Documentation Index
Fetch the complete documentation index at: https://docs.vatic.trading/llms.txt
Use this file to discover all available pages before exploring further.
Endpoint
wss://api.vatic.trading/ws
No authentication required. Connect once and subscribe to any supported asset / stream combination.
Available streams
The WebSocket currently supports two real-time streams:
| Stream | Subscribe with | What you receive |
|---|
| Vatic target prices | {"type":"subscribe","asset":"btc","marketTypes":["5min","15min"]} | window_open events at each Polymarket/Vatic market boundary |
| Hyperliquid mark prices | {"type":"subscribe","channel":"hyperliquid_mark_price","asset":"btc"} | hyperliquid_mark_price snapshots and live updates for the underlying perp mark price |
Why WebSocket over polling?
REST polling at window boundaries causes two problems:
- 502 errors — Chainlink/Binance takes 1–5s to publish a price after a window opens. Polling at
:00 means your request arrives before the price exists.
- Rate limits — Hammering the endpoint while waiting burns your 120 req/min budget instantly.
The WebSocket absorbs the publish lag server-side, retries the upstream fetch automatically, and pushes the resolved price to all subscribers the instant it’s ready. For Hyperliquid, it also gives you live access to the underlying markPrice that matters for prediction-market settlement.
Market types
| Type | Boundary | Price source |
|---|
5min | Every 5 minutes | Chainlink Data Streams |
15min | Every 15 minutes | Chainlink Data Streams |
1hour | Top of every hour | Binance aggTrades |
4hour | 00:00, 04:00, 08:00, 12:00, 16:00, 20:00 ET | Binance aggTrades |
daily | Midnight ET | Binance aggTrades |
Supported assets: btc, eth, sol, xrp, hype, doge, bnb
Connection flow
1. Connect
On connect the server immediately sends a connected event:
{
"event": "connected",
"supportedAssets": ["btc", "eth", "sol", "xrp", "hype", "doge", "bnb"],
"supportedMarketTypes": ["5min", "15min", "1hour", "4hour", "daily"],
"supportedChannels": ["hyperliquid_mark_price"],
"usage": [
"Send {\"type\":\"subscribe\",\"asset\":\"btc\",\"marketTypes\":[\"5min\",\"15min\"]}",
"Send {\"type\":\"subscribe\",\"channel\":\"hyperliquid_mark_price\",\"asset\":\"btc\"}"
]
}
2. Subscribe
Vatic target prices
Send a JSON message to subscribe to one asset across one or more market types:
{
"type": "subscribe",
"asset": "btc",
"marketTypes": ["5min", "15min"]
}
| Field | Type | Description |
|---|
type | "subscribe" | Required. |
asset | string | One of the supported asset symbols. |
marketTypes | string[] | One or more market types. Omit to subscribe to all five. |
The server confirms with a subscribed event and immediately pushes a window_open snapshot for the current window of each subscribed type — so you always have the latest price on connect, without waiting for the next boundary.
{ "event": "subscribed", "asset": "btc", "marketTypes": ["5min", "15min"] }
Hyperliquid mark price
Send a JSON message to subscribe to the underlying perp mark-price stream:
{
"type": "subscribe",
"channel": "hyperliquid_mark_price",
"asset": "btc"
}
| Field | Type | Description |
|---|
type | "subscribe" | Required. |
channel | "hyperliquid_mark_price" | Required for the Hyperliquid mark-price stream. |
asset | string | One of the supported asset symbols. |
The server confirms with:
{ "event": "subscribed", "channel": "hyperliquid_mark_price", "asset": "btc" }
It then immediately pushes a snapshot:
{
"event": "hyperliquid_mark_price",
"channel": "hyperliquid_mark_price",
"asset": "btc",
"coin": "BTC",
"source": "hyperliquid",
"markPrice": 78669,
"oraclePrice": 78700,
"midPrice": 78669.5,
"prevDayPx": 78333,
"change24h": 0.4289379954808319,
"openInterest": 29626.19272,
"funding": 0.0000058782,
"volume": 921508494.6523755,
"observedAt": "2026-05-03T13:38:56.147Z",
"snapshot": true
}
After the snapshot, the server keeps broadcasting updates whenever the upstream Hyperliquid perp context changes.
3. Receive price events
At every window boundary the server pushes a window_open event:
{
"event": "window_open",
"asset": "btc",
"marketType": "5min",
"windowStart": 1744027500,
"windowStartIso": "2025-04-07T12:05:00.000Z",
"price": 82450.75,
"source": "chainlink"
}
The initial snapshot after subscribe includes "snapshot": true.
If the upstream price fetch fails after all retries, you receive window_open_error instead:
{
"event": "window_open_error",
"asset": "btc",
"marketType": "5min",
"windowStart": 1744027500,
"windowStartIso": "2025-04-07T12:05:00.000Z",
"error": "Price unavailable — upstream fetch failed after retries"
}
4. Unsubscribe
{ "type": "unsubscribe" }
Removes all subscriptions for the current connection.
Heartbeat
The server sends a WebSocket ping every 30 seconds. If your client does not respond with a pong, the connection is terminated. Most WebSocket libraries handle this automatically.
Examples
Node.js
import WebSocket from 'ws';
function connect() {
const ws = new WebSocket('wss://api.vatic.trading/ws');
ws.on('open', () => console.log('connected'));
ws.on('message', (raw) => {
const text = typeof raw === 'string' ? raw : raw.toString();
const msg = JSON.parse(text);
if (msg.event === 'connected') {
ws.send(JSON.stringify({
type: 'subscribe',
asset: 'btc',
marketTypes: ['5min', '15min'],
}));
}
if (msg.event === 'window_open') {
const label = msg.snapshot ? 'snapshot' : 'LIVE';
console.log(`[${label}] ${msg.asset} ${msg.marketType} — $${msg.price} (${msg.windowStartIso})`);
}
});
ws.on('close', () => {
console.log('disconnected, reconnecting in 3s...');
setTimeout(connect, 3000);
});
ws.on('error', (err) => console.error('ws error:', err.message));
}
connect();
TypeScript — Hyperliquid mark price
import WebSocket, { type RawData } from 'ws';
function connect() {
const ws = new WebSocket('wss://api.vatic.trading/ws');
ws.on('message', (raw: RawData) => {
const text = typeof raw === 'string' ? raw : raw.toString();
const msg = JSON.parse(text);
if (msg.event === 'connected') {
ws.send(JSON.stringify({
type: 'subscribe',
channel: 'hyperliquid_mark_price',
asset: 'btc',
}));
}
if (msg.event === 'hyperliquid_mark_price') {
const label = msg.snapshot ? 'snapshot' : 'LIVE';
console.log(
`[${label}] ${msg.asset} mark=${msg.markPrice} oracle=${msg.oraclePrice} funding=${msg.funding} at ${msg.observedAt}`
);
}
});
ws.on('close', () => setTimeout(connect, 3000));
}
connect();
Python
import asyncio, json
import websockets
async def connect():
uri = "wss://api.vatic.trading/ws"
while True:
try:
async with websockets.connect(uri, ping_interval=30) as ws:
print("connected")
async for raw in ws:
msg = json.loads(raw)
if msg["event"] == "connected":
await ws.send(json.dumps({
"type": "subscribe",
"asset": "btc",
"marketTypes": ["5min", "15min"],
}))
elif msg["event"] == "window_open":
label = "snapshot" if msg.get("snapshot") else "LIVE"
print(f"[{label}] {msg['asset']} {msg['marketType']} — ${msg['price']} ({msg['windowStartIso']})")
except Exception as e:
print(f"disconnected ({e}), reconnecting in 3s...")
await asyncio.sleep(3)
asyncio.run(connect())
TypeScript
import WebSocket, { type RawData } from 'ws';
interface WindowOpenEvent {
event: 'window_open';
asset: string;
marketType: string;
windowStart: number;
windowStartIso: string;
price: number;
source: string;
snapshot?: boolean;
}
function connect(): void {
const ws = new WebSocket('wss://api.vatic.trading/ws');
ws.on('message', (raw: RawData) => {
const text = typeof raw === 'string' ? raw : raw.toString();
const msg = JSON.parse(text);
if (msg.event === 'connected') {
ws.send(JSON.stringify({
type: 'subscribe',
asset: 'btc',
marketTypes: ['5min', '15min'],
}));
}
if (msg.event === 'window_open') {
const e = msg as WindowOpenEvent;
const label = e.snapshot ? 'snapshot' : 'LIVE';
console.log(`[${label}] ${e.asset} ${e.marketType} — $${e.price} (${e.windowStartIso})`);
}
});
ws.on('close', () => setTimeout(connect, 3000));
ws.on('error', (err) => console.error('ws error:', err.message));
}
connect();
Event reference
| Event | Direction | Description |
|---|
connected | Server → Client | Sent immediately on connect with supported assets and types. |
subscribed | Server → Client | Confirms a successful subscribe. Followed by current-window snapshots. |
unsubscribed | Server → Client | Confirms unsubscribe. |
window_open | Server → Client | Target price pushed at every window boundary. Also sent as snapshot on subscribe. |
window_open_error | Server → Client | Upstream price fetch failed after all retries. |
hyperliquid_mark_price | Server → Client | Live Hyperliquid underlying perp mark price, including oraclePrice, midPrice, funding, and openInterest. |
error | Server → Client | Invalid JSON, unknown asset, or unknown message type. |
subscribe | Client → Server | Subscribe to either Vatic target-price market types or a named real-time channel like hyperliquid_mark_price. |
unsubscribe | Client → Server | Remove all subscriptions for this connection. |