rivomarkets

Polymarket API

Polymarket runs two APIs with nothing in common except the logo. polymarket.com trades from a crypto wallet on Polygon, and Polymarket US trades dollars on a CFTC-regulated exchange. This guide covers both, from your first public request to a signed order and a live order book stream.

Updated September 27, 2026

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.comPolymarket US
Who tradesMost countries outside the USUS residents
Base URLsgamma-api, data-api and clob.polymarket.comapi.polymarket.us and gateway.polymarket.us
AuthWallet signature (L1), then HMAC headers (L2)Ed25519 key with X-PM headers
MoneypUSD on PolygonUS dollars
Market IDToken ID per outcomeMarket slug
SDKs@polymarket/clob-client-v2, py-clob-client-v2polymarket-us on pip and npm
Rate limitThrottled per endpoint, 9,000 per 10 seconds general20 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.

curl
# 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": "..."}
Python: market, tokens and books
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"])
TypeScript: any wallet's open positions
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, outcomePrices and clobTokenIds as JSON strings. Parse them before you index into them.
  • The book response carries tick_size, min_order_size and neg_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 /positions endpoint 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:

  1. L1, once: your wallet signs an EIP-712 message. Send the signature with POLY_ADDRESS, POLY_SIGNATURE, POLY_TIMESTAMP and POLY_NONCE to POST /auth/api-key to create credentials, or GET /auth/derive-api-key to recover the ones you have. You get back an apiKey, a secret and a passphrase.
  2. L2, every trading call: sign timestamp, method, path and body with HMAC-SHA256 using the base64-decoded secret, and send five headers.
L2 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/orders

Then pick the signature type matching the wallet holding your funds:

Signature typeValueAccount
EOA0A plain wallet you control directly
POLY_PROXY1Legacy proxy wallets from email or Google sign-up
GNOSIS_SAFE2Legacy Safe wallets from MetaMask or Rabby sign-up
DEPOSIT_WALLET3The 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

Python: py-clob-client-v2
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"]))
TypeScript: @polymarket/clob-client-v2
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.GTC rests 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_all or 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, nonce and taker left the signed order. The protocol sets the fee at match time. Read the fee with getClobMarketInfo().
  • The EIP-712 domain version moved from 1 to 2, with a new exchange contract.
  • @polymarket/clob-client and py-clob-client no longer work against production.
  • Builder attribution became a bytes32 builder 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.

TypeScript: market channel
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);
  }
};
ChannelAddressAccess
Marketwss://ws-subscriptions-clob.polymarket.com/ws/marketPublic
Userwss://ws-subscriptions-clob.polymarket.com/ws/userYour CLOB API credentials
Sportswss://sports-api.polymarket.com/wsLive scores for sports markets
Reference priceswss://ws-live-v2.polymarket.com/wsAuthenticated, crypto and equity prices
  • The market channel sends book, price_change, last_trade_price and tick_size_change events.
  • Set custom_feature_enabled to true for best_bid_ask, new_market and market_resolved too.
  • Send the text frame PING every 10 seconds to keep the connection alive. The server answers PONG.
  • Add and remove tokens on an open socket with operation: "subscribe" and "unsubscribe".

Polymarket API rate limits

APIEndpointLimit
GammaGeneral4,000 per 10 seconds
Gamma/events500 per 10 seconds
Gamma/markets300 per 10 seconds
Datav1 general1,000 per 10 seconds
Datav2 general800 per 10 seconds
CLOBGeneral9,000 per 10 seconds
CLOB/book and /price1,500 per 10 seconds each
CLOBPOST /order5,000 per 10 seconds burst, 120,000 per 10 minutes sustained
CLOBDELETE /order5,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?

  1. Download the Polymarket US app and pass identity checks.
  2. Open polymarket.us/developer and create a key. Save the secret. Polymarket shows the secret once.
  3. Sign each private request with Ed25519 over timestamp, method and path, and send three X-PM headers.
Python: polymarket-us SDK
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)
Raw requests
# 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_SHORT or SELL_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:

Polymarket US subscribe message
{
  "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

ExchangeTaker fee100 shares at 50 centsMakers
polymarket.com, crypto0.07 x C x p x (1 - p)$1.75Free, 20% rebate
polymarket.com, sports and culture0.05 x C x p x (1 - p)$1.25Free, rebate
polymarket.com, politics and tech0.04 x C x p x (1 - p)$1.00Free, rebate
polymarket.com, geopoliticsFree$0Free
Polymarket US0.0695 x C x p x (1 - p)$1.74Paid 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_client without 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_size per market. Ticks change as prices near 0 or 1, and the socket sends tick_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

  1. Call the geoblock endpoint from the machine your bot runs on. A US server trades nothing on polymarket.com.
  2. Pull a market from Gamma and parse the token IDs, tick size and neg risk flag.
  3. Read the book for both tokens and confirm the prices add up to about $1.
  4. Fund the wallet with pUSD and find its signature type and funder address.
  5. Derive API credentials once and store them. Deriving again returns the same set.
  6. Place one small resting order far from the market, watch the user channel, then cancel.
  7. Log latency on every call. Throttling shows up as slowness first.
  8. 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

JobUseWhy
Find markets and pricesGammaSlugs, outcomes, prices and token IDs in one call
Track a walletData API /positions and activityAny address, no key
Show a live bookCLOB market WebSocketPush updates, no polling
Run a trading bot abroadpy-clob-client-v2 or @polymarket/clob-client-v2Direct order book access
Run a trading bot in the USpolymarket-us SDKThe only Polymarket route for US residents
Rank wallets by settled profitRivo /v1/tradersPolymarket 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.
Rivo: Polymarket wallets and trades
# 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.

Track Polymarket wallets without writing the API code

Rivo reads the Polymarket tape, scores every wallet on settled markets and alerts you when the ones you follow trade.

See the leaderboard