Skip to main content

WebSocketClient Setup

The WebSocketClient connects to the Limitless Exchange WebSocket server for real-time market data, position updates, order lifecycle events, and transaction notifications.
import { WebSocketClient } from '@limitless-exchange/sdk';

const ws = new WebSocketClient({
  url: 'wss://ws.limitless.exchange',
  autoReconnect: true,
});

ws.connect();

Constructor Options

OptionTypeDefaultDescription
urlstringWebSocket server URL
autoReconnectbooleantrueAutomatically reconnect on disconnection
hmacCredentials{ tokenId, secret }Required for authenticated subscriptions (positions, order events, transactions). The SDK signs the handshake automatically.
Public subscriptions (market prices) do not require authentication. Authenticated subscriptions (positions, order events, transactions) require hmacCredentials — see Authentication to generate a token.

Public Subscriptions

Market Prices

Subscribe to real-time price updates for one or more markets. No authentication required.
const ws = new WebSocketClient({
  url: 'wss://ws.limitless.exchange',
});

ws.connect();

ws.subscribe('subscribe_market_prices', {
  marketSlugs: ['btc-100k-weekly', 'eth-5k-daily'],
  marketAddresses: ['0x1234...'], // For AMM markets
});
Subscriptions replace previous ones. To listen to both CLOB (by slug) and AMM (by address) markets, include both marketSlugs and marketAddresses in a single subscribe_market_prices call.

Authenticated Subscriptions

These subscriptions require hmacCredentials passed to the constructor. The SDK signs the WebSocket handshake automatically.
const ws = new WebSocketClient({
  url: 'wss://ws.limitless.exchange',
  hmacCredentials: {
    tokenId: process.env.LMTS_TOKEN_ID,
    secret: process.env.LMTS_TOKEN_SECRET,
  },
});

ws.connect();

Positions

Subscribe to real-time updates when your positions change:
ws.subscribe('subscribe_positions');

ws.on('positions', (data) => {
  console.log('Position update:', data);
});

Order Events

Subscribe to CLOB order lifecycle and settlement events for your account:
ws.subscribe('subscribe_order_events');

ws.on('orderEvent', (event: OrderEvent) => {
  if (event.source === 'OME') {
    console.log('Order state:', event.type, event.orderId, event.clientOrderId);
  } else {
    console.log('Settlement:', event.type, event.orderId, event.clientOrderId, event.txHash);
  }
});
orderEvent uses source as a discriminator:
  • source: 'OME' — off-chain order state changes: placement, update, cancellation.
  • source: 'SETTLEMENT' — on-chain settlement results for the taker order and each matched maker order.
For settlement events, clientOrderId is the id of the recipient’s own orderId. If only one side of a trade supplied a clientOrderId, only that side’s event includes it. Counterparty order ids inside takerOrderId or makerMatches[] are not resolved to client ids.

Transactions

Subscribe to transaction confirmations:
ws.subscribe('subscribe_transactions');

ws.on('tx', (data) => {
  console.log('Transaction:', data.hash, data.status);
});

Events

orderbookUpdate (CLOB markets)

Fired when a CLOB market orderbook changes. Contains the full updated orderbook.
ws.on('orderbookUpdate', (data: OrderbookUpdate) => {
  console.log('Market:', data.marketSlug);
  console.log('Bids:', data.orderbook.bids.length);
  console.log('Asks:', data.orderbook.asks.length);

  if (data.orderbook.bids.length > 0 && data.orderbook.asks.length > 0) {
    const spread = data.orderbook.asks[0].price - data.orderbook.bids[0].price;
    console.log('Spread:', spread.toFixed(4));
  }
});

newPriceData (AMM markets)

Fired when AMM market prices update.
ws.on('newPriceData', (data: NewPriceData) => {
  console.log('Market:', data.marketAddress);
  console.log('YES:', data.updatedPrices.yes);
  console.log('NO:', data.updatedPrices.no);
});

positions

Fired when any of your positions change (fill, cancel, resolution).
ws.on('positions', (data: PositionEvent) => {
  console.log('Updated positions:', data);
});

tx

Fired on transaction events related to your account.
ws.on('tx', (data: TransactionEvent) => {
  console.log('Tx hash:', data.hash);
  console.log('Status:', data.status);
});

Type Definitions

interface OrderbookUpdate {
  marketSlug: string;
  orderbook: {
    bids: { price: number; size: number }[];
    asks: { price: number; size: number }[];
  };
}

