API documentation

WebSocket

Endpoint wss://api.lexx-trade.com/api/v2/ws · AsyncAPI 3.0 · API v2.0.0 · download asyncapi.yaml · Practical client patterns live in the WebSocket guide.

Real-time, per-user streaming for orders, balances, positions, and bot state over a single authenticated WebSocket. Companion to the REST OpenAPI spec (openapi.yaml).

All messages are JSON objects with an op discriminator. Every server message carries a ts (Unix ms); client requests may carry a client-chosen id that is echoed back on the reply.

Connection

  • Endpoint: wss://api.lexx-trade.com/api/v2/ws
  • One socket carries all channels. There are no public (unauthenticated) channels — market data (orderbook/ticker/public trades) is not served here.
  • Delivery is per-user: a socket only ever receives events for the account that owns the authenticating key.

Authentication (Ed25519, challenge-response)

  1. On connect the server sends a one-time challenge.
  2. The client signs "WSAuth" + timestamp + challenge with its Ed25519 private key and sends an auth request.
  3. The server replies with auth { authenticated: true, userId }.
  • key is the raw 32-byte Ed25519 public key, Base64url (43 chars) — this IS the key identifier.
  • sign is the Base64 Ed25519 signature (Base64url also accepted).
  • timestamp is Unix ms and must be within ±5000 ms of server time.
  • The challenge is single-use and connection-bound, so a captured auth frame cannot be replayed. To re-authenticate, reconnect.
  • Auth must complete within 5 s of connecting (else the socket is closed, 4001).
  • If the key has an IP whitelist it is enforced (CIDR) against the real client IP.
  • Subscribing requires a valid key with at least read permission.

Limits (DoS backstops — not per subscription tier)

LimitValueOn breach
Connections per client IP50upgrade rejected 429
Total connections per node10 000upgrade rejected 503
Max frame size64 KiBsocket closed 1009 (message too big; may surface as abnormal 1006 on some clients)
Messages per socket200 / 10 sRATE_LIMITED, close 1008
Auth attempts per socket5TOO_MANY_ATTEMPTS, close 4001
Send-buffer backlog per socket4 MiBsocket terminated (slow consumer — abnormal close 1006)

A client that cannot keep up with its event stream (unread data piles up past 4 MiB) is dropped without a close frame — read messages promptly and reconnect on 1006.

Unknown op values after authentication are silently ignored (no error reply) — do not block waiting on the correlation id of an unsupported op.

Heartbeat

The server sends a WebSocket control-ping every 20 s; standard clients auto-reply with a pong and a socket that misses it is terminated within ~20–40 s. An optional application-level ping/pong is also supported.

Close codes

CodeReason
1008Message-rate limit exceeded
1009Frame exceeded the 64 KiB max size (message too big)
4001Auth timeout, or too many auth attempts
4003API key revoked mid-session

Reconnecting

The auth challenge is single-use and connection-bound: after any disconnect you must open a new socket, receive a fresh challenge, re-authenticate, and re-subscribe (subscriptions are not persisted across connections). Recommended client behavior:

  • Reconnect with exponential backoff plus jitter (e.g. 1 s → 2 s → 4 s → … capped at 30 s); reset the backoff after a successful re-auth.
  • On close 1008 (message-rate limit) reduce your message rate before reconnecting.
  • On close 4001 complete auth faster after connecting (it must finish within 5 s) and check your clock skew (±5000 ms window).
  • On close 4003 the API key was revoked — do not auto-reconnect; obtain a new key first.

Client → Server

Messages the CLIENT sends to the server.

auth Authenticate (client → server)

Authenticate the connection using the server-issued challenge.

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

args object required
key string required

Raw 32-byte Ed25519 public key, Base64url (43 chars). This IS the key id.

sign string required

Base64 Ed25519 signature of "WSAuth" + timestamp + challenge (Base64url also accepted).

timestamp integer required

Unix milliseconds; must be within ±5000 ms of server time.

ping Ping (client → server)

Application-level liveness check; the server replies with pong.

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

subscribe Subscribe (client → server)

Subscribe to a private channel. Requires auth + a key with read access.

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

args object required
channel string required

Private channel name.

enum: "orders" · "balance" · "positions" · "botStatus"

exchange string

Optional filter — narrows delivery to one exchange. Supported on orders, balance, and positions; NOT supported on botStatus (the subscription is ACKed but never delivers).

symbol string

