> ## Documentation Index
> Fetch the complete documentation index at: https://docs.struct.to/llms.txt
> Use this file to discover all available pages before exploring further.

# Rooms WS

> Stream rooms in real time with the StructWebSocket client.

`StructWebSocket` is a typed wrapper around the rooms websocket (`wss://api.struct.to/ws`). It handles connection, keepalive, reconnect, and replay of subscriptions automatically. Every room has a typed filter and a typed subscribe response.

## Connect

```typescript theme={null}
import { StructWebSocket } from "@structbuild/sdk";

const ws = new StructWebSocket({ apiKey: "sk_live_xxx" });
await ws.connect();
```

`connect()` resolves once the socket reaches the `connected` state. A socket can safely be kept open for the lifetime of your app; it will auto-reconnect on transient failures.

## Subscribe

```typescript theme={null}
await ws.subscribe("polymarket_trades", {
  condition_ids: ["0xabc..."],
});

await ws.subscribe("polymarket_order_book", {
  condition_ids: ["0xabc..."],
});

await ws.subscribe("polymarket_market_metrics", {
  condition_ids: ["0xabc..."],
});

await ws.subscribe("polymarket_trader_pnl", {
  traders: ["0x1234567890abcdef1234567890abcdef12345678"],
});
```

`subscribe(room, filters?)` returns a promise that resolves with the server's subscribe response (rejected filters, current configuration, and so on). Filters are fully typed per room.

Some rooms have optional filters. For those, you can omit the second argument to subscribe without any filter:

```typescript theme={null}
await ws.subscribe("polymarket_asset_prices");
await ws.subscribe("polymarket_clob_rewards", { subscribe_all: true });

await ws.subscribe("polymarket_markets_stream", {
  interval_ms: 1000,
  mode: "filter",
  filter: { categories: ["crypto"], min_volume: 50000 },
});

await ws.subscribe("polymarket_events_stream", {
  interval_ms: 500,
  mode: "ids",
  event_slugs: ["us-election-2028"],
});
```

Calling `subscribe` a second time on the same room replaces the previous filters.

## Listen for events

Register handlers with `on(event, listener)`. Listeners receive fully typed payloads. `on` returns a disposer function that removes the listener.

```typescript theme={null}
const disposeTrades = ws.on("trade_stream_update", (event) => {
  event.condition_id;
  event.price;
  event.size;
  event.side;
});

ws.on("order_book_update", (event) => {
  event.asset_id;
  event.bids;
  event.asks;
});

ws.on("clob_rewards_update", (event) => {
  event.event_type;
  event.condition_id;
  event.reward;
});

ws.on("trader_global_pnl_batch", (event) => {
  event.block;
  event.timeframe;
  event.data;
});

disposeTrades();
```

You can also use `once` for one-shot listeners, `off` to remove a specific listener, and `removeAllListeners` to clear handlers for a given event (or all events).

## Unsubscribe and disconnect

```typescript theme={null}
ws.unsubscribe("polymarket_trades");
ws.disconnect();
```

`unsubscribe` leaves the room and drops its replay entry so it will not be resubscribed on reconnect. `disconnect` tears down the socket, cancels timers, and clears all state.

## Available rooms

