Polymarket API Guide (2026): US and International Endpoints, Auth, Limits and Code

How we make money: we earn a commission if you sign up for Polymarket or subscribe to KalshiSpy through our links. We earn nothing from Kalshi, Robinhood, FanDuel, DraftKings, Novig or OG. Rankings are not for sale. Full disclosure
Polymarket has two separate sets of APIs, one for each of its products. Polymarket US, the CFTC-regulated exchange for US residents, has a public market-data API and an authenticated Retail API for orders. The international polymarket.com site has the Gamma, CLOB and Data APIs, plus WebSocket feeds. Anyone can read the international market data, but its order endpoints reject new orders from the United States. If you are in the US and want to trade by API, you need the Polymarket US API.
Everything below was checked against docs.polymarket.us and docs.polymarket.com on October 16–17, 2026. Both APIs change often. Both changelogs list breaking changes as recently as October 2026, so check the docs before you ship.
Which API to use
| You want to | Use | Base URL | Key needed? |
|---|---|---|---|
| Read US markets, books and prices | Polymarket US public API | https://gateway.polymarket.us | No |
| Trade on Polymarket US from the US | Polymarket US Retail API | https://api.polymarket.us | Yes |
| Find international markets and events | Gamma API | https://gamma-api.polymarket.com | No |
| Read international books, prices and price history | CLOB API | https://clob.polymarket.com | No |
| Trade on the international site (outside the US) | CLOB API | https://clob.polymarket.com | Yes |
| Read wallet positions, trades, holders and leaderboards | Data API v2 | https://data-api.polymarket.com/v2 | No |
| Move funds between chains (international) | Bridge API | https://bridge.polymarket.com | No |
The two products have different markets, prices and order books. A Polymarket US market and the international market on the same event are separate instruments, with different identifiers and different prices.
The Polymarket US API
Public market data
The public API needs no key. Markets are identified by a slug, such as tec-mlb-champ-2026-09-27-cle.
| Endpoint | Returns |
|---|---|
GET /v1/markets | Markets, with limit, offset, active, closed and ordering filters |
GET /v1/markets/{slug} | One market |
GET /v1/markets/{slug}/book | Full order book and stats |
GET /v1/markets/{slug}/bbo | Best bid and offer, last trade and open interest, in a lighter format |
GET /v1/markets/{slug}/settlement | Settlement price |
GET /v1/events | Events, with the same filters |
GET /v1/price-history | Yes and No display prices for one market; pass the slug as symbol |
There are also endpoints for series, sports leagues and teams, tags and search. Prices come back as objects such as {"value": "0.2050", "currency": "USD"}. Book levels use px for price and qty for quantity, and the book's sell side is called offers, not asks.
Each market also carries a feeCoefficient. On October 17, 2026 it was 0.0695 on every market we sampled, matching the published fee schedule.
Python: read US prices
Tested against the live API on October 17, 2026.
import requests
GATEWAY = "https://gateway.polymarket.us"
markets = requests.get(
f"{GATEWAY}/v1/markets",
params={"limit": 5, "active": "true", "closed": "false"},
timeout=10,
).json()["markets"]
for m in markets:
bbo = requests.get(f"{GATEWAY}/v1/markets/{m['slug']}/bbo", timeout=10).json()["marketData"]
bid = bbo.get("bestBid", {}).get("value")
ask = bbo.get("bestAsk", {}).get("value")
print(f"{m['question']} [{m['slug']}]: bid {bid} / ask {ask}")
Sample output: World Series Champion [tec-mlb-champ-2026-09-27-cle]: bid 0.2050 / ask 0.2060.
Getting API keys
- Open an account in the Polymarket US app and pass identity verification. Our guide to using Polymarket in the US covers that.
- Go to polymarket.us/developer and sign in with the same method you used in the app: Apple, Google or email.
- Create a key. You get a Key ID and a Secret Key. The secret is shown once.
Polymarket US warns that switching sign-in methods can break API access (authentication docs).
Signing requests
Authenticated requests carry three headers:
| Header | Value |
|---|---|
X-PM-Access-Key | Your Key ID |
X-PM-Timestamp | Current time in milliseconds |
X-PM-Signature | Ed25519 signature of timestamp + METHOD + path, base64-encoded |
The timestamp must be within 30 seconds of server time. This is the pattern from Polymarket US's docs:
import base64
import os
import time
import requests
from cryptography.hazmat.primitives.asymmetric import ed25519
key_id = os.environ["POLYMARKET_KEY_ID"]
secret = os.environ["POLYMARKET_SECRET_KEY"]
private_key = ed25519.Ed25519PrivateKey.from_private_bytes(base64.b64decode(secret)[:32])
def auth_headers(method, path):
timestamp = str(int(time.time() * 1000))
message = f"{timestamp}{method}{path}"
signature = base64.b64encode(private_key.sign(message.encode())).decode()
return {
"X-PM-Access-Key": key_id,
"X-PM-Timestamp": timestamp,
"X-PM-Signature": signature,
"Content-Type": "application/json",
}
path = "/v1/portfolio/positions"
positions = requests.get(f"https://api.polymarket.us{path}", headers=auth_headers("GET", path), timeout=10)
print(positions.json())
The official SDKs
Polymarket US publishes polymarket-us for Python (3.10+) and TypeScript (Node 18+). The SDK signs requests for you.
import os
from polymarket_us import PolymarketUS
client = PolymarketUS(
key_id=os.environ["POLYMARKET_KEY_ID"],
secret_key=os.environ["POLYMARKET_SECRET_KEY"],
)
book = client.markets.book("chiefs-super-bowl")
order = client.orders.create({
"marketSlug": "chiefs-super-bowl",
"intent": "ORDER_INTENT_BUY_LONG",
"type": "ORDER_TYPE_LIMIT",
"price": {"value": "0.55", "currency": "USD"},
"quantity": 100,
"tif": "TIME_IN_FORCE_GOOD_TILL_CANCEL",
})
The slug above is the docs' example. Use a live slug from /v1/markets.
The Retail API covers orders (create, modify, cancel, preview, close a position, and batches of up to 20), portfolio positions and activity, account balances, combos and RFQs (generally available since October 1, 2026), and incentive programs.
US WebSockets
| Endpoint | Streams |
|---|---|
wss://api.polymarket.us/v1/ws/private | Your orders, positions, balances and RFQ updates |
wss://api.polymarket.us/v1/ws/markets | Order books, best bid and offer, and trades |
Both need your API key. Polymarket US recommends them over polling. For example, subscribe to SUBSCRIPTION_TYPE_MARKET_DATA_LITE instead of calling /bbo in a loop.
US rate limits
From the rate limits page, as of October 2026:
- General: 25 requests per second across the Retail API, counted per source IP and Cloudflare location. Several keys on one IP share the limit.
- Combos and RFQs:
POST /v1/combosandPOST /v1/rfqsshare 1 request per second. The RFQ read endpoints are 1 per second each. Creating and deleting quotes allows 100 per second. - Over the limit: you get
429 Too Many Requests. Wait at least a second and back off exponentially. - Latency stopgap: when the exchange is slow, it rejects any new order not processed within 5 seconds, with the message
Global Rate Limit Exceeded. Despite the wording, this is not a rate limit, and you do not need to slow down. Pure cancels are never rejected this way.
Production trading systems that need higher limits can ask support@polymarket.us.
Maintenance window
Polymarket US goes down every Thursday from 6 to 8 a.m. Eastern (since September 24, 2026; it was 2 to 4 a.m. before). All open orders are canceled first, all API requests return 503 during the window, and books reopen empty (general FAQs). Build your bot to expect this.
The international APIs
The international site settles trades on the Polygon blockchain. Its collateral is pUSD, a token backed by USDC (pUSD docs). Older guides that tell you to hold "native USDC, not USDC.e" are out of date: deposits of either are wrapped into pUSD.
Gamma API: find markets
Gamma serves events, markets, tags, series, comments, sports metadata and search.
| Endpoint | Notes |
|---|---|
GET /markets | limit and offset paging; filters include closed, slug, condition_ids, clob_token_ids, tag_id, volume and liquidity ranges; sort with order and ascending |
GET /markets/keyset | Cursor paging: pass next_cursor back as after_cursor; limit up to 100; offset returns 422 |
GET /markets/{id} and /markets/slug/{slug} | One market |
GET /events and /events/keyset | Events, which group related markets |
GET /public-search | Search markets, events and profiles |
A Gamma market object includes question, conditionId, slug, outcomes, outcomePrices and clobTokenIds. The last three are JSON-encoded strings, so parse them before use. Each outcome has its own token ID, and the CLOB and Data APIs use those token IDs.
CLOB API: books and prices
The CLOB's public read endpoints need no key.
| Endpoint | Returns |
|---|---|
GET /book?token_id= | Order book: bids, asks, tick_size, min_order_size, neg_risk, last_trade_price |
POST /books | Several books in one request |
GET /price?token_id=&side= | Best price on one side |
GET /midpoint?token_id= | Midpoint of best bid and best ask |
GET /spread?token_id= | Spread |
GET /last-trade-price?token_id= | Last trade price |
GET /prices-history?market= | Price series for one token ID; interval is one of 1m, 1h, 6h, 1d, 1w, all, max; fidelity sets resolution in minutes; or pass startTs and endTs |
GET /tick-size and GET /fee-rate | Market trading parameters |
Older guides use /orderbook/{token_id} and /markets on the CLOB. Use /book and Gamma's /markets instead.
Python: read international books
Tested against the live API on October 17, 2026.
import json
import requests
GAMMA = "https://gamma-api.polymarket.com"
CLOB = "https://clob.polymarket.com"
# The five open markets with the most 24-hour volume
markets = requests.get(
f"{GAMMA}/markets",
params={"closed": "false", "limit": 5, "order": "volume24hr", "ascending": "false"},
timeout=10,
).json()
for m in markets:
token_ids = json.loads(m["clobTokenIds"]) # a JSON string, not a list
outcomes = json.loads(m["outcomes"])
book = requests.get(f"{CLOB}/book", params={"token_id": token_ids[0]}, timeout=10).json()
bids = [float(level["price"]) for level in book["bids"]]
asks = [float(level["price"]) for level in book["asks"]]
best_bid = max(bids) if bids else None
best_ask = min(asks) if asks else None
print(m["question"])
print(f" {outcomes[0]}: bid {best_bid} / ask {best_ask}, tick {book['tick_size']}")
The code takes the highest bid and the lowest ask rather than the first element of each list, so it does not depend on sort order. A side can be empty, which is why it checks for that.
curl checks
# Five open markets
curl -G "https://gamma-api.polymarket.com/markets" \
--data-urlencode "closed=false" --data-urlencode "limit=5"
# Midpoint for one token
curl "https://clob.polymarket.com/midpoint?token_id=<TOKEN_ID>"
# Hourly prices for the last day
curl "https://clob.polymarket.com/prices-history?market=<TOKEN_ID>&interval=1d&fidelity=60"
# The most recent trade across all markets
curl "https://data-api.polymarket.com/v2/trades?limit=1"
Data API v2: wallets and activity
The Data API reports what has happened and who holds what. It needs no key. Version 1 is retired on October 24, 2026, so new code should use v2 (migration guide).
| v2 endpoint | Returns |
|---|---|
GET /v2/positions?user= | A wallet's positions; status can be OPEN, REDEEMABLE, REDEEMABLE_LOST, MERGEABLE or CLOSED |
GET /v2/trades | Trade feed, filterable by user or condition |
GET /v2/activity | Account activity |
GET /v2/holders?condition= | Top holders of a market |
GET /v2/oi and /v2/live-volume | Open interest and live event volume |
GET /v2/leaderboard | Trader rankings |
GET /v2/prices-history?token_id= | A token's price history |
GET /v2/user-pnl, /v2/user-stats, /v2/user-volume | A user's PnL series, stats and volume |
What changed from v1:
- Every response wraps its payload in
data. Paged routes add apaginationobject. - Paging is cursor-only. Pass
pagination.next_cursorback ascursoruntil it isnull. There is nooffset. - Fields are
snake_case(proxy_wallet,condition_id). - Markets are selected with
condition(up to 20 condition IDs), notmarket. /closed-positionsis folded into/v2/positions?status=CLOSED.- On the feed endpoints, resend the same filters with every page.
Authentication for trading
Placing orders on the international CLOB takes two layers (API docs):
- L1. Your wallet signs an EIP-712
ClobAuthmessage on Polygon (chain ID 137). You send that signature toPOST /auth/api-keyto create credentials, or toGET /auth/derive-api-keyto recover existing ones. You get back anapiKey, asecretand apassphrase. - L2. Each private request is signed with HMAC-SHA256 using the
secret, over the timestamp, the uppercase method, the path and the exact body. The request carries five headers:POLY_ADDRESS,POLY_SIGNATURE,POLY_TIMESTAMP,POLY_API_KEYandPOLY_PASSPHRASE.
Each order is also signed by the wallet. The SDKs handle all of this.
Check the location first. GET https://polymarket.com/api/geoblock returns whether the calling IP is blocked, with its country and region. The United States and the United Kingdom are close-only on both the website and the API: existing positions can be closed, new orders are rejected (geographic restrictions).
SDKs
Polymarket replaced its older CLOB clients with unified SDKs that cover Gamma, CLOB, Data API and wallet setup in one client:
| Language | Package | Notes |
|---|---|---|
| Python | polymarket-client | PublicClient and AsyncPublicClient for data; SecureClient and AsyncSecureClient for trading |
| TypeScript | @polymarket/client | Signer adapters for Viem, Privy and Ethers v5 |
| Rust | In development | A migration guide covers the older crate |
If your code imports py-clob-client, @polymarket/clob-client-v2 or the builder relayer packages, follow the SDK migration guide. A minimal Python example:
from polymarket import PublicClient
with PublicClient() as client:
page = client.list_markets(closed=False, page_size=10).first_page()
for market in page.items:
print(market)
International WebSockets
| Feed | URL | Use |
|---|---|---|
| Market channel | wss://ws-subscriptions-clob.polymarket.com/ws/market | Public books, price changes, trades and market lifecycle |
| User channel | wss://ws-subscriptions-clob.polymarket.com/ws/user | Your orders and fills; needs API credentials |
| Sports | wss://sports-api.polymarket.com/ws | Live game status and scores |
| PolyBolt live data | wss://ws-live-v2.polymarket.com/ws | Reference prices for crypto, equities and TWAPs; replaces the older RTDS feed and needs CLOB credentials |
To subscribe to the market channel, send the token IDs after you connect:
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, // adds best_bid_ask, new_market and market_resolved events
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(msg.event_type, msg);
};
The server sends a book snapshot first unless you set initial_dump: false. Subscriptions do not survive a disconnect, so reconnect and resubscribe in code.
International rate limits
Polymarket enforces IP-based limits through Cloudflare. Requests over the limit are throttled, delayed or queued, rather than rejected at once. Selected limits from the rate limits page, as of October 2026:
| API | Endpoint | Limit |
|---|---|---|
| Gamma | General | 4,000 requests per 10 s |
| Gamma | /markets | 300 per 10 s |
| Gamma | /events | 500 per 10 s |
| CLOB | /book, /price, /midpoint | 1,500 per 10 s each |
| CLOB | /books, /prices, /midpoints | 500 per 10 s each |
| CLOB | /prices-history | 1,000 per 10 s |
| CLOB | POST /order | 5,000 per 10 s burst; 120,000 per 10 min sustained |
| CLOB | DELETE /cancel-all | 250 per 10 s burst; 6,000 per 10 min sustained |
| Data API v2 | General | 800 per 10 s |
| Data API v2 | /v2/trades | 300 per 10 s |
| Bridge | General | 50 per 10 s |
Order and cancel requests also count against per-signer token buckets, separate for orders and cancels, with tiers based on 30-day trading volume. Polymarket ran these in warning mode from July 24, 2026, flagging requests that would be rejected with the header Poly-RateLimit-Warning: true (trading rate limits). Watch for that header. A batch order is admitted only if the bucket holds enough tokens for every order in it.
Fees for API traders
International taker fees are set by market category and applied at match time. You do not put them in your order. The formula is fee = shares × feeRate × p × (1 − p). Rates run from 0.04 (politics, finance, tech, mentions) to 0.07 (crypto). Geopolitics markets are fee-free. Makers pay nothing and receive rebates funded from taker fees (fees). Read a market's rate from GET /fee-rate.
On Polymarket US, the taker fee is 0.0695 × contracts × p × (1 − p) on standard markets as of October 2026, at most $1.74 per 100 contracts. Makers earn a rebate. Rebates move to volume tiers on October 19, 2026 (fee schedule).
On-chain data
International trades, balances and positions settle on Polygon, so you can also query them directly. Polymarket's data resources page points to:
- Goldsky, which streams Polymarket on-chain data into your own database, and CryptoHouse, a ClickHouse instance you can query with SQL.
- Dune, with starter queries for volume, value locked and open interest, plus community dashboards.
- Allium, another SQL analytics platform.
Polymarket notes that third-party schemas can lag its contract upgrades, so check indexed addresses against its contracts page. On-chain data covers the international site only. Polymarket US trades do not settle on a public blockchain.
Handling errors
Common responses on both APIs:
400for bad parameters, such as a condition ID passed where a token ID belongs. International error bodies can includeretry_after_seconds.401for missing or invalid credentials.404when no order book exists for a token, which happens on closed or inactive markets.422on Gamma when you passoffsetto a keyset endpoint orclosed=anywithout an ID filter.429when you are over a limit on Polymarket US.503during the Polymarket US maintenance window.
A retry helper with exponential backoff and jitter:
import random
import time
import requests
def get_json(url, params=None, max_retries=5):
for attempt in range(max_retries):
try:
r = requests.get(url, params=params, timeout=10)
if r.status_code in (429, 500, 502, 503):
time.sleep(min(2 ** attempt + random.random(), 30))
continue
r.raise_for_status()
return r.json()
except requests.ConnectionError:
time.sleep(min(2 ** attempt + random.random(), 30))
raise RuntimeError(f"Gave up on {url}")
Because the international API throttles rather than rejects, a slow response can be a rate-limit signal. Set timeouts, and measure latency as well as status codes.
Building a trading bot
An API client is the easy part of a bot. The work is in the signal, sizing, risk controls and reliability.
A typical loop:
- Pull market state from a WebSocket feed, or by polling books and prices.
- Work out your own probability from outside data: polls, news, prices on other venues.
- Size the position from your edge, your confidence, your current position and your risk budget.
- Place or amend orders to close the gap between the position you want and the one you have.
- Track fills, fees and profit and loss.
Practical points:
- Fees and spreads set the bar. At 50¢ the US taker fee is about 3.5% of the money you put in. If your edge is smaller than the fee plus the spread, you have no edge.
- Most markets are not fast. Outside the busiest games, books rarely move in milliseconds. Polling every few seconds is fine for most strategies.
- Cancel logic matters. Stale orders left on the book during a sharp move fill at bad prices. Build a kill switch. The international CLOB has a heartbeat endpoint for this.
- Plan for downtime. Polymarket US cancels every open order before its Thursday window. The international matching engine has maintenance restarts too.
- Start tiny. Trade at a hundredth of your planned size for the first week.
Bots must also follow each exchange's rules. Polymarket US bars trading on confidential information obtained in breach of a duty, and some contracts bar people connected to the event (trading restrictions).
Building a research tool
Most useful API projects never place an order.
- Probability over time. Poll prices every few minutes into a database and chart them against news.
- Backtesting. Pull
/prices-historyand test whether a signal would have beaten the market. - Cross-venue comparison. Compare a Polymarket US price with the same event on the international site or on Kalshi. Different books often disagree.
- Resolution tracking. Watch the source a market resolves on, such as a government data release, so you know when the outcome is set.
Read endpoints cover all of these without a key.
Gotchas
- Token ID, condition ID or slug. International markets have one condition ID and one token ID per outcome. Order books and price history need the token ID. Polymarket US uses slugs.
- Encoded fields. Gamma returns
outcomes,outcomePricesandclobTokenIdsas JSON strings. - Prices are strings. Both APIs return prices as strings such as
"0.5500". Parse withDecimalif you do arithmetic on money. - Data API v1 shuts down October 24, 2026.
- Breaking changes are frequent. On October 15, 2026 Polymarket US changed its event list endpoints to return primary markets only. Watch both changelogs.
- US data retention. Polymarket US prunes old executions and keeps market data and orders for 45 and 90 days. Store what you need.
- Location. Orders to the international CLOB from the US are rejected. Do not route around it.
FAQ
Does Polymarket have an API?
Yes, two. Polymarket US has a public market-data API at gateway.polymarket.us and an authenticated Retail API at api.polymarket.us. The international site has the Gamma, CLOB and Data APIs.
Can I trade on Polymarket by API from the US?
Yes, through the Polymarket US Retail API, after you open and verify a Polymarket US account and create a key at polymarket.us/developer. The international CLOB rejects new orders from US IP addresses.
Do I need an API key to read data?
No. Polymarket US public endpoints, Gamma, the CLOB read endpoints and Data API v2 all work without a key.
What are the rate limits?
Polymarket US allows 25 requests per second in general, per IP. The international APIs use Cloudflare limits per 10-second window, such as 1,500 per 10 seconds for /book, plus per-signer limits on orders.
Which SDK should I use?
For Polymarket US, polymarket-us in Python or TypeScript. For the international site, polymarket-client in Python or @polymarket/client in TypeScript. The older py-clob-client has been replaced.
How do I get historical prices?
On the international site, GET /prices-history on the CLOB or GET /v2/prices-history on the Data API, with a token ID. On Polymarket US, GET /v1/price-history with the market slug as symbol. For bulk history on the international site, Dune, Goldsky and Allium hold the on-chain record.
What does Polymarket settle in?
Polymarket US settles in US dollars through its clearinghouse, QC Clearing LLC. The international site settles in pUSD, a USDC-backed token on Polygon.
Where is the WebSocket?
Polymarket US: wss://api.polymarket.us/v1/ws/markets and /v1/ws/private, both with a key. International: wss://ws-subscriptions-clob.polymarket.com/ws/market for public data and /ws/user for your own orders.
Weekly roundup · Free
Get the Bellwether weekly market roundup
One short email each Sunday: what moved on Kalshi and Polymarket, the regulation news that mattered, and the markets worth watching.
One email per week · Unsubscribe anytime · We don't share your email