Optional filter — narrows delivery to one symbol. Supported ONLY on orders and ONLY together with exchange. On other channels (or without exchange) the subscription is ACKed but never delivers.

unsubscribe Unsubscribe (client → server)

Remove a previous subscription (same args identify the subscription).

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

args object required
channel string required

Private channel name.

enum: "orders" · "balance" · "positions" · "botStatus"

exchange string

Optional filter — narrows delivery to one exchange. Supported on orders, balance, and positions; NOT supported on botStatus (the subscription is ACKed but never delivers).

symbol string

Optional filter — narrows delivery to one symbol. Supported ONLY on orders and ONLY together with exchange. On other channels (or without exchange) the subscription is ACKed but never delivers.

Server → Client

Messages the SERVER sends to the client.

challenge Challenge (server → client)

One-time, connection-bound challenge sent on connect. Include it in the signed auth message.

Payload

op object required
data object required
challenge string required

Hex string to include in the signed auth payload.

ts integer required

Server timestamp, Unix milliseconds.

auth Auth result (server → client)

Successful authentication. Errors are delivered as an error message instead.

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

data object required
authenticated object required
userId string required

The account id the key belongs to.

ts integer required

Server timestamp, Unix milliseconds.

pong Pong (server → client)

Reply to an application-level ping.

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

ts integer required

Server timestamp, Unix milliseconds.

subscribed Subscribe ack (server → client)

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

channel string required

Private channel name.

enum: "orders" · "balance" · "positions" · "botStatus"

ts integer required

Server timestamp, Unix milliseconds.

unsubscribed Unsubscribe ack (server → client)

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

channel string

Private channel name.

enum: "orders" · "balance" · "positions" · "botStatus"

ts integer required

Server timestamp, Unix milliseconds.

update.orders Order update (server → client)

Emitted on the orders channel.

Payload

op object required
channel object required
data object required
event string required

enum: "ORDER_CREATE" · "ORDER_UPDATE"

order object required

Trading order returned by the Public API. Contains the fields selected by orderToPublicData from the internal IOrder model. Covers spot, margin, and futures markets.

id string required

