Skip to main content
The Polymarket US API enforces rate limits to ensure fair usage and system stability. All limits are per participant firm unless stated otherwise.

REST API

Trading Endpoints

Order management operations (CreateOrder, CancelOrder, etc.) are rate-limited at 250 requests per second per firm, averaged over a 1-minute window. This means short bursts above 250 req/sec are permitted as long as the average stays within budget.

Query / Report Endpoints

Read-heavy endpoints have lower per-firm limits. Cache responses where noted.
EndpointLimitNotes
GetTradeStats60 req/minHeavy aggregation query
ListInstruments6 req/minStatic data — cache client-side
ListSymbols6 req/minStatic data — cache client-side
GetOrderBook12 req/minPrefer streaming for real-time data
GetBBO12 req/minPrefer streaming for real-time data
SearchOrders12 req/minUse filters to narrow results
SearchExecutions12 req/minUse filters to narrow results
SearchTrades12 req/minUse filters to narrow results
ListPositionValuations~0.5 req/minMark-to-market calculation; call sparingly

Public (Unauthenticated) Endpoints

LimitValue
Max requests per second20 per IP

gRPC Streaming

SettingValue
Max concurrent streams per firm20
Ingress message rate (per firm, across all streams)250 msg/sec
Egress (server to client)Unlimited
Ingress rate is averaged over a 1-minute window, allowing short bursts. Exceeding the average limit will result in throttled or rejected messages.

FIX Protocol

SettingValue
Ingress message rate300 msg/sec per session
FIX rate limiting is enforced at the FIX gateway level.

Summary

ProtocolScopeLimit
REST — trading (orders)Per firm250 req/sec (1-min avg)
REST — query endpointsPer firm, per endpoint0.5–60 req/min (see table above)
REST — public/unauthPer IP20 req/sec
gRPC streaming (ingress)Per firm (all streams)250 msg/sec (1-min avg)
gRPC streaming (egress)Per firmUnlimited
FIXPer session300 msg/sec

Rate Limit Response

When rate limited, the REST API returns:
{
  "code": 8,
  "message": "rate limit exceeded",
  "details": []
}
HTTP Status: 429 Too Many Requests

Retry Strategy

When receiving a 429 response:
  1. Stop making requests immediately
  2. Wait 1 second before retrying
  3. Implement exponential backoff for repeated 429s
  4. Consider reducing your request rate
import time

def make_request_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 429:
            wait_time = 2 ** attempt  # 1, 2, 4 seconds
            print(f"Rate limited. Waiting {wait_time}s...")
            time.sleep(wait_time)
            continue

        return response

    raise Exception("Max retries exceeded")

Best Practices

Use Streaming Instead of Polling

The API is designed as a streaming-first system. Instead of repeatedly polling for updates, subscribe to real-time streams:
Don’t PollUse Streaming Instead
Repeated calls to /v1/report/orders/searchCreateOrderSubscription gRPC stream
Repeated calls to /v1/positionsCreatePositionSubscription gRPC stream
Repeated calls to /v1/orderbookCreateMarketDataSubscription gRPC stream
Streaming connections don’t count against the REST rate limit. One streaming connection can replace hundreds of polling requests.

Cache Reference Data

Reference data (instruments, symbols, metadata) changes infrequently — ListInstruments and ListSymbols are limited to just 6 req/min. Cache responses locally:
class InstrumentCache:
    def __init__(self):
        self.instruments = {}
        self.last_refresh = None

    def get_instrument(self, symbol):
        # Refresh cache every 5 minutes
        if self._needs_refresh():
            self._refresh_instruments()
        return self.instruments.get(symbol)

    def _needs_refresh(self):
        if not self.last_refresh:
            return True
        return (time.time() - self.last_refresh) > 300

    def _refresh_instruments(self):
        response = api.list_instruments()
        for inst in response.instruments:
            self.instruments[inst.symbol] = inst
        self.last_refresh = time.time()

Batch Operations

Where possible, batch your operations instead of making individual requests:
  • Use SearchOrders with filters instead of fetching orders one by one
  • Use ListInstruments with symbol filters instead of individual lookups
  • Subscribe to multiple symbols in a single streaming connection

Design Around ListPositionValuations

ListPositionValuations is the most restrictive endpoint at ~0.5 req/min. It performs mark-to-market calculations across all positions and is intended for periodic reporting (e.g., end-of-day P&L), not real-time monitoring.

Monitoring Your Usage

Track your request patterns to stay within limits:
import time
from collections import deque

class RateLimiter:
    def __init__(self, max_requests=250, window_seconds=1):
        self.max_requests = max_requests
        self.window = window_seconds
        self.requests = deque()

    def can_make_request(self):
        now = time.time()
        # Remove old requests outside the window
        while self.requests and self.requests[0] < now - self.window:
            self.requests.popleft()
        return len(self.requests) < self.max_requests

    def record_request(self):
        self.requests.append(time.time())

    def wait_if_needed(self):
        while not self.can_make_request():
            time.sleep(0.05)  # 50ms
        self.record_request()

Abuse Prevention

Patterns that may result in temporary or permanent restrictions:
  • Sustained requests above the rate limit
  • Polling for data available via streaming
  • Requesting the same unchanged data repeatedly
  • Automated retry loops without backoff
Abuse of the API may result in temporary or permanent restrictions on your API credentials. Contact onboarding@qcex.com if you need higher limits for legitimate use cases.

Troubleshooting Rate Limits

Consistently Hitting Limits

If you’re consistently receiving 429 errors:
  • Reduce request frequency
  • Batch multiple operations where possible
  • Cache responses that don’t change frequently (reference data, instrument lists)
  • Use streaming endpoints instead of polling
  • Contact support to discuss higher rate limits for production use

Need Higher Limits

For production use cases requiring higher limits:
  1. Document your use case and expected volume
  2. Contact support at onboarding@qcex.com
  3. Provide environment (dev, preprod, prod)
  4. Specify which endpoints you need higher limits for

Next Steps