Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vela.monolithsystematic.com/llms.txt

Use this file to discover all available pages before exploring further.

Connection

wss://vela-engine.fly.dev/ws
const ws = new WebSocket("wss://vela-engine.fly.dev/ws");

ws.onopen = () => {
  ws.send(JSON.stringify({ type: "ping" }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  handleMessage(msg);
};
Send a ping every 30 seconds. The server closes idle connections after 60 seconds.

Subscribe / Unsubscribe

{ "type": "subscribe", "channel": "orderbook:ETH-USDC" }
{ "type": "unsubscribe", "channel": "orderbook:ETH-USDC" }
Private channels require authentication before subscribing. See Authentication Flow below.

Public Channels

ChannelDescription
orderbook:{market_id}Full order book snapshot + incremental updates
trades:{market_id}Public trade feed for a market
marketsAll markets — best bid/ask, 24h volume, updated on change

Order Book

Snapshot (sent immediately on subscribe, and on significant changes):
{
  "type": "snapshot",
  "channel": "orderbook:ETH-USDC",
  "seq": 1,
  "data": {
    "bids": [[1580500000, 500000], [1580000000, 1000000]],
    "asks": [[1581000000, 300000], [1581500000, 700000]]
  },
  "timestamp": "2026-04-15T12:00:00.000Z"
}
Incremental update:
{
  "type": "update",
  "channel": "orderbook:ETH-USDC",
  "seq": 2,
  "data": {
    "bids": [[1580500000, 0]],
    "asks": []
  },
  "timestamp": "2026-04-15T12:00:00.100Z"
}
A quantity of 0 means the price level was removed. Apply updates in seq order. If you detect a gap in sequence numbers, re-subscribe to get a fresh snapshot.

Trades

{
  "type": "trade",
  "channel": "trades:ETH-USDC",
  "seq": 5,
  "data": {
    "trade_id": "trd_4a2b1c",
    "price": 1581000000,
    "quantity": 500000,
    "side": "bid",
    "timestamp": "2026-04-15T12:00:01.234Z"
  }
}
side is the aggressor (taker) side.

Markets

{
  "type": "markets_update",
  "channel": "markets",
  "seq": 12,
  "data": [
    {
      "id": "ETH-USDC",
      "best_bid": "1580500000",
      "best_ask": "1581000000",
      "volume_24h": "42500000000",
      "last_price": "1580800000"
    }
  ],
  "timestamp": "2026-04-15T12:00:05.000Z"
}

Private Channel

ChannelAuth RequiredDescription
account:{address}YesAll account events: fills, order updates, balance changes

Authentication Flow

The auth signature message is vela:ws:{address}:{timestamp} (timestamp is Unix seconds, must be within 30 seconds of server time). Step 1 — Send auth:
{
  "type": "auth",
  "address": "0xYourWalletAddress",
  "signature": "0x...",
  "timestamp": 1713000000
}
Signing in Python:
from eth_account.messages import encode_defunct

def sign_ws_auth(account, address: str, timestamp: int) -> str:
    msg = f"vela:ws:{address}:{timestamp}"
    message = encode_defunct(text=msg)
    signed = account.sign_message(message)
    return signed.signature.hex()
Signing in TypeScript:
async function signWsAuth(
  signer: ethers.Signer,
  address: string,
  timestamp: number
): Promise<string> {
  return signer.signMessage(`vela:ws:${address}:${timestamp}`);
}
Step 2 — Subscribe to account channel:
{ "type": "subscribe", "channel": "account:0xYourWalletAddress" }
Auth success response:
{ "type": "auth_success", "address": "0xYourWalletAddress" }

Account Channel Message Types

account_snapshot

Sent immediately after subscribing to the account channel. Provides current state.
{
  "type": "account_snapshot",
  "channel": "account:0x...",
  "data": {
    "balances": {
      "USDC": { "available": "10000000000", "locked": "500000000" }
    },
    "open_orders": [
      {
        "order_id": 12345,
        "market_id": "ETH-USDC",
        "side": "bid",
        "price": 1580500000,
        "quantity": 500000,
        "filled_quantity": 0,
        "status": "open"
      }
    ]
  }
}

fill

Sent when one of your orders receives a fill.
{
  "type": "fill",
  "channel": "account:0x...",
  "data": {
    "fill_id": "fill_abc123",
    "order_id": 12345,
    "client_order_id": "my-order-001",
    "market_id": "ETH-USDC",
    "side": "bid",
    "price": 1580500000,
    "quantity": 250000,
    "filled_quantity_cumulative": 250000,
    "is_maker": true,
    "maker_fee": -39512,
    "taker_fee": 197563,
    "timestamp": "2026-04-15T12:00:01.234Z"
  }
}

order_update

Sent when an order’s status changes.
{
  "type": "order_update",
  "channel": "account:0x...",
  "data": {
    "order_id": 12345,
    "client_order_id": "my-order-001",
    "market_id": "ETH-USDC",
    "status": "partially_filled",
    "filled_quantity": 250000,
    "remaining_quantity": 250000,
    "last_fill_price": 1580500000
  }
}
Possible status values: open, partially_filled, filled, cancelled, rejected. cancelled with no user-initiated cancel means the credit system auto-cancelled the order.

balance_update

Sent when your balance changes.
{
  "type": "balance_update",
  "channel": "account:0x...",
  "data": {
    "asset": "USDC",
    "available": "9840000000",
    "locked": "0",
    "reason": "fill",
    "timestamp": "2026-04-15T12:00:01.234Z"
  }
}
reason values: fill, order_placed, order_cancelled, deposit, withdrawal.

Sequence Numbers and Gap Detection

All messages include a seq field that increments monotonically per channel. If you receive two messages with non-consecutive sequence numbers, you missed one or more updates. On gap detection: unsubscribe and re-subscribe to the channel to receive a fresh snapshot, then resume applying incremental updates from the new baseline.

Auto-Reconnect Pattern

import asyncio
import websockets
import json
import time

async def connect_and_subscribe(address: str, sign_fn):
    uri = "wss://vela-engine.fly.dev/ws"
    while True:
        try:
            async with websockets.connect(uri) as ws:
                # Auth
                ts = int(time.time())
                sig = sign_fn(address, ts)
                await ws.send(json.dumps({
                    "type": "auth",
                    "address": address,
                    "signature": sig,
                    "timestamp": ts,
                }))

                # Subscribe
                await ws.send(json.dumps({
                    "type": "subscribe",
                    "channel": f"account:{address}",
                }))
                await ws.send(json.dumps({
                    "type": "subscribe",
                    "channel": "orderbook:ETH-USDC",
                }))

                async for message in ws:
                    handle(json.loads(message))

        except websockets.ConnectionClosed:
            await asyncio.sleep(1)  # brief pause before reconnect
On reconnect, re-send auth and all subscriptions. The server does not persist subscription state across connections.