WebSocket Channels

Connect to wss://vee-cinco-testnet.com/ws/. Send {"type":"subscribe","channel":"<name>","id":"<id>"}.

Authentication

Private channels require authentication before subscribing.

1

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.

shell
# 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\" }
  }"
2

Sign the WS auth payload

Sign timestamp + "WEBSOCKET" + "/ws/authenticate" with your Ed25519 private key.

shell
TS=$(($(date +%s) * 1000))
SIG=$(printf '%s' "${TS}WEBSOCKET/ws/authenticate" \
  | openssl pkeyutl -sign -inkey private.pem \
  | xxd -p | tr -d '\n')
3

Send the authenticate frame

Connect and send this before subscribing to any private channel.

shell
# 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>"}

Channels

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.

Subscription ID

market_id — Numeric market ID (e.g. "0" for BTC-USD).

subscribe_id: 0

Subscribe Parameters

ParamTypeDescriptionDefault
n_levelsintegerNumber of price levels per side to include in snapshot and updates. Range 1–100. Defaults to 20.20

Snapshot payload

Full book state sent once on subscribe.

FieldTypeDescriptionExample
bidsarray['94500.0', '1.5'] | ['94499.0', '2.0']
asksarray['94501.0', '0.8'] | ['94502.0', '3.1']
sequence_numberinteger1042

Update payload

Incremental update. size "0" means the level was removed.

FieldTypeDescriptionExample
bidsarray
asksarray
sequence_numberinteger

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.

Subscription ID

market_id — Numeric market ID.

subscribe_id: 0

Subscribe Parameters

ParamTypeDescriptionDefault
n_levelsintegerMaximum levels per side per update message. Range 1–100. Defaults to 20.20

Update payload

Same incremental delta shape as v5_l2orderbook updates.

FieldTypeDescriptionExample
bidsarray
asksarray
sequence_numberinteger

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.

Subscription ID

market_id — Numeric market ID.

subscribe_id: 0

Update payload

A single matched trade.

FieldTypeDescriptionExample
trade_idstring7f3a1b9c-...
pricestring94500.00
sizestring0.25
sidestringBUY | SELL
created_atintegerUnix 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.

Update payload

One market entry; keyed by market_id.

FieldTypeDescriptionExample
market_idinteger0
display_namestringBTC-USD
oracle_pricestring94500.00
index_pricestring94498.00
open_intereststring1234.5
funding_ratestringCurrent 1-hour funding rate.0.0001
volume_24hstring890123.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.

Subscription ID

market_id — Numeric market ID.

subscribe_id: 0

Update payload

FieldTypeDescriptionExample
market_idinteger0
oracle_pricestring94501.00
timestampintegerUnix 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.

Subscription ID

market_id — Numeric market ID.

subscribe_id: 0

Update payload

FieldTypeDescriptionExample
bid_pricestring94500.00
bid_sizestring1.5
ask_pricestring94501.00
ask_sizestring0.8
sequence_numberinteger

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.

Subscription ID

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

Snapshot payload

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).

FieldTypeDescriptionExample
free_collateralstring
total_valuestringTotal account value for the snapshot row (equity line).
positionsarray

Update payload

Partial account update triggered by a fill or funding event.

FieldTypeDescriptionExample
free_collateralstring
positionsarray

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.

Subscription ID

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

Snapshot payload

Sent once on subscribe.

FieldTypeDescriptionExample
is_snapshotboolean
positionsarray

Update payload

Partial position list or per-market deltas; entries use the same row shape.

FieldTypeDescriptionExample
positionsarray

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.

Subscription ID

ethereum_address — Master Ethereum address associated with the API key.

subscribe_id: 0xAbCd...1234

Snapshot payload

Envelope for v5_user_fill channel snapshot data. Sent on subscribe with is_snapshot=true, containing recent fills from ClickHouse.

FieldTypeDescriptionExample
is_snapshotboolean
fillsarray

Update payload

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.

FieldTypeDescriptionExample
trade_idstringUnique trade identifier.
order_idstringOrder ID that generated this fill.
addressstringEthereum address (lowercase 0x + 40 hex). Only present on REST and snapshot responses.
account_indexintegerAccount index (account index, 0–10). Identifies the account for orders, positions, fills, and API keys.
market_idintegerPerpetual market identifier. 0 = BTC-PERP, 1 = ETH-PERP. Used for orders, positions, funding, and market metadata.0 | 1
market_display_namestringMarket symbol (e.g. BTC-PERP).
client_idstringClient-provided order ID. Only present on streaming updates.
sidestringOrder side.BUY | SELL
original_sizestringOriginal order size in human-readable base-asset units (decimal string).
sizestringFill size in human-readable base-asset units (decimal string).
pricestringFill price in human-readable USD (decimal string).
feestringFee amount (decimal string).
closed_pnlstringRealized 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.
rolestringLiquidity role (maker or taker).MAKER | TAKER
remaining_sizestringRemaining unfilled order size after this fill. Only present on streaming updates.
created_atintegerFill timestamp (epoch ms).
sequence_numberintegerSequence 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.

Subscription ID

ethereum_address — Master Ethereum address associated with the API key.

subscribe_id: 0xAbCd...1234

Update payload

Unified WsOrderUpdate shape used for both snapshot entries and streaming events.

FieldTypeDescriptionExample
order_idstring
client_idstring
market_idinteger
market_display_namestringBTC-USD
sidestringBUY | SELL
statusstringOPEN | FILLED | CANCELED | MARGIN_CANCELED | REJECTED | TPSL_PLACED | TPSL_CANCELED | TPSL_TRIGGERED
pricestringLimit price.94000.00
original_sizestring1.0
remaining_sizestring0.0 means fully filled.0.5
trigger_pricestringSet for TP/SL orders only.
tpsl_typestringSet for TP/SL orders only.TAKE_PROFIT | STOP_LOSS
rejection_reasonstringNon-empty when status is REJECTED.
status_timestampintegerUnix timestamp in milliseconds of the most recent status change.
sequence_numberinteger