Connect to wss://vee-cinco-testnet.com/ws/. Send {"type":"subscribe","channel":"<name>","id":"<id>"}.
Private channels require authentication before subscribing.
Create an API Key
Generate an Ed25519 key pair. The private key stays on your machine and is never sent anywhere — only the public key is registered. The public key hex becomes your api_key. valid_until is a Unix timestamp in milliseconds; max 180 days from now, defaults to 14 days if omitted.
# Generate key pair (requires openssl)
openssl genpkey -algorithm ed25519 -out private.pem
API_KEY=$(openssl pkey -in private.pem -pubout -outform DER | tail -c 32 | xxd -p -c 32)
# Register — set valid_until to when you want the key to expire (ms timestamp, max 180 days out)
curl -X POST https://<host>/api/v5/createAPIKey \
-H "Content-Type: application/json" \
-d "{
\"ethereum_address\": \"0x...\",
\"public_key\": \"$API_KEY\",
\"api_wallet_name\": \"dYdX\",
\"valid_until\": 1777479871997,
\"signature\": { \"r\": \"0x01\", \"s\": \"0x01\" }
}"Sign the WS auth payload
Sign timestamp + "WEBSOCKET" + "/ws/authenticate" with your Ed25519 private key.
TS=$(($(date +%s) * 1000))
SIG=$(printf '%s' "${TS}WEBSOCKET/ws/authenticate" \
| openssl pkeyutl -sign -inkey private.pem \
| xxd -p | tr -d '\n')Send the authenticate frame
Connect and send this before subscribing to any private channel.
# Connect (requires websocat: brew install websocat)
websocat wss://<host>/ws/
# Send authenticate frame
{"type":"post","id":1,"request":{"type":"authenticate","payload":{"api_key":"<API_KEY>","timestamp":"<TS>","signature":"<SIG>"}}}
# Then subscribe
{"type":"subscribe","channel":"v5_accounts","id":"0x<ethereum_address>"}v5_l2orderbook public
Full L2 orderbook snapshot followed by incremental updates for a single market. On subscribe the server sends the current book up to n_levels price levels per side, then streams delta updates as orders are placed or cancelled.
market_id — Numeric market ID (e.g. "0" for BTC-USD).
subscribe_id: 0
| Param | Type | Description | Default |
|---|---|---|---|
n_levels | integer | Number of price levels per side to include in snapshot and updates. Range 1–100. Defaults to 20. | 20 |
Full book state sent once on subscribe.
| Field | Type | Description | Example |
|---|---|---|---|
bids | array | ['94500.0', '1.5'] | ['94499.0', '2.0'] | |
asks | array | ['94501.0', '0.8'] | ['94502.0', '3.1'] | |
sequence_number | integer | 1042 |
Incremental update. size "0" means the level was removed.
| Field | Type | Description | Example |
|---|---|---|---|
bids | array | | |
asks | array | | |
sequence_number | integer | |
v5_l2orderbook_updates public
Incremental orderbook updates only — no initial snapshot is sent. Suitable for clients that maintain their own book and only need the delta stream. Same update shape as v5_l2orderbook.
market_id — Numeric market ID.
subscribe_id: 0
| Param | Type | Description | Default |
|---|---|---|---|
n_levels | integer | Maximum levels per side per update message. Range 1–100. Defaults to 20. | 20 |
Same incremental delta shape as v5_l2orderbook updates.
| Field | Type | Description | Example |
|---|---|---|---|
bids | array | | |
asks | array | | |
sequence_number | integer | |
v5_trades public
Stream of executed trades for a single market, newest-first. Snapshot on subscribe contains recent trades; streaming updates deliver each new fill as it is matched.
market_id — Numeric market ID.
subscribe_id: 0
A single matched trade.
| Field | Type | Description | Example |
|---|---|---|---|
trade_id | string | 7f3a1b9c-... | |
price | string | 94500.00 | |
size | string | 0.25 | |
side | string | BUY | SELL | |
created_at | integer | Unix timestamp in milliseconds. | 1712345678000 |
v5_markets public
Global channel (no id) that streams market metadata and 24-hour statistics for all listed markets. Clients receive a snapshot of all markets on subscribe followed by individual market updates as prices, funding rates, or open interest changes.
One market entry; keyed by market_id.
| Field | Type | Description | Example |
|---|---|---|---|
market_id | integer | 0 | |
display_name | string | BTC-USD | |
oracle_price | string | 94500.00 | |
index_price | string | 94498.00 | |
open_interest | string | 1234.5 | |
funding_rate | string | Current 1-hour funding rate. | 0.0001 |
volume_24h | string | 890123.45 |
v5_oracle_prices public
Per-market oracle price updates sourced from the on-chain slinky aggregator. Pushes a new price whenever the oracle index changes by the minimum tick.
market_id — Numeric market ID.
subscribe_id: 0
| Field | Type | Description | Example |
|---|---|---|---|
market_id | integer | 0 | |
oracle_price | string | 94501.00 | |
timestamp | integer | Unix timestamp in milliseconds. | 1712345679000 |
v5_bbo public
Best bid and offer (top-of-book) for a single market. Lower bandwidth than v5_l2orderbook when only the inside quote is needed.
market_id — Numeric market ID.
subscribe_id: 0
| Field | Type | Description | Example |
|---|---|---|---|
bid_price | string | 94500.00 | |
bid_size | string | 1.5 | |
ask_price | string | 94501.00 | |
ask_size | string | 0.8 | |
sequence_number | integer | |
v5_accounts auth required
Account state snapshot and streaming updates for a single sub-account. Snapshot on subscribe includes open positions, balances, and margin info. Updates are pushed whenever a fill, liquidation, or funding payment changes account state. Periodic re-snapshots are sent every 5 seconds.
ethereum_address — Master Ethereum address (0x-prefixed, 40 hex digits) that owns the sub-account. Must match the API key used to authenticate.
subscribe_id: 0xAbCd...1234
Payload shape for v5_accounts channel snapshot channel_data (balances + open positions). total_value is the account value line used in the channel (same semantics as equity in REST Account).
| Field | Type | Description | Example |
|---|---|---|---|
free_collateral | string | | |
total_value | string | Total account value for the snapshot row (equity line). | |
positions | array | |
Partial account update triggered by a fill or funding event.
| Field | Type | Description | Example |
|---|---|---|---|
free_collateral | string | | |
positions | array | |
v5_positions auth required
Open positions only for the authenticated sub-account. Snapshot on subscribe uses the same per-row shape as the positions array in v5_accounts; streaming updates when position fields change.
ethereum_address — Master Ethereum address (0x-prefixed, 40 hex digits) that owns the sub-account. Must match the API key used to authenticate.
subscribe_id: 0xAbCd...1234
Sent once on subscribe.
| Field | Type | Description | Example |
|---|---|---|---|
is_snapshot | boolean | | |
positions | array | |
Partial position list or per-market deltas; entries use the same row shape.
| Field | Type | Description | Example |
|---|---|---|---|
positions | array | |
v5_user_fill auth required
Per-user fill stream. Snapshot on subscribe contains recent fills; streaming updates deliver each new fill as orders are matched. Snapshot is sent once on connect only.
ethereum_address — Master Ethereum address associated with the API key.
subscribe_id: 0xAbCd...1234
Envelope for v5_user_fill channel snapshot data. Sent on subscribe with is_snapshot=true, containing recent fills from ClickHouse.
| Field | Type | Description | Example |
|---|---|---|---|
is_snapshot | boolean | | |
fills | array | |
Unified fill shape used across REST responses, WebSocket snapshots, and streaming updates. Fields only available from persistence (not the SBE wire path) are optional and may be absent in streaming updates.
| Field | Type | Description | Example |
|---|---|---|---|
trade_id | string | Unique trade identifier. | |
order_id | string | Order ID that generated this fill. | |
address | string | Ethereum address (lowercase 0x + 40 hex). Only present on REST and snapshot responses. | |
account_index | integer | Account index (account index, 0–10). Identifies the account for orders, positions, fills, and API keys. | |
market_id | integer | Perpetual market identifier. 0 = BTC-PERP, 1 = ETH-PERP. Used for orders, positions, funding, and market metadata. | 0 | 1 |
market_display_name | string | Market symbol (e.g. BTC-PERP). | |
client_id | string | Client-provided order ID. Only present on streaming updates. | |
side | string | Order side. | BUY | SELL |
original_size | string | Original order size in human-readable base-asset units (decimal string). | |
size | string | Fill size in human-readable base-asset units (decimal string). | |
price | string | Fill price in human-readable USD (decimal string). | |
fee | string | Fee amount (decimal string). | |
closed_pnl | string | Realized price PnL on the closed or reduced portion of the position (decimal string, quote currency). Omitted or "0" when the fill only adds to or opens a position. | |
role | string | Liquidity role (maker or taker). | MAKER | TAKER |
remaining_size | string | Remaining unfilled order size after this fill. Only present on streaming updates. | |
created_at | integer | Fill timestamp (epoch ms). | |
sequence_number | integer | Sequence number for ordering and reconciliation. Only present on streaming updates. | |
v5_orders auth required
Open and recently closed order updates for an account. Snapshot on subscribe includes all open orders and up to 100 recently closed orders. Streaming updates use a unified shape for both status changes and fill events. Snapshot is sent once on connect only.
ethereum_address — Master Ethereum address associated with the API key.
subscribe_id: 0xAbCd...1234
Unified WsOrderUpdate shape used for both snapshot entries and streaming events.
| Field | Type | Description | Example |
|---|---|---|---|
order_id | string | | |
client_id | string | | |
market_id | integer | | |
market_display_name | string | BTC-USD | |
side | string | BUY | SELL | |
status | string | OPEN | FILLED | CANCELED | MARGIN_CANCELED | REJECTED | TPSL_PLACED | TPSL_CANCELED | TPSL_TRIGGERED | |
price | string | Limit price. | 94000.00 |
original_size | string | 1.0 | |
remaining_size | string | 0.0 means fully filled. | 0.5 |
trigger_price | string | Set for TP/SL orders only. | |
tpsl_type | string | Set for TP/SL orders only. | TAKE_PROFIT | STOP_LOSS |
rejection_reason | string | Non-empty when status is REJECTED. | |
status_timestamp | integer | Unix timestamp in milliseconds of the most recent status change. | |
sequence_number | integer | |