| Room                              | Filters                                                                                                                     | Event                                                                                                                                                                                                                                                                           |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `polymarket_trades`               | `condition_ids?`, `market_slugs?`, `event_slugs?`, `position_ids?`, `traders?`, `trade_types?`, `status?`, `subscribe_all?` | `trade_stream_update`                                                                                                                                                                                                                                                           |
| `polymarket_oracle_events`        | `condition_ids?`, `market_slugs?`, `event_slugs?`, `oracle_event_types?`, `status?`, `subscribe_all?`                       | `oracle_event_update`                                                                                                                                                                                                                                                           |
| `polymarket_asset_prices`         | `asset_symbols?`                                                                                                            | `asset_price_tick`, `asset_price_window_update`                                                                                                                                                                                                                                 |
| `polymarket_asset_window_updates` | `asset_symbols?`, `timeframes?`                                                                                             | `asset_window_update`                                                                                                                                                                                                                                                           |
| `polymarket_market_metrics`       | `condition_ids`                                                                                                             | `market_metrics_update`                                                                                                                                                                                                                                                         |
| `polymarket_event_metrics`        | `event_slugs`                                                                                                               | `event_metrics_update`                                                                                                                                                                                                                                                          |
| `polymarket_position_metrics`     | `position_ids`                                                                                                              | `position_metrics_update`                                                                                                                                                                                                                                                       |
| `polymarket_tag_metrics`          | `tags`                                                                                                                      | `tag_metrics_update`                                                                                                                                                                                                                                                            |
| `polymarket_trader_pnl`           | `traders`, `update_types?`, `timeframes?`, `dirty_kinds?`                                                                   | `trader_global_pnl_batch`, `trader_market_pnl_batch`, `trader_category_pnl_batch`, `trader_global_tick_batch`, `trader_market_tick_batch`, `trader_category_tick_batch`, `trader_global_resolution_batch`, `trader_market_resolution_batch`, `trader_category_resolution_batch` |
| `polymarket_trader_positions`     | `traders`, `dirty_kinds?`                                                                                                   | `trader_position_batch`, `trader_position_price_batch`, `trader_position_resolution_batch`                                                                                                                                                                                      |
| `polymarket_trader_pnl_exits`     | `traders`, `reasons?`                                                                                                       | `trader_exit_marker_batch`                                                                                                                                                                                                                                                      |
| `polymarket_holder_metrics`       | `position_ids?`, `condition_ids?`, `event_slugs?`                                                                           | `holder_metrics_position_batch`, `holder_metrics_condition_batch`, `holder_metrics_event_batch`                                                                                                                                                                                 |
| `polymarket_accounts`             | `wallets`, `include_usdce?`, `include_pusd?`, `include_matic?`                                                              | `accounts_update`, `usdce_update`, `pusd_update`, `matic_update`                                                                                                                                                                                                                |
| `polymarket_order_book`           | `condition_ids?`, `position_ids?`                                                                                           | `order_book_update`                                                                                                                                                                                                                                                             |
| `polymarket_clob_rewards`         | `condition_ids?`, `subscribe_all?`                                                                                          | `clob_rewards_update`                                                                                                                                                                                                                                                           |
| `polymarket_events_stream`        | `interval_ms?`, `mode?`, `filter?`, `event_slugs?`, `event_ids?`                                                            | `events_stream_update`                                                                                                                                                                                                                                                          |
| `polymarket_markets_stream`       | `interval_ms?`, `mode?`, `filter?`, `condition_ids?`, `market_slugs?`, `event_slugs?`                                       | `markets_stream_update`                                                                                                                                                                                                                                                         |
| `polymarket_position_liquidity`   | `position_ids?`                                                                                                             | `position_liquidity_update`                                                                                                                                                                                                                                                     |
| `polymarket_market_liquidity`     | `condition_ids?`                                                                                                            | `market_liquidity_update`                                                                                                                                                                                                                                                       |
| `polymarket_event_liquidity`      | `event_slugs?`                                                                                                              | `event_liquidity_update`                                                                                                                                                                                                                                                        |

See the [WebSockets tab](/websockets/getting-started) for full payload schemas for each room.

## Lifecycle events

| Event              | Payload            | When it fires                                                             |
| ------------------ | ------------------ | ------------------------------------------------------------------------- |
| `connected`        | `void`             | Socket reaches the connected state (initial connect and every reconnect). |
| `disconnected`     | `{ code, reason }` | Connection closed, cleanly or otherwise.                                  |
| `reconnecting`     | `{ attempt }`      | Auto-reconnect attempt starting.                                          |
| `reconnect_failed` | `Error`            | All reconnect attempts exhausted.                                         |
| `auth_failed`      | `Error`            | Server rejected the credentials. No further reconnects are attempted.     |
| `error`            | `Error`            | Socket or listener error.                                                 |
| `warning`          | `Error`            | Non-fatal warning from the transport.                                     |

```typescript theme={null}
ws.on("connected", () => console.log("live"));
ws.on("disconnected", ({ code, reason }) => console.log("gone", code, reason));
ws.on("reconnecting", ({ attempt }) => console.log("retry", attempt));
ws.on("auth_failed", (err) => console.error(err));
```

## Reconnection and replay

When the socket drops, the SDK:

1. Emits `disconnected`.
2. Enters `reconnecting` state with exponential backoff and jitter.
3. On each attempt, rebuilds the URL via `getJwt` (if configured) so the latest JWT is used.
4. On successful reconnect, replays every active subscription so your handlers keep firing without manual bookkeeping.

Configure behaviour via `reconnect`:

```typescript theme={null}
const ws = new StructWebSocket({
  apiKey: "sk_live_xxx",
  reconnect: {
    maxRetries: 10,
    initialDelayMs: 500,
    maxDelayMs: 30_000,
  },
  subscribeTimeout: 10_000,
});
```

| Option                     | Default    | Description                                                   |
| -------------------------- | ---------- | ------------------------------------------------------------- |
| `reconnect.maxRetries`     | `Infinity` | Reconnect attempts before emitting `reconnect_failed`.        |
| `reconnect.initialDelayMs` | `1000`     | Base delay between attempts.                                  |
| `reconnect.maxDelayMs`     | `30_000`   | Upper bound for the backoff delay.                            |
| `subscribeTimeout`         | `10_000`   | Milliseconds to wait for each subscribe ack before rejecting. |

## Keepalive

The transport sends a `ping` every 30 seconds and closes the socket if no `pong` arrives within 60. This is automatic; you do not need to call it.

## Connection state

```typescript theme={null}
ws.state;
```

Possible values: `"disconnected"`, `"connecting"`, `"connected"`, `"reconnecting"`.
