Key takeawaysThe 15,000 per 10 seconds is a global ceiling, not a budget: the binding number is the endpoint you call — /positions allows 150, /markets 300, /events 500.
- The 15,000 per 10 seconds is a global ceiling, not a budget: the binding number is the endpoint you call —
/positionsallows 150,/markets300,/events500. - Read-side figures use a 10-second window (so
/marketsat 300 means 30 rps sustained), but windows vary: trading also carries a 10-minute sustained cap, the relayer is per minute, and signer buckets are in tokens per second. - Host budgets are separate — Gamma 4,000, CLOB 9,000, Data API 1,000 per 10 seconds — and in our test endpoint-specific throttling stayed local: a control endpoint took zero refusals across six pairs while the loaded one took 5–35%, though the load never approached the shared and host-wide ceilings above it.
- Documentation says excess requests are queued rather than rejected; in our runs the read endpoints returned an immediate 429 with no slowdown phase,
Retry-After: 0and noX-RateLimit-*headers — so count requests yourself and monitor both latency and 429s. - Exceeding a limit yields nothing: offered loads of 35.6–43.6 rps to
/marketsproduced a flat 27.8–28.7 successful rps, 93–96% of the documented ceiling, with 21–35% of requests refused. - Trading has a second, orthogonal limiter: per-signer token buckets with separate order and cancel balances, volume tiers from Standard (40/s, burst 60) to Elite (600/s, burst 900), all-or-nothing batches, and a cancel-all that debits one token per order actually canceled — its 429s do carry a meaningful
Retry-After. - Read capacity scales with addresses — 95.3% efficiency at twenty, no per-/24 penalty, budget resets on switching — while order throughput, being signer-scoped, does not.
This summary was created with AI.
Three APIs, three separate budgets
As our guide to Polymarket’s three APIs explains, Polymarket runs three hosts, and each carries its own allowance under that global ceiling. The official rate limit documentation lists them per endpoint, and the shape is consistent: a generous host-wide number, with much tighter caps on the endpoints that cost the platform real work.
| Host | General | Tighter endpoints |
|---|---|---|
Gamma (gamma-api) |
4,000 / 10s | /events 500, /markets 300, search 350 |
CLOB (clob) |
9,000 / 10s | /book, /price, /midpoint 1,500; batch /books, /prices, /midpoints 500; /data/orders, /data/trades 500; API-key endpoints 100 |
Data (data-api) |
1,000 / 10s | /trades 200, /positions 150, /closed-positions 150 |
Gamma API rate limits are the most forgiving because metadata is cacheable and mostly static. CLOB API rate limits are the largest in absolute terms — 9,000 per 10 seconds for the host — because market data is what most integrations read constantly. Data API rate limits are the tightest of the three, and that asymmetry is the single most useful thing to internalize: the wallet-scoped endpoints are the scarce resource, so a portfolio tracker is budget-constrained long before a price feed is.
The separation works in your favor once you plan around it. Reading market metadata from Gamma does not consume the allowance your position polling needs on the Data API, so enriching a wallet's holdings with market titles is effectively free from the budget's point of view. Design pipelines so each host does the job it's cheapest at.
Why the general number misleads
The 15,000 figure is a ceiling across everything, not an allowance you can spend on any one thing. For the fields, filters, and pagination behind the tightest endpoint, see our guide to the Polymarket Data API /positions endpoint. In practice your binding constraint is whichever endpoint-level number you hit first, and the gap is dramatic: 150 per 10 seconds on /positions is 1% of the global cap.
It also helps to convert, because the rate limits per second that people assume are rarely what's published. The read-side figures use a 10-second window, so /markets at 300 per 10 seconds is 30 requests per second sustained — not 300. Windows aren't uniform across the platform, though: trading endpoints also carry a sustained cap measured over 10 minutes, the relayer's submit endpoint is expressed per minute, and the per-signer trading buckets are defined in tokens per second. Read the window along with the number, every time.
The rate limits on the markets endpoint are a good illustration of why the distinction matters: at 30 requests per second you can walk a large catalog quickly, but a naive loop firing 300 requests in the first second will collide with the window even though the "per 10 seconds" number looked comfortable.
The practical consequences fall out of the arithmetic:
- Compute your own ceiling per job. A tracker watching 500 wallets at one
/positionscall each needs 500 ÷ 150 ≈ 3.3 ten-second windows — 33 seconds per full sweep from one address, whatever the global cap says. - Batch where a batch exists.
/booksand/priceshave a lower request allowance than their single-item versions (500 versus 1,500 per 10 seconds), but each request covers many tokens, so for multi-token work they reduce the number of requests you need. How much depends on how many tokens you pack per call. - Page with cursors on Gamma.
/markets/keysetand/events/keysetreturn anext_cursorand replace the offset endpoints, which are on a deprecation path. Note the caps differ:limitmaxes at 100 on/markets/keysetand at 500 on/events/keyset.
What throttling looks like from your side
This is where Polymarket's published model differs from most venues. Limits are enforced by Cloudflare on sliding windows, and the documentation states that requests over the limit are throttled — delayed and queued — rather than immediately rejected.
What the documentation does not promise is the shape of that degradation: it doesn't say latency will always be your first symptom, nor that responses will keep returning 200 while you're over budget. Our own measurements found the opposite behavior on the read endpoints — a hard 429 at the knee with no gradual slowdown before it — and the section below covers what we saw. So instrument for both. Track the p95 of request duration per endpoint, count 429s separately, and keep a client-side counter of requests per 10-second window per host so you know your position before the platform tells you.
On the retry side, be precise about what carries a hint. The per-signer trading limiter documents a Retry-After header on its 429 responses, and there the value is meaningful — it's the minimum delay before your request becomes affordable. The general IP-based rate-limit page makes no such promise for the read endpoints, so don't build a backoff that assumes one will arrive with a useful value.
Rate limits with authentication follow the same IP-based model, with two additions worth planning for. The API-key management endpoints on the CLOB have their own tight allowance of 100 requests per 10 seconds, which is ample for deriving a key at startup and restrictive if you re-derive credentials on every worker restart. And authenticated trading carries a second limiter entirely, described next.
Burst and sustained limits on trading
Orders and cancellations are governed by per-signer token buckets that sit alongside the Cloudflare IP limits, not instead of them. Both apply. The signer address here is the address associated with your CLOB API credentials, and each signer gets two independent buckets — one for orders, one for cancellations — where spending in one does not touch the other.
Trading endpoint limits are expressed as a refill rate plus a burst capacity. Tokens accrue continuously at the tier's rate; the burst is the maximum the bucket can hold, so a full bucket can be spent at once and then refills at the steady rate. The documentation gives the arithmetic directly: burst_seconds = burst / rate_per_sec tells you how long a full burst lasts under continuous pressure.
Token costs are per unit of work rather than per request, which is the detail that catches batch users:
| Bucket | Request | Token cost |
|---|---|---|
| Order | POST /order |
1 |
| Order | POST /orders |
number of orders in the batch |
| Cancel | DELETE /order |
1 |
| Cancel | DELETE /orders |
number of submitted order IDs |
| Cancel | DELETE /cancel-all |
1 plus the number of orders actually canceled |
| Cancel | DELETE /cancel-market-orders |
1 plus the number of matching orders canceled |
Batches are all-or-nothing at the limiter: a batch is admitted only if the bucket holds enough tokens for every entry, otherwise the whole request is rejected and nothing is processed. A batch whose cost exceeds the tier's burst capacity can never be admitted — it has to be split, and retrying it unchanged will fail forever.
The cancel-all mechanics deserve special attention because they can leave you in debt. Since the number of orders to be canceled isn't known upfront, the request first spends one token, then debits one more per order successfully canceled after the fact. On tiers that allow it, that second debit can push the bucket below zero, and further cancellations stay blocked until the balance recovers.
Capacity depends on volume tiers, assigned from the maker wallet's cumulative 30-day volume — even when the maker differs from the signer — and refreshed every three hours:
| Tier | 30-day volume | Order rate/burst | Cancel rate/burst | Negative cancel balance |
|---|---|---|---|---|
| Standard | — | 40 / 60 | 80 / 120 | Yes |
| Copper | $30,000+ | 60 / 90 | 120 / 180 | Yes |
| Bronze | $50,000+ | 80 / 120 | 160 / 240 | Yes |
| Silver | $100,000+ | 200 / 300 | 400 / 600 | Yes |
| Gold | $500,000+ | 400 / 600 | 800 / 1,200 | Yes |
| Platinum | $2.5M+ | 450 / 675 | 900 / 1,350 | No |
| Diamond | $5M+ | 525 / 787 | 1,050 / 1,575 | No |
| Elite | $10M+ | 600 / 900 | 1,200 / 1,800 | No |
Polymarket notes that thresholds, the volume window and the rates themselves may change as the system is tuned, so read them from the card rather than hardcoding. The same page describes a warning-mode rollout beginning July 24, 2026, during which requests that would later be rejected carry a Poly-RateLimit-Warning: true header while still being processed — check the current status of live enforcement before assuming either behavior.
Unlike the IP-based limits, this limiter reports its state in headers: Poly-RateLimit-Remaining for the bucket balance, Poly-RateLimit-Reset for when the current wait ends, Poly-RateLimit-Tier for the tier applied, and Retry-After on a 429. Two subtleties: Reset is not when the bucket is full, but when enough tokens should exist for the request you attempted; and Remaining can go negative after a cancel-all on tiers that permit debt. Compare a large batch's cost against the remaining balance before sending it.
Our test: what the limits actually do
We measured the read side of all three hosts in August 2026. The test campaign ran for 24 hours in total; individual load steps lasted 60 seconds, so this does not constitute a 24-hour steady-state load test. Everything below is public GET traffic — no authentication, no orders, no interference with live books — from two separately reported pools of dedicated addresses, a datacenter pool and an ISP pool, never merged into a combined figure. Load was applied as a percentage of the documented rate, and a ladder stopped at the first refusal.
Over-limit behavior contradicts the documented model. This is the headline result. On every endpoint and both pools, the knee arrived as an immediate 429 with no queueing phase before it: baseline latency stayed flat right up to the breaking step, then requests were refused outright. We never observed the gradual slowdown the documentation describes. Two details make it worse for anyone building a client:
Retry-Afteris present but its value is0— as a pause instruction it tells you nothing.X-RateLimit-*headers are absent entirely. There is no way to read your remaining budget; the only signal is hitting the wall.
Both facts point the same direction: maintain your own counter per host and per endpoint, and treat a 429 as confirmation you were already over, not as a scheduling hint.
Where the knee sits.
| Endpoint | Documented | Knee | Verdict |
|---|---|---|---|
gamma /markets |
300 / 10s = 30 rps | first 429 during the nominal 100% step | refusals begin at the documented rate |
data /positions |
150 / 10s = 15 rps | between 100% and 125% | survives documented, breaks below 125% |
Read these as bands rather than precise thresholds — a ladder in discrete steps locates the knee between two steps, not to the request. Both pools produced identical boundaries, so we found no difference between datacenter and ISP addresses on where the limit falls.
Endpoint throttling stayed local — within the range we tested. We loaded one endpoint to 150% of its documented rate while slowly polling a second one, in six pairs. The target took between 5% and 35% refusals; the control took zero 429s in all six pairs, including the pair where both endpoints live on the same host (/markets under load, /events as control).
Be careful about what that does and doesn't establish. Gamma publishes a shared allowance for /markets and /events together, and a host-wide general limit above that; loading /markets to 150% of its own cap stays well below both. So the honest reading is narrower than "the budgets are isolated": endpoint-specific throttling on /markets did not spill onto the control endpoint at the load we applied. Whether the shared and host-wide ceilings behave independently is a separate question our design didn't reach — it would need load high enough to approach those higher tiers.
Pushing harder buys nothing. Counting successful responses rather than requests sent, on gamma /markets:
| Pool | Offered | Succeeded | Of documented 30 rps |
|---|---|---|---|
| Datacenter | 35.6 rps | 28.1 | 94% |
| Datacenter | 43.6 rps | 28.7 | 96% |
| ISP | 42.9 rps | 27.8 | 93% |
| ISP | 37.9 rps | 27.9 | 93% |
Four independent runs, offered loads from 35.6 to 43.6 requests per second, and useful throughput never left the 27.8–28.7 band — 93–96% of the documented ceiling. This is the more solid evidence about where the limit sits: not a single knee observation, but a throughput plateau that held while offered load varied by more than 20%. Everything above the plateau converts into refusals — 21% to 35% of requests across these four runs — for zero additional data. "Push harder and some will slip through" is not a strategy here.
Addresses add up linearly. Running each address at half its measured knee on /positions:
| Addresses | Datacenter, rps | Efficiency | ISP, rps | Efficiency |
|---|---|---|---|---|
| 1 | 9.09 | 100% | 9.10 | 100% |
| 2 | 18.10 | 99.6% | 18.11 | 99.5% |
| 5 | 45.11 | 99.3% | 45.12 | 99.2% |
| 10 | 88.70 | 97.6% | 89.18 | 98.0% |
| 20 | 173.28 | 95.3% | — | — |
Interactive test results
More load stops producing more data
The first view shows the throughput plateau on /markets. Switch views to compare measured multi-address scaling with a perfectly linear result.
Hover, focus, or tap a point for the exact result. The tables remain the complete source data.
Two related findings: the limit is not counted per subnet — four addresses inside one /24 matched four from separate /24s, with no refusals in either group — and the budget resets on switching addresses, so an address driven to refusal is followed by a fresh full budget on the next one. Egress uniqueness was verified first, since none of this arithmetic holds if addresses share an exit node: 999 unique egress points out of 999 on the datacenter pool, 100 out of 100 on ISP.
Proxy overhead differs by pool. Direct baselines were sampled interleaved with the proxied runs rather than once at the start, so the comparison is like-for-like:
| Host | Added by datacenter | Added by ISP |
|---|---|---|
| gamma | +747 ms | +327 ms |
| data | +643 ms | +312 ms |
| clob | +612 ms | +464 ms |
ISP addresses added less overhead on every host, though not by a constant factor: roughly half as much on gamma (327 against 747 ms) and data (312 against 643 ms), but only about a quarter less on clob (464 against 612 ms). For throughput work the difference is irrelevant — both pools hit identical limit boundaries, so the endpoint ceiling binds either way. For latency-sensitive work on this route, ISP was the faster option.
One result we can't explain. At an identical offered rate of 22.3 rps on /positions, the datacenter pool took 5% refusals and delivered 21.3 successful rps, while ISP took 29% refusals and delivered 15.8 — a sixfold difference in refusal rate under equal load. The runs were six minutes apart, so the limit may drift over time, or something may distinguish the address sets. We're publishing it as an open question rather than smoothing it over.
What we didn't measure. No CLOB endpoint was load-tested — only availability and latency — so we have no measured number for /book or /price, and the documented figures stand unverified by us. Trading endpoints were excluded on principle: they require a funded wallet and signed orders, and even an immediately canceled order interferes with a live book, so everything in the trading section above comes from documentation. The longest step was 60 seconds, so multi-hour steady load is untested, and this was a single geographic route.
Designing inside the limits
Most integrations that hit limits are spending their budget on questions they already know the answer to. Before adding any capacity, three habits usually free more headroom than infrastructure would:
Cache what doesn't move. A market's question, slug, condition ID and token IDs never change. Fetching them once and storing them removes a whole class of Gamma calls from the hot path.
Subscribe instead of polling. Live prices and book updates belong on the WebSocket channels; REST polling for data that pushes is the most common source of self-inflicted throttling.
Poll by tier, not uniformly. Wallets with large live exposure deserve a short interval; dormant ones deserve a long one. A uniform timer spends most of its budget confirming that nothing happened.
After those, what remains is genuinely bound by the documented per-IP allowances — and our measurements sharpen what that means. Pushing a single address past its endpoint ceiling produced no extra throughput at all, so the only way to read faster is more addresses, and those add up close to linearly: 95.3% efficiency at twenty addresses, with no penalty for taking them from one contiguous /24 and a full budget available immediately after switching. That applies to the read side only. Order throughput cannot be scaled this way: the trading buckets are scoped to the signer, so adding addresses does not raise how fast you can place or cancel orders, and shouldn't be attempted as a workaround.
If your constraint is read volume, our proxies for crypto projects are dedicated IPv4 addresses, static for the full plan term, each subject to its own documented allowance. On choosing between pools, our runs support one conclusion and not the other: both pools hit identical limit boundaries, so neither is faster for throughput, while ISP added less latency overhead on this route — which matters only if your workload is latency-sensitive. Verify scaling against your own workload rather than assuming it stays linear past the range we tested, and check Polymarket's current terms of use before distributing a workload across addresses.