The Polymarket API in 60 seconds
- polymarket.com splits into three APIs: Gamma for markets, Data for wallets, CLOB for books and orders.
- All reads are public. Trading needs a wallet signature (L1) to mint credentials, then HMAC headers (L2) on every call.
- Every outcome is its own token ID. You trade token IDs, not market IDs.
- CLOB V2 went live on April 28, 2026. Anything built on the old SDKs is dead.
- Polymarket US is a different exchange with a different API, Ed25519 keys and a 20 requests a second limit.
- polymarket.com rejects new orders from the US. Check the geoblock endpoint before you trade.
Our take: the polymarket.com API is the most transparent data source in prediction markets. Every trade names a wallet, and the Data API hands you any wallet's positions for free. The trading side asks more of you than Kalshi: a wallet, a signature type, a funder address and a tick size per market. Budget a day to get your first order through.
Does Polymarket have an API?
Yes, two of them, and they don't share anything but the name.
| polymarket.com | Polymarket US | |
|---|---|---|
| Who trades | Most countries outside the US | US residents |
| Base URLs | gamma-api, data-api and clob.polymarket.com | api.polymarket.us and gateway.polymarket.us |
| Auth | Wallet signature (L1), then HMAC headers (L2) | Ed25519 key with X-PM headers |
| Money | pUSD on Polygon | US dollars |
| Market ID | Token ID per outcome | Market slug |
| SDKs | @polymarket/clob-client-v2, py-clob-client-v2 | polymarket-us on pip and npm |
| Rate limit | Throttled per endpoint, 9,000 per 10 seconds general | 20 requests a second per key, 429 above |
Accounts, balances, books and instruments are separate. Code written for one exchange never trades on the other, and an order on one never touches the other's book.
How polymarket.com organizes markets
- Event: the headline question, such as a presidential race.
- Market: one yes or no question inside the event, identified by a condition ID and a slug.
- Token: each outcome of a market is an ERC-1155 token with its own token ID. The CLOB trades tokens.
The workflow for every bot: find the market on Gamma, read its clobTokenIds, then call the CLOB with the token ID for the outcome you want.
Can you use the Polymarket API without a key?
Yes. Every read on Gamma, the Data API and the CLOB is public. You only need credentials to trade.
# Find a market and its two outcome token IDs (Gamma)
curl "https://gamma-api.polymarket.com/markets?slug=<MARKET_SLUG>"
# The order book for one outcome token (CLOB)
curl "https://clob.polymarket.com/book?token_id=<TOKEN_ID>"
# Every open position held by one wallet (Data API)
curl "https://data-api.polymarket.com/positions?user=0x<WALLET_ADDRESS>"
# Can this IP trade on polymarket.com?
curl "https://polymarket.com/api/geoblock"
# {"blocked": false, "ip": "...", "country": "...", "region": "..."}import json
import requests
GAMMA = "https://gamma-api.polymarket.com"
CLOB = "https://clob.polymarket.com"
market = requests.get(f"{GAMMA}/markets", params={"slug": "<MARKET_SLUG>"}).json()[0]
# Gamma returns these three fields as JSON strings, not arrays.
outcomes = json.loads(market["outcomes"])
token_ids = json.loads(market["clobTokenIds"])
prices = json.loads(market["outcomePrices"])
for outcome, token_id, price in zip(outcomes, token_ids, prices):
book = requests.get(f"{CLOB}/book", params={"token_id": token_id}).json()
best_bid = max((float(level["price"]) for level in book["bids"]), default=None)
best_ask = min((float(level["price"]) for level in book["asks"]), default=None)
print(outcome, "mid", price, "bid", best_bid, "ask", best_ask, "tick", book["tick_size"])const DATA = "https://data-api.polymarket.com";
interface Position {
title: string;
outcome: string;
size: number;
avgPrice: number;
cashPnl: number;
}
const wallet = "0x<WALLET_ADDRESS>";
const res = await fetch(`${DATA}/positions?user=${wallet}&limit=50`);
const positions = (await res.json()) as Position[];
for (const p of positions) {
console.log(p.title, p.outcome, p.size, "at", p.avgPrice, "P&L", p.cashPnl);
}- Gamma returns
outcomes,outcomePricesandclobTokenIdsas JSON strings. Parse them before you index into them. - The book response carries
tick_size,min_order_sizeandneg_risk. Your order needs all three to be valid. - The displayed price on polymarket.com is the midpoint of the best bid and ask, or the last trade when the spread runs wider than 10 cents.
- The Data API
/positionsendpoint returns size, average price, current value and cash P&L for any address. This is how every Polymarket wallet tracker works.
How do you get a Polymarket API key?
You don't sign up for one. You derive it from your wallet, and trading on polymarket.com takes two levels of auth:
- L1, once: your wallet signs an EIP-712 message. Send the signature with
POLY_ADDRESS,POLY_SIGNATURE,POLY_TIMESTAMPandPOLY_NONCEtoPOST /auth/api-keyto create credentials, orGET /auth/derive-api-keyto recover the ones you have. You get back an apiKey, a secret and a passphrase. - L2, every trading call: sign timestamp, method, path and body with HMAC-SHA256 using the base64-decoded secret, and send five headers.
POLY_ADDRESS your Polygon signer address
POLY_SIGNATURE url-safe base64 HMAC-SHA256 of timestamp + method + path + body
POLY_TIMESTAMP Unix timestamp in seconds
POLY_API_KEY apiKey from L1
POLY_PASSPHRASE passphrase from L1
# Example message for GET /data/orders with no body:
# 1727470800GET/data/ordersThen pick the signature type matching the wallet holding your funds:
| Signature type | Value | Account |
|---|---|---|
| EOA | 0 | A plain wallet you control directly |
| POLY_PROXY | 1 | Legacy proxy wallets from email or Google sign-up |
| GNOSIS_SAFE | 2 | Legacy Safe wallets from MetaMask or Rabby sign-up |
| DEPOSIT_WALLET | 3 | The default for accounts created since May 4, 2026 |
For types 1 to 3, pass the smart wallet address as the funder. The wrong signature type is the most common reason a correct-looking order gets refused.
How to place and cancel a Polymarket order
import os
from py_clob_client_v2 import (
ApiCreds, ClobClient, OrderArgs, OrderPayload, OrderType,
PartialCreateOrderOptions, Side, SignatureTypeV2,
)
HOST = "https://clob.polymarket.com"
CHAIN_ID = 137 # Polygon mainnet
PK = os.environ["PK"]
# Step 1 (L1): derive API credentials from your wallet signature.
creds = ClobClient(host=HOST, chain_id=CHAIN_ID, key=PK).create_or_derive_api_key()
# Step 2 (L2): trade with those credentials. A proxy wallet account
# needs its signature type and the proxy address as funder.
client = ClobClient(
host=HOST,
chain_id=CHAIN_ID,
key=PK,
creds=creds,
signature_type=SignatureTypeV2.POLY_PROXY,
funder=os.environ["PROXY_WALLET_ADDRESS"],
)
resp = client.create_and_post_order(
order_args=OrderArgs(token_id="<TOKEN_ID>", price=0.40, side=Side.BUY, size=100),
options=PartialCreateOrderOptions(tick_size="0.01"),
order_type=OrderType.GTC,
)
print(resp)
client.cancel_order(OrderPayload(orderID=resp["orderID"]))import { ClobClient, OrderType, Side } from "@polymarket/clob-client-v2";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygon } from "viem/chains";
const host = "https://clob.polymarket.com";
const account = privateKeyToAccount(process.env.PK as `0x${string}`);
const signer = createWalletClient({ account, chain: polygon, transport: http() });
// L1: derive credentials, then L2: build the trading client with them.
const creds = await new ClobClient({ host, chain: 137, signer }).createOrDeriveApiKey();
const client = new ClobClient({ host, chain: 137, signer, creds });
const book = await client.getOrderBook("<TOKEN_ID>");
console.log("tick size", book.tick_size, "levels", book.bids.length, book.asks.length);
const resp = await client.createAndPostOrder(
{ tokenID: "<TOKEN_ID>", price: 0.4, side: Side.BUY, size: 100 },
{ tickSize: "0.01" },
OrderType.GTC,
);
console.log(resp);
await client.cancelOrder({ orderID: resp.orderID });OrderType.GTCrests on the book. GTD adds an expiry. FAK fills what crosses now and cancels the rest.- The tick size comes from the market. A 0.01 market rejects a price of 0.405.
- Cancelling a partly filled order cancels only the unfilled part.
- Cancel in bulk with
cancel_orders,cancel_allor by market. Batch cancels take up to 3,000 order IDs.
Polymarket also ships a newer high-level SDK, @polymarket/client in TypeScript and polymarket in Python, built around a secure client and deposit wallets. The V2 CLOB clients above stay the direct route to the order book, and Polymarket's own examples for both live on GitHub.
What changed in Polymarket CLOB V2
April 28, 2026 broke every Polymarket bot written before then. What changed:
- Collateral moved from USDC.e to pUSD, an ERC-20 on Polygon backed one to one by USDC. The website wraps automatically. Your bot has to hold pUSD.
feeRateBps,nonceandtakerleft the signed order. The protocol sets the fee at match time. Read the fee withgetClobMarketInfo().- The EIP-712 domain version moved from 1 to 2, with a new exchange contract.
@polymarket/clob-clientandpy-clob-clientno longer work against production.- Builder attribution became a
bytes32builder code on each order, replacing the old HMAC builder headers.
Does Polymarket have a WebSocket?
Yes. The public market channel streams books, price changes and trades for any token, no key needed.
const ws = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/market");
ws.onopen = () => {
ws.send(JSON.stringify({ assets_ids: ["<TOKEN_ID>"], type: "market" }));
// Application-level heartbeat: send PING every 10 seconds.
setInterval(() => ws.send("PING"), 10_000);
};
ws.onmessage = (event) => {
if (event.data === "PONG") return;
const messages = JSON.parse(event.data);
for (const msg of [].concat(messages)) {
// event_type: book, price_change, last_trade_price or tick_size_change
console.log(msg.event_type, msg);
}
};| Channel | Address | Access |
|---|---|---|
| Market | wss://ws-subscriptions-clob.polymarket.com/ws/market | Public |
| User | wss://ws-subscriptions-clob.polymarket.com/ws/user | Your CLOB API credentials |
| Sports | wss://sports-api.polymarket.com/ws | Live scores for sports markets |
| Reference prices | wss://ws-live-v2.polymarket.com/ws | Authenticated, crypto and equity prices |
- The market channel sends
book,price_change,last_trade_priceandtick_size_changeevents. - Set
custom_feature_enabledto true forbest_bid_ask,new_marketandmarket_resolvedtoo. - Send the text frame
PINGevery 10 seconds to keep the connection alive. The server answersPONG. - Add and remove tokens on an open socket with
operation: "subscribe"and"unsubscribe".
Polymarket API rate limits
| API | Endpoint | Limit |
|---|---|---|
| Gamma | General | 4,000 per 10 seconds |
| Gamma | /events | 500 per 10 seconds |
| Gamma | /markets | 300 per 10 seconds |
| Data | v1 general | 1,000 per 10 seconds |
| Data | v2 general | 800 per 10 seconds |
| CLOB | General | 9,000 per 10 seconds |
| CLOB | /book and /price | 1,500 per 10 seconds each |
| CLOB | POST /order | 5,000 per 10 seconds burst, 120,000 per 10 minutes sustained |
| CLOB | DELETE /order | 5,000 per 10 seconds burst, 120,000 per 10 minutes sustained |
Polymarket throttles through Cloudflare. Over the limit, your requests slow down and queue instead of failing with a 429. A bot seeing sudden latency spikes has likely hit a limit, so watch response times, not only status codes.
Check the Polymarket geoblock before you trade
GET https://polymarket.com/api/geoblock returns whether the calling IP is blocked, plus its country and region. Orders from blocked regions get rejected. Three tiers apply:
- Fully blocked: sanctioned countries such as Iran, Syria, Cuba and North Korea, plus Crimea, Donetsk and Luhansk.
- Close only: you close existing positions and open nothing new. The US, the UK, France, Germany, Australia and Singapore are all here, among others.
- Website only: a short list where the site blocks new positions and the API still accepts orders.
Polymarket's terms forbid using a VPN to get around the block. The full country picture is in is Polymarket legal in the US.
How does the Polymarket US API work?
- Download the Polymarket US app and pass identity checks.
- Open polymarket.us/developer and create a key. Save the secret. Polymarket shows the secret once.
- Sign each private request with Ed25519 over timestamp, method and path, and send three
X-PMheaders.
import os
from polymarket_us import PolymarketUS
# Public data needs no credentials.
public = PolymarketUS()
print(public.markets.list({"limit": 10}))
print(public.markets.book("<MARKET_SLUG>"))
# Trading needs a key from polymarket.us/developer.
client = PolymarketUS(
key_id=os.environ["POLYMARKET_KEY_ID"],
secret_key=os.environ["POLYMARKET_SECRET_KEY"],
)
order = client.orders.create({
"marketSlug": "<MARKET_SLUG>",
"intent": "ORDER_INTENT_BUY_LONG",
"type": "ORDER_TYPE_LIMIT",
"price": {"value": "0.40", "currency": "USD"},
"quantity": 10,
"tif": "TIME_IN_FORCE_GOOD_TILL_CANCEL",
})
print(order)# Public order book, no key
curl "https://gateway.polymarket.us/v1/markets/<MARKET_SLUG>/book"
# Signed request: Ed25519 over timestamp + method + path
POST https://api.polymarket.us/v1/orders
X-PM-Access-Key: <key id>
X-PM-Timestamp: <milliseconds, within 30 seconds of server time>
X-PM-Signature: <base64 Ed25519 signature>
# Cancel
POST https://api.polymarket.us/v1/order/<ORDER_ID>/cancel
{"marketSlug": "<MARKET_SLUG>"}- Markets are identified by slug, not token ID. Order intent is one of
ORDER_INTENT_BUY_LONG,SELL_LONG,BUY_SHORTorSELL_SHORT. - Time in force covers day, good till cancel, good till date, immediate or cancel and fill or kill.
- Timestamps must be within 30 seconds of server time. Sync your clock.
- 20 requests a second per key, and 20 per IP for public calls. Over the limit, stop, wait a second, then back off.
- An order rejected after 5 seconds with "Global Rate Limit Exceeded" is latency protection, not a real rate limit. Keep your normal pace.
Stream Polymarket US books over wss://api.polymarket.us/v1/ws/markets with a signed handshake:
{
"subscribe": {
"requestId": "books-1",
"subscriptionType": "SUBSCRIPTION_TYPE_MARKET_DATA",
"marketSlugs": ["<MARKET_SLUG>"]
}
}Subscription types cover full books, lite prices and trades, with up to 100 markets per subscription. Private orders, positions and balances stream on /v1/ws/private.
What Polymarket fees cost an API bot
| Exchange | Taker fee | 100 shares at 50 cents | Makers |
|---|---|---|---|
| polymarket.com, crypto | 0.07 x C x p x (1 - p) | $1.75 | Free, 20% rebate |
| polymarket.com, sports and culture | 0.05 x C x p x (1 - p) | $1.25 | Free, rebate |
| polymarket.com, politics and tech | 0.04 x C x p x (1 - p) | $1.00 | Free, rebate |
| polymarket.com, geopolitics | Free | $0 | Free |
| Polymarket US | 0.0695 x C x p x (1 - p) | $1.74 | Paid a 0.0125 rebate |
A resting order pays nothing on either exchange and earns a rebate. A bot posting limit orders beats one hitting the book, before any edge. Detail in Polymarket fees explained.
Polymarket API errors and gotchas
- Old SDK. Anything importing
py_clob_clientwithout v2 fails on production. - Wrong signature type or funder. The order signs fine and gets refused. Match the type to your wallet.
- Off-grid price. Read
tick_sizeper market. Ticks change as prices near 0 or 1, and the socket sendstick_size_change. - Negative risk markets. Multi-outcome events set
neg_risk. Pass the flag or the order fails. - Holding USDC.e. CLOB V2 settles in pUSD. Wrap first.
- Silent throttling. Slow responses, not errors, mean you hit a limit.
- US IP. Orders from the US get rejected on polymarket.com. Reads still work.
- Timestamp units. CLOB L2 uses seconds. Polymarket US and Kalshi use milliseconds.
A checklist for your first Polymarket bot
- Call the geoblock endpoint from the machine your bot runs on. A US server trades nothing on polymarket.com.
- Pull a market from Gamma and parse the token IDs, tick size and neg risk flag.
- Read the book for both tokens and confirm the prices add up to about $1.
- Fund the wallet with pUSD and find its signature type and funder address.
- Derive API credentials once and store them. Deriving again returns the same set.
- Place one small resting order far from the market, watch the user channel, then cancel.
- Log latency on every call. Throttling shows up as slowness first.
- Start small and scale after a week of clean fills.
Polymarket API vs Kalshi API
Kalshi hands you one signing scheme, a full demo exchange and dollars. Polymarket hands you a wallet, three APIs and on-chain settlement, with no demo exchange. In return every polymarket.com trade names a wallet, which Kalshi never shows. Our take: build on Kalshi first if you want a working order bot this week. Build on Polymarket first if you want to study who wins. The Kalshi side is in the Kalshi API guide.
Which Polymarket API for which job
| Job | Use | Why |
|---|---|---|
| Find markets and prices | Gamma | Slugs, outcomes, prices and token IDs in one call |
| Track a wallet | Data API /positions and activity | Any address, no key |
| Show a live book | CLOB market WebSocket | Push updates, no polling |
| Run a trading bot abroad | py-clob-client-v2 or @polymarket/clob-client-v2 | Direct order book access |
| Run a trading bot in the US | polymarket-us SDK | The only Polymarket route for US residents |
| Rank wallets by settled profit | Rivo /v1/traders | Polymarket does not score wallets for you |
Does the Polymarket API do backtesting?
No. Polymarket gives you markets, prices, trades and wallet activity. There is no endpoint that replays a strategy for you. To backtest an idea yourself you pull every settled market you care about, rebuild the prices you would have filled at, apply the category fee, handle 50-50 and disputed resolutions, and hold out recent data so you don't fit the past.
Copying a wallet is harder still. The Data API tells you what one address holds and did, one address at a time. It doesn't rank wallets, score their closed positions against how markets settled, or tell you what copying them at your size would have returned. That is the part Rivo does for you.
Where Rivo fits next to the Polymarket API
The Data API tells you what a wallet holds. It doesn't tell you whether that wallet actually wins. Rivo does the scoring: we read the Polymarket tape, keep every large trade with its wallet, and grade each position when its market settles. One bearer key covers Polymarket, Polymarket US, Kalshi and Gemini:
- REST under /v1: the live tape across venues, wallets ranked by profit on settled markets, one wallet's full record and a flat-stake copy replay.
- Backtests, built in: score a signal or a wallet against markets already settled, at your size, with fees and an out of sample holdout. Polymarket's API has nothing like it.
- SSE at /v1/stream: trades pushed to your process, up to 3 streams per key.
- Webhooks: signed deliveries to your own https endpoint.
- Remote MCP: the same tools in Claude, ChatGPT or Cursor. See the prediction market MCP server.
- Scoped keys: read, write and trade, with an optional daily spend cap.
# Large Polymarket trades with the wallet behind each one
curl "https://api.rivo.markets/v1/feed?platform=polymarket&lane=whale&pageSize=10" \
-H "Authorization: Bearer rivo_live_..."
# Polymarket wallets ranked by profit on settled markets
curl "https://api.rivo.markets/v1/traders?platform=polymarket&sort=profit&limit=20" \
-H "Authorization: Bearer rivo_live_..."
# Replay copying one wallet at $100 a trade
curl "https://api.rivo.markets/v1/traders/polymarket/0x<WALLET_ADDRESS>" \
-H "Authorization: Bearer rivo_live_..."120 requests a minute per key, shared between REST and MCP, included in the $15 a month plan. Full reference in the Rivo API docs. Prefer no code? The Polymarket leaderboard and wallet tracker show the same data in a browser.
Where Rivo stops: we do not replace the CLOB for market making, and we do not sell full order book history. Quote both sides of a book through Polymarket directly. Use Rivo to decide which wallets deserve your attention.
Frequently asked questions
Does Polymarket have an API?
Yes, two. polymarket.com runs the Gamma API for market data, the Data API for positions and activity, and the CLOB API for order books and trading. Polymarket US runs a separate API at api.polymarket.us with Ed25519 keys. Market data on both needs no key.
Is the Polymarket API free?
Yes. Polymarket charges nothing for API access. Orders you place pay the normal trading fee for the market's category, and apps routing orders add their own builder fee.
What is the Polymarket Gamma API?
Gamma is the market and event metadata API for polymarket.com at gamma-api.polymarket.com. Use Gamma to find markets by slug, read outcomes and prices, and get the token IDs the CLOB API needs. The general limit is 4,000 requests per 10 seconds.
What is the Polymarket CLOB API?
The CLOB API at clob.polymarket.com runs the polymarket.com order book. Public calls return books and prices by token ID. Trading calls need L2 headers signed with credentials derived from your wallet.
How do I get a Polymarket API key?
On polymarket.com, sign an EIP-712 message with your wallet to create or derive an apiKey, secret and passphrase. The SDK method create_or_derive_api_key does this for you. On Polymarket US, finish identity checks in the app and create a key at polymarket.us/developer.
Why did my old Polymarket bot stop working?
Polymarket moved to CLOB V2 on April 28, 2026. The legacy clob-client and py-clob-client packages stopped working against production, collateral changed from USDC.e to pUSD, and feeRateBps left the signed order. Install @polymarket/clob-client-v2 or py-clob-client-v2.
What is the Polymarket US API?
The API for Polymarket's CFTC-regulated US exchange. Trading runs through api.polymarket.us with Ed25519 keys and X-PM headers, public data through gateway.polymarket.us, the limit is 20 requests per second per key, and the official SDKs are polymarket-us on pip and npm.
Does the Polymarket API work in the US?
Reading data works from anywhere. Placing new orders on polymarket.com from a US IP gets rejected, because the US is on the close-only list. Check an IP at polymarket.com/api/geoblock. US traders use the Polymarket US API instead.
Does Polymarket have a WebSocket?
Yes. polymarket.com has a public market channel at wss://ws-subscriptions-clob.polymarket.com/ws/market, a user channel for your own orders and a sports feed. Polymarket US streams at wss://api.polymarket.us/v1/ws/markets and /v1/ws/private, both behind a key.
What are the Polymarket API rate limits?
On polymarket.com the CLOB allows 9,000 requests per 10 seconds in general, 1,500 per 10 seconds on /book and /price, and 5,000 order posts per 10 seconds in a burst. Polymarket throttles excess calls instead of rejecting them. Polymarket US allows 20 requests a second per key and returns 429 above the limit.
Does the Polymarket API show who placed a trade?
On polymarket.com, yes. Every trade settles on Polygon and names a wallet address, and the Data API returns any wallet's positions. Polymarket US and Kalshi publish no trader identity on their trade feeds.