interface NewPriceData {
  marketAddress: string;
  updatedPrices: {
    yes: string;
    no: string;
  };
}

interface PositionEvent {
  clob: Array<{
    market: { slug: string };
    positions: {
      yes: { size: number; collateral: number };
      no: { size: number; collateral: number };
    };
  }>;
}

type OrderEvent = OmeOrderEvent | SettlementOrderEvent;

interface OmeOrderEvent {
  source: 'OME';
  type: 'PLACEMENT' | 'UPDATE' | 'CANCELLATION';
  eventId: number;
  orderId: string;
  clientOrderId?: string;
  userId: number;
  marketId: string;
  token: string;
  side: 'BUY' | 'SELL';
  price: string;
  remainingSize: string;
  timestamp: string;
}

interface SettlementOrderEvent {
  source: 'SETTLEMENT';
  type: 'MINED' | 'FAILED';
  eventId: string;
  tradeEventId: string;
  orderId?: string;
  clientOrderId?: string;
  takerOrderId?: string;
  takerAccount?: string;
  makerMatches?: Array<{
    account: string;
    orderId: string;
    matchedSize: string;
    price: string;
  }>;
  marketSlug?: string;
  tokenId?: string;
  side?: 'BUY' | 'SELL';
  price?: string;
  amountContracts?: string;
  amountCollateral?: string;
  configuredFeeRateBps?: number;
  effectiveFeeBps?: number;
  feeAmountContracts?: string;
  txHash?: string;
  timestamp: string;
}

interface TransactionEvent {
  hash: string;
  status: 'pending' | 'confirmed' | 'failed';
  type: string;
}

Connection Management

Disconnect handling

Listen for disconnections and clean up resources:
ws.on('disconnect', (reason: string) => {
  console.log('Disconnected:', reason);
});

ws.on('reconnect', () => {
  console.log('Reconnected — resubscribing...');

  ws.subscribe('subscribe_market_prices', {
    marketSlugs: ['btc-100k-weekly'],
  });
});
When autoReconnect is enabled, the client automatically attempts to reconnect. However, you must re-send your subscriptions after reconnection. Listen for the reconnect event to resubscribe.

Graceful shutdown

Clean up the WebSocket connection on process exit:
process.on('SIGINT', () => {
  console.log('Shutting down...');
  ws.disconnect();
  process.exit(0);
});

Debugging

Log all raw events to inspect the data the server sends:
ws.onAny((eventName: string, ...args: unknown[]) => {
  console.log(`[WS] ${eventName}:`, JSON.stringify(args, null, 2));
});
Use raw event logging during development to discover event shapes and debug subscription issues. Remove it before deploying to production.

Full Example

A complete script that subscribes to market prices and positions:
import { WebSocketClient } from '@limitless-exchange/sdk';

const ws = new WebSocketClient({
  url: 'wss://ws.limitless.exchange',
  hmacCredentials: {
    tokenId: process.env.LMTS_TOKEN_ID,
    secret: process.env.LMTS_TOKEN_SECRET,
  },
  autoReconnect: true,
});

ws.connect();

ws.subscribe('subscribe_market_prices', {
  marketSlugs: ['btc-100k-weekly'],
});

ws.subscribe('subscribe_positions');
ws.subscribe('subscribe_order_events');
ws.subscribe('subscribe_transactions');

ws.on('orderbookUpdate', (data) => {
  const best_bid = data.orderbook.bids[0];
  const best_ask = data.orderbook.asks[0];
  console.log(`[${data.marketSlug}] Bid: ${best_bid?.price ?? '-'} | Ask: ${best_ask?.price ?? '-'}`);
});

ws.on('positions', (data) => {
  console.log('[Positions]', JSON.stringify(data));
});

ws.on('orderEvent', (event) => {
  console.log('[OrderEvent]', event.source, event.type, event.orderId, event.clientOrderId ?? '(no client id)');
});

ws.on('tx', (data) => {
  console.log(`[Tx] ${data.hash}${data.status}`);
});

ws.on('disconnect', (reason) => {
  console.log('[Disconnected]', reason);
});

ws.on('reconnect', () => {
  ws.subscribe('subscribe_market_prices', {
    marketSlugs: ['btc-100k-weekly'],
  });
  ws.subscribe('subscribe_positions');
  ws.subscribe('subscribe_order_events');
  ws.subscribe('subscribe_transactions');
});

process.on('SIGINT', () => {
  ws.disconnect();
  process.exit(0);
});

console.log('Listening for events... (Ctrl+C to stop)');