Skip to main content

WebSocket Endpoints

EndpointPurposeData Types
/v1/ws/marketsPublic market dataOrder books, prices, trades
/v1/ws/privatePrivate account dataOrders, positions, balances
Authentication: API key signature in handshake headers

Market Data WebSocket

Real-time public market data streaming. WebSocket URL:
wss://api.polymarket.us/v1/ws/markets
Headers:
X-PM-Access-Key: {api_key_id}
X-PM-Timestamp: {unix_timestamp_ms}
X-PM-Signature: {ed25519_signature}

Market Data Subscription Types

Full Order Book

SUBSCRIPTION_TYPE_MARKET_DATA - Complete order book with all price levels. Subscribe:
{
  "type": "subscribe",
  "subscription_type": "SUBSCRIPTION_TYPE_MARKET_DATA",
  "instrument_ids": ["inst_abc123", "inst_def456"]
}
Message:
{
  "type": "market_data",
  "instrument_id": "inst_abc123",
  "timestamp": "2026-01-13T10:00:00Z",
  "bids": [
    {"price": 0.62, "quantity": 500},
    {"price": 0.61, "quantity": 750},
    {"price": 0.60, "quantity": 1000}
  ],
  "asks": [
    {"price": 0.63, "quantity": 450},
    {"price": 0.64, "quantity": 800},
    {"price": 0.65, "quantity": 1200}
  ]
}

Price Summary (Lite)

SUBSCRIPTION_TYPE_MARKET_DATA_LITE - Best bid/ask and last price only. Subscribe:
{
  "type": "subscribe",
  "subscription_type": "SUBSCRIPTION_TYPE_MARKET_DATA_LITE",
  "instrument_ids": ["inst_abc123"]
}
Message:
{
  "type": "market_data_lite",
  "instrument_id": "inst_abc123",
  "timestamp": "2026-01-13T10:00:00Z",
  "bid": 0.62,
  "ask": 0.63,
  "last_price": 0.625,
  "volume_24h": 125000.00
}

Trade Feed

SUBSCRIPTION_TYPE_TRADE - Individual trade executions. Subscribe:
{
  "type": "subscribe",
  "subscription_type": "SUBSCRIPTION_TYPE_TRADE",
  "instrument_ids": ["inst_abc123"]
}
Message:
{
  "type": "trade",
  "instrument_id": "inst_abc123",
  "timestamp": "2026-01-13T10:00:00Z",
  "price": 0.625,
  "quantity": 50,
  "side": "buy"
}

Market Data Limits

LimitValue
Max connections1 per API key
Max subscriptions10 instruments
Reconnect cooldown5 seconds

Private Data WebSocket

Real-time private account data streaming. WebSocket URL:
wss://api.polymarket.us/v1/ws/private
Headers:
X-PM-Access-Key: {api_key_id}
X-PM-Timestamp: {unix_timestamp_ms}
X-PM-Signature: {ed25519_signature}

Private Data Subscription Types

Order Updates

SUBSCRIPTION_TYPE_ORDER - Real-time order status changes (drop copy). Subscribe:
{
  "type": "subscribe",
  "subscription_type": "SUBSCRIPTION_TYPE_ORDER"
}
Message:
{
  "type": "order_update",
  "order_id": "ord_xyz789",
  "instrument_id": "inst_abc123",
  "status": "filled",
  "filled_quantity": 100,
  "average_price": 0.625,
  "timestamp": "2026-01-13T10:00:00Z"
}

Working Orders Snapshot

SUBSCRIPTION_TYPE_ORDER_SNAPSHOT - Snapshot of all open orders. Subscribe:
{
  "type": "subscribe",
  "subscription_type": "SUBSCRIPTION_TYPE_ORDER_SNAPSHOT"
}
Message:
{
  "type": "order_snapshot",
  "orders": [
    {
      "order_id": "ord_xyz789",
      "instrument_id": "inst_abc123",
      "side": "buy",
      "type": "limit",
      "quantity": 100,
      "price": 0.55,
      "status": "open"
    }
  ],
  "timestamp": "2026-01-13T10:00:00Z"
}

Position Changes

SUBSCRIPTION_TYPE_POSITION - Real-time position updates. Subscribe:
{
  "type": "subscribe",
  "subscription_type": "SUBSCRIPTION_TYPE_POSITION"
}
Message:
{
  "type": "position_update",
  "instrument_id": "inst_abc123",
  "quantity": 150,
  "entry_price": 0.55,
  "unrealized_pnl": 10.50,
  "timestamp": "2026-01-13T10:00:00Z"
}

Account Balance

SUBSCRIPTION_TYPE_ACCOUNT_BALANCE - Real-time balance changes. Subscribe:
{
  "type": "subscribe",
  "subscription_type": "SUBSCRIPTION_TYPE_ACCOUNT_BALANCE"
}
Message:
{
  "type": "balance_update",
  "total_balance": 1000.00,
  "available_balance": 750.00,
  "reserved_balance": 250.00,
  "timestamp": "2026-01-13T10:00:00Z"
}

Private Data Limits

LimitValue
Max connections1 per API key
Reconnect cooldown5 seconds

Python Connection Example

Market Data Connection

import websocket
import json
import time

def on_message(ws, message):
    data = json.loads(message)
    print(f"Received: {data}")

def on_open(ws):
    # Subscribe to market data
    ws.send(json.dumps({
        "type": "subscribe",
        "subscription_type": "SUBSCRIPTION_TYPE_MARKET_DATA",
        "instrument_ids": ["inst_abc123"]
    }))

ws = websocket.WebSocketApp(
    "wss://api.polymarket.us/v1/ws/markets",
    header={
        "X-PM-Access-Key": api_key_id,
        "X-PM-Signature": signature,
        "X-PM-Timestamp": str(int(time.time() * 1000))
    },
    on_message=on_message,
    on_open=on_open
)

ws.run_forever()

Private Data Connection

import websocket
import json
import time

def on_message(ws, message):
    data = json.loads(message)
    print(f"Received: {data}")

def on_open(ws):
    # Subscribe to order updates
    ws.send(json.dumps({
        "type": "subscribe",
        "subscription_type": "SUBSCRIPTION_TYPE_ORDER"
    }))

ws = websocket.WebSocketApp(
    "wss://api.polymarket.us/v1/ws/private",
    header={
        "X-PM-Access-Key": api_key_id,
        "X-PM-Signature": signature,
        "X-PM-Timestamp": str(int(time.time() * 1000))
    },
    on_message=on_message,
    on_open=on_open
)

ws.run_forever()

Managing Subscriptions

Subscribe to Additional Instruments (Market Data)

{
  "type": "subscribe",
  "subscription_type": "SUBSCRIPTION_TYPE_MARKET_DATA",
  "instrument_ids": ["inst_ghi789"]
}

Unsubscribe from Instruments

{
  "type": "unsubscribe",
  "instrument_ids": ["inst_abc123"]
}

Unsubscribe from All

{
  "type": "unsubscribe_all"
}

Heartbeats

The server sends periodic heartbeat messages to keep the connection alive:
{
  "type": "heartbeat",
  "timestamp": "2026-01-13T10:00:00Z"
}
Respond to heartbeats with a pong message to maintain the connection:
{"type": "pong"}

Error Messages

{
  "type": "error",
  "code": "MAX_SUBSCRIPTIONS_EXCEEDED",
  "message": "Cannot subscribe to more than 10 instruments"
}

Common Error Codes

CodeDescription
MAX_SUBSCRIPTIONS_EXCEEDEDTrying to subscribe to more than 10 instruments (market data only)
INVALID_INSTRUMENTInstrument ID does not exist
AUTHENTICATION_FAILEDInvalid API key or signature
RATE_LIMIT_EXCEEDEDReconnecting too quickly (5 second cooldown)
DUPLICATE_CONNECTIONAnother connection with same API key exists for this endpoint

Reconnection Strategy

import time
import websocket

def connect_with_retry(url, headers, max_retries=5):
    retries = 0
    while retries < max_retries:
        try:
            ws = websocket.WebSocketApp(url, header=headers)
            ws.run_forever()
        except Exception as e:
            retries += 1
            wait_time = min(5 * (2 ** retries), 60)  # Exponential backoff
            print(f"Connection failed, retrying in {wait_time}s...")
            time.sleep(wait_time)

Best Practices

  • Use two separate connections - One for market data, one for private data
  • Handle reconnections gracefully - Implement exponential backoff
  • Respect the 5-second cooldown - Don’t reconnect immediately after disconnect
  • Limit market subscriptions to 10 - Prioritize your most important instruments
  • Process messages quickly - Don’t block the message handler
  • Monitor heartbeats - Reconnect if you stop receiving them
  • Store subscription state - Re-subscribe after reconnection
Current limitations:
  • 1 connection per API key per endpoint - You can have one connection to /v1/ws/markets and one to /v1/ws/private simultaneously
  • 10 instrument maximum on market data - Subscribe to your most actively traded instruments
These features will soon be available via the Retail API:
  • Multiple connections per API key per endpoint
  • More than 10 simultaneous market data subscriptions