LEXX order identifier — the platform-generated client order id (the exchange's native numeric order id is never exposed). Format is exchange-specific: x-MTB46TF3-{uid} (binance-spot), x-MZ8FjHFm-{uid} (binance-futures), lexxO{uid} (OKX — no dashes), lexx-{uid} (Bybit). Bot orders append the run id as a final segment (e.g. x-MZ8FjHFm-{uid}_{runId}). The id is stable for the lifetime of an order, but a modify/split creates NEW orders with new ids.

exchange string required

Exchange account identifier (e.g., binance-spot, binance-futures, bybit-spot, bybit-futures, okx-swap).

symbol string required

Trading pair symbol (e.g., BTCUSDT, SOLUSDT).

side string required

Order direction: BUY to go long/close short, SELL to go short/close long.

enum: "BUY" · "SELL"

type string required

Order type (from the internal OrderType enum). MARKET = immediate execution at best price. LIMIT = execute at specified price or better. LIMIT_MAKER = post-only limit (rejected if it would take liquidity). STOP_MARKET = market order triggered at stopPrice. STOP_LIMIT = limit order triggered at stopPrice. TAKE_PROFIT_MARKET = market order at take-profit level. TAKE_PROFIT_LIMIT = limit order at take-profit level. Note: trailing stops are represented as STOP_MARKET plus a populated trailing object, not a distinct order type.

enum: "MARKET" · "LIMIT" · "LIMIT_MAKER" · "STOP_MARKET" · "STOP_LIMIT" · "TAKE_PROFIT_MARKET" · "TAKE_PROFIT_LIMIT"

status string required

Order lifecycle state. NEW = accepted but not yet live on exchange. OPENED = active on exchange. CLOSED = fully filled. CANCELLED = cancelled. ERROR = rejected.

enum: "NEW" · "OPENED" · "CLOSED" · "CANCELLED" · "ERROR"

positionSide string

Position direction for hedge-mode futures. BOTH = one-way mode.

enum: "LONG" · "SHORT" · "BOTH"

price string

Limit price. String-encoded decimal.

stopPrice string | null

Trigger price for stop/take-profit orders.

fillPrice string | null

Volume-weighted average fill price. Null if no fills yet.

origQty string

Originally requested quantity in base asset.

executedQty string

Quantity already filled.

reduceOnly boolean

If true, order can only reduce an existing position.

closePosition boolean

If true, closes the entire position.

trailing object | null

Trailing stop parameters. Present (populated) when the order is a trailing stop; the type field remains STOP_MARKET in that case.

delta number

Callback rate in basis points (100 = 1%).

time number

Activation timestamp (Unix ms).

isContract boolean

True for futures/perpetual contracts, false for spot.

creatorId string

Identifier of the entity that created this order (bot ID, user short ID).

creator string

Source that created this order.

enum: "API" · "UI" · "BOT"

isWorking boolean

True if the order is currently active on the exchange order book.

metadata string

JSON-encoded metadata string. Contains allocation info for bot orders, creation timestamps, etc. Parse with JSON.parse().

specific object

Exchange-specific fields (e.g., goodTillDate). Structure varies by exchange.

orderTime integer required

Timestamp when the order was submitted, in Unix milliseconds.

ts integer required

Server timestamp, Unix milliseconds.

update.balance Balance update (server → client)

Emitted on the balance channel.

Payload

op object required
channel object required
data object required
event object required
exchange string required
marketType string
changes object required

Changed balance entries keyed by ASSET ticker, plus an optional total wallet summary. Each asset entry is {free, wallet, locked, lockedByBot?, usd?} — all string-encoded decimals. total additionally carries ts (Unix ms) and, on futures, mmr, imr, upnl, crossUpnl, crossWallet. Spot and futures share the same shape — distinguish them by marketType on the envelope.

total object

Aggregated wallet summary (optional).

ts integer required

Server timestamp, Unix milliseconds.

update.positions Position update (server → client)

Emitted on the positions channel. changes is a batch of positions that changed, keyed by symbol.

Payload

op object required
channel object required
data object required
event object required
exchange string required
changes object required

Changed positions keyed by symbol. Each value is a PARTIAL position object — only the fields that changed are present. Fields mirror the REST PublicPosition model: symbol, quote, marketType, amount, entryPrice, unrealizedProfit, type (ISOLATED/CROSSED), leverage, side, isolatedWallet, liquidationPrice, bepPrice, mmr (string-encoded decimals) and updateTime (Unix ms number). Futures only — unlike balance, this envelope has no marketType field.

ts integer required

Server timestamp, Unix milliseconds.

update.botStatus Bot status update (server → client)

Emitted on the botStatus channel.

Payload

op object required
channel object required
data object required
event string required

enum: "BOT_STARTED" · "BOT_STOPPED" · "BOT_ERROR" · "BOT_UPDATE"

bot object required

Sanitized bot record — the internal bot entry with internal-only fields removed (userId, apiKeyId, keyId, apiKey, secret, credentials, workerId, worker, internalConfig, _id, __v are never present; same deny-list as the REST PublicBot). It is an OPEN object: beyond the fields below it may carry additional lifecycle fields (e.g. runId). Inlined here because PublicBot uses an OpenAPI-style discriminated union that is not valid in the AsyncAPI schema context.

id string
type string

enum: "FIBO" · "CHANNEL" · "SQUEEZE" · "INTRADAY" · "ALGO" · "ALARM" · "NOTIFY"

status string
exchange string
symbol string
ts integer required

Server timestamp, Unix milliseconds.

error Error (server → client)

Any protocol/auth/subscription error. Some errors are followed by a socket close (see close codes).

Payload

op object required
id string

Optional client-chosen correlation id; echoed back on the matching reply.

data object required
code string required

Machine-readable error code.

enum: "AUTH_REQUIRED" · "AUTH_TIMEOUT" · "AUTH_IN_PROGRESS" · "CHALLENGE_MISSING" · "TIMESTAMP_INVALID" · "TIMESTAMP_EXPIRED" · "INVALID_ARGS" · "INVALID_KEY" · "INVALID_SIGNATURE" · "UNAUTHORIZED" · "IP_REJECTED" · "INSUFFICIENT_PERMISSIONS" · "TOO_MANY_ATTEMPTS" · "KEY_REVOKED" · "RATE_LIMITED" · "INVALID_JSON" · "INTERNAL_ERROR"

message string required
ts integer required

Server timestamp, Unix milliseconds.

Cookie Preferences

Manage your cookie preferences below. Necessary cookies are always active as they are essential for the website to function properly.

Strictly Necessary

Essential for the website to function. These cookies cannot be disabled.

Analytics

Help us understand how visitors interact with our website by collecting and reporting information anonymously.

Marketing

Used to track visitors across websites to display relevant advertisements.

Preferences

Allow the website to remember choices you make, such as language or region.