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
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
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:
subscribe a second time on the same room replaces the previous filters.
Listen for events
Register handlers withon(event, listener). Listeners receive fully typed payloads. on returns a disposer function that removes the listener.
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
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_trader_pnl | traders | trader_global_pnl_update, trader_market_pnl_update, trader_event_pnl_update |
polymarket_trader_positions | traders | trader_position_update |
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 |
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. |
Reconnection and replay
When the socket drops, the SDK:- Emits
disconnected. - Enters
reconnectingstate with exponential backoff and jitter. - On each attempt, rebuilds the URL via
getJwt(if configured) so the latest JWT is used. - On successful reconnect, replays every active subscription so your handlers keep firing without manual bookkeeping.
reconnect:
| 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 aping 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
"disconnected", "connecting", "connected", "reconnecting".