Files
agent-skills/websocket.md
T
Suhail Kakar 91ee44ae11 add skills
2026-02-19 21:29:35 +05:30

5.8 KiB

WebSocket

Three channels for real-time data. Market and sports channels are public; user channel requires API credentials.

Channels

Channel Endpoint Auth
Market wss://ws-subscriptions-clob.polymarket.com/ws/market No
User wss://ws-subscriptions-clob.polymarket.com/ws/user Yes
Sports wss://sports-api.polymarket.com/ws No

Market Channel

Public. Subscribes by asset IDs (token IDs).

Subscribe

{
  "assets_ids": ["TOKEN_ID_1", "TOKEN_ID_2"],
  "type": "market",
  "custom_feature_enabled": true
}

Set custom_feature_enabled: true to enable best_bid_ask, new_market, and market_resolved events.

Event Types

Event Trigger Key Fields
book On subscribe + when trade affects book bids[], asks[], hash, timestamp
price_change Order placed or cancelled price_changes[] with price, size, side, best_bid, best_ask
last_trade_price Trade executed price, side, size, fee_rate_bps
tick_size_change Price hits >0.96 or <0.04 old_tick_size, new_tick_size
best_bid_ask Top-of-book changes best_bid, best_ask, spread
new_market Market created question, assets_ids, outcomes
market_resolved Market resolved winning_asset_id, winning_outcome

Events requiring custom_feature_enabled: true: best_bid_ask, new_market, market_resolved.

tick_size_change is critical for bots — if tick size changes and you use the old one, orders are rejected.

A price_change with size: "0" means the price level was removed from the book.

Example Messages

// book
{
  "event_type": "book",
  "asset_id": "TOKEN_ID",
  "market": "0xCONDITION_ID",
  "bids": [{"price": ".48", "size": "30"}],
  "asks": [{"price": ".52", "size": "25"}],
  "timestamp": "123456789000",
  "hash": "0x..."
}
// price_change
{
  "event_type": "price_change",
  "market": "0xCONDITION_ID",
  "price_changes": [{
    "asset_id": "TOKEN_ID",
    "price": "0.5",
    "size": "200",
    "side": "BUY",
    "hash": "...",
    "best_bid": "0.5",
    "best_ask": "1"
  }],
  "timestamp": "..."
}

User Channel

Authenticated. Subscribes by condition IDs (market IDs), not asset IDs. The markets field is optional — omit it to receive events for all markets.

Subscribe

{
  "auth": {
    "apiKey": "your-api-key",
    "secret": "your-api-secret",
    "passphrase": "your-passphrase"
  },
  "markets": ["0xCONDITION_ID"],
  "type": "user"
}

Event Types

Event Trigger
trade Trade lifecycle: MATCHED, MINED, CONFIRMED, RETRYING, FAILED
order Order lifecycle: PLACEMENT, UPDATE, CANCELLATION

Trade Message

{
  "event_type": "trade",
  "id": "trade-uuid",
  "market": "0xCONDITION_ID",
  "asset_id": "TOKEN_ID",
  "side": "BUY",
  "size": "10",
  "price": "0.57",
  "status": "MATCHED",
  "maker_orders": [{ "order_id": "0x...", "matched_amount": "10", "price": "0.57" }],
  "type": "TRADE"
}

Order Message

{
  "event_type": "order",
  "id": "0xORDER_ID",
  "market": "0xCONDITION_ID",
  "asset_id": "TOKEN_ID",
  "side": "SELL",
  "price": "0.57",
  "original_size": "10",
  "size_matched": "0",
  "type": "PLACEMENT"
}

Order types: PLACEMENT, UPDATE (partial fill), CANCELLATION.

Sports Channel

No subscription message needed. Connect and receive all active sports data.

// sport_result
{ "type": "sport_result", ... }  // Live scores, periods, status

Dynamic Subscribe / Unsubscribe

Modify subscriptions without reconnecting:

// Market channel — subscribe to more
{ "assets_ids": ["NEW_TOKEN_ID"], "operation": "subscribe", "custom_feature_enabled": true }

// Market channel — unsubscribe
{ "assets_ids": ["OLD_TOKEN_ID"], "operation": "unsubscribe" }

// User channel — subscribe to more markets
{ "markets": ["0xNEW_CONDITION_ID"], "operation": "subscribe" }

Heartbeat

Market & User Channels

Send PING every 10 seconds. Server responds with PONG.

const ws = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/market");

ws.onopen = () => {
  // Subscribe...
  setInterval(() => ws.send("PING"), 10_000);
};

ws.onmessage = (event) => {
  if (event.data === "PONG") return;
  const msg = JSON.parse(event.data);
  // handle msg.event_type
};

Sports Channel

Server sends ping every 5 seconds. Respond with pong within 10 seconds or connection closes.

Full TypeScript Example

const ws = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/market");

ws.onopen = () => {
  ws.send(JSON.stringify({
    type: "market",
    assets_ids: ["TOKEN_ID"],
    custom_feature_enabled: true,
  }));
  setInterval(() => ws.send("PING"), 10_000);
};

ws.onmessage = (event) => {
  if (event.data === "PONG") return;
  const msg = JSON.parse(event.data);
  switch (msg.event_type) {
    case "book":
      console.log("Book snapshot:", msg.bids.length, "bids", msg.asks.length, "asks");
      break;
    case "price_change":
      for (const pc of msg.price_changes) {
        console.log(`${pc.side} ${pc.size}@${pc.price} (best: ${pc.best_bid}/${pc.best_ask})`);
      }
      break;
    case "last_trade_price":
      console.log(`Trade: ${msg.side} ${msg.size}@${msg.price}`);
      break;
    case "tick_size_change":
      console.log(`Tick: ${msg.old_tick_size}${msg.new_tick_size}`);
      break;
  }
};

Troubleshooting

  • Connection closes immediately: send subscription message right after open
  • Drops after ~10s: you're not sending PING heartbeats
  • No messages: verify asset IDs are correct and markets are active
  • Auth failed (user channel): check API credentials haven't expired