Skip to main content
Authenticated users automatically receive order and balance notifications over the WebSocket. No subscription action needed — just authenticate and events start flowing.

Connect and Authenticate

// Authenticate on connection by passing your JWT as a query param
const ws = new WebSocket(`wss://ws.agg.market/ws?appId=${appId}&token=${accessToken}`);
You’ll receive a confirmation:
{ "type": "connected", "appId": "your-app-id", "userId": "user-123" }
You can also authenticate mid-session (e.g. after the user signs in):
ws.send(JSON.stringify({ action: "authenticate", token: accessToken }));
// Response: { "type": "authenticated", "userId": "user-123" }
Once authenticated, all your order and balance events are delivered automatically. No separate subscription action is needed.
No initial state is sent on authentication — you only receive events for actions that happen after you connect. To get current balances or holdings, use the REST endpoints (GET /trading/balance, GET /trading/holdings).

Events

Order Submitted

Sent after a trade is successfully placed:
{
  "type": "order_submitted",
  "venue": "kalshi",
  "orderId": "order-abc-123",
  "side": "buy",
  "price": 0.55,
  "size": 10,
  "marketId": "market-123",
  "timestamp": 1710705123456
}

Balance Update

Sent after orders are placed, reflecting your updated balance:
{
  "type": "balance_update",
  "venue": "kalshi",
  "tradingBalanceCents": 50000,
  "walletBalanceCents": 100000,
  "timestamp": 1710705123456
}

Handling Events

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  switch (msg.type) {
    case "order_submitted":
      addOrder({
        id: msg.orderId,
        venue: msg.venue,
        side: msg.side,
        price: msg.price,
        size: msg.size,
      });
      break;

    case "balance_update":
      updateBalance(msg.venue, {
        trading: msg.tradingBalanceCents / 100,
        wallet: msg.walletBalanceCents ? msg.walletBalanceCents / 100 : null,
      });
      break;
  }
};

Reconnection

If the connection drops, reconnect and re-authenticate. If your access token has expired, refresh it first:
function connect() {
  const ws = new WebSocket(`wss://ws.agg.market/ws?appId=${appId}&token=${accessToken}`);

  ws.onclose = async () => {
    // Refresh token if needed
    try {
      const { accessToken: newToken } = await client.refreshToken({
        refreshToken: storedRefreshToken,
      });
      accessToken = newToken;
    } catch {
      // Refresh failed — user needs to re-authenticate
      return;
    }
    setTimeout(connect, 1000);
  };

  ws.onmessage = handleMessage;
}