Skip to main content

Rate Limits

Rate limits are enforced per API key using sliding-window counters with both per-second (RPS) and per-minute (RPM) buckets.

Tiers

The free tier allows short bursts (up to 2 requests in any one second) but is also capped at 120 requests in any rolling one-minute window, so the per-minute bucket is the one you’ll hit first under sustained load. Use POST /v1/prices/batch and the WebSocket feeds (which don’t count against the REST limit) to stay well inside it.
The authoritative source for tier limits is GET /v1/keys/tiers. If a doc page ever disagrees with that endpoint, the endpoint wins.

Rate Limit Response

When you exceed your limit, the API returns HTTP 429 with the Polymarket-shape single-field error envelope and a stable X-Polysim-Code response header:
Branch on X-Polysim-Code === "RATE_LIMIT_EXCEEDED" rather than the body prose, and read the Retry-After header for the exact wait time in seconds.

Rate Limit Headers (on every response)

Every authenticated response carries x-ratelimit-* headers so bots can pre-throttle instead of waiting for an actual 429:
Every header above is also emitted under the PolySim-namespaced x-polysim-ratelimit-* prefix with identical values (e.g. x-polysim-ratelimit-remaining). Read whichever your SDK or proxy keys off — the unprefixed x-ratelimit-* form is canonical.

Handling Rate Limits

When the limiter does fire, exponential backoff keyed off Retry-After:

Best Practices

Use Batch Endpoints

POST /v1/orders/batch and POST /v1/prices/batch combine multiple operations into one request — and a batch call counts as one tick against your RPS/RPM. It’s bounded by your tier’s Max Batch Size (see the Tiers table above): free=1 means no batching benefit on free, so this pays off most on pro (5) / pro_plus (10) / enterprise (25).

Use WebSocket Feeds

Subscribe to WS /v1/ws/prices instead of polling GET /v1/markets. WebSocket connections don’t count against your REST rate limit.

Cache Market Metadata

Market metadata (slug, question, outcomes) changes infrequently. Cache it locally and only refresh periodically.

Idempotency Keys

On order placement (POST /v1/orders, POST /v1/order, POST /v1/clob/order), send an Idempotency-Key header — a Stripe-style alias for the body’s client_order_id — so a retried request can’t double-fill. Reusing a key with a different payload returns 409 IDEMPOTENCY_KEY_REUSE; reuse it only for the exact same order you’re retrying.

Next Steps