A single-page reference for everything Polymarket developers need — API endpoints, contract addresses, order struct, signing, V1 → V2 migration, SDK gotchas, and example requests.
Last updated: April 18, 2026 (just before V2 cutover)
- Endpoints
- Chains & tokens
- Contract addresses
- V1 vs V2 quick diff
- Gamma API (markets, events)
- CLOB API (trading)
- Data API (positions, trades, PnL)
- Order struct (V2)
- EIP-712 domains
- Signing flow
- Fees
- Common pitfalls
- SDK packages
- Useful links
| Purpose | URL | Auth |
|---|---|---|
| Gamma API (markets, events) | https://gamma-api.polymarket.com |
none |
| Data API (positions, trades, PnL) | https://data-api.polymarket.com |
none |
| CLOB production (V2 post-April-22) | https://clob.polymarket.com |
HMAC |
| CLOB V2 staging | https://clob-v2.polymarket.com |
HMAC |
- Chain: Polygon mainnet (chainId 137)
- V1 collateral: USDC.e —
0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 - V2 collateral: pUSD (ERC-20, 1:1 backed by USDC via
CollateralOnramp.wrap()) - Decimals: 6 (same as USDC on Polygon — amounts are scaled by 10⁶)
| Contract | Address |
|---|---|
| CTF Exchange (standard) | 0xE111180000d2663C0091e4f400237545B87B996B |
| NegRisk CTF Exchange | 0xe2222d279d744050d28e00520010520000310F59 |
| Collateral Onramp | TBD — check docs when published |
| pUSD | TBD — check docs when published |
| Contract | Address |
|---|---|
| CTF Exchange (standard) | 0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E |
| NegRisk CTF Exchange | 0xC5d563A36AE78145C45a50134d48A1215220f80a |
| Item | V1 | V2 |
|---|---|---|
| Python SDK | py-clob-client |
py-clob-client-v2 |
| TS SDK | @polymarket/clob-client |
@polymarket/clob-client-v2 |
| Exchange EIP-712 domain version | "1" |
"2" |
| ClobAuth EIP-712 domain version | "1" |
"1" (unchanged |
| Collateral | USDC.e | pUSD (wrap via onramp) |
| Order.nonce | present | removed (replaced by timestamp) |
| Order.expiration | present | removed |
| Order.taker | present | removed |
| Order.feeRateBps | present | removed (protocol-set) |
| Order.timestamp | — | new (milliseconds) |
| Order.metadata | — | new (bytes32) |
| Order.builder | — | new (bytes32) |
| Builder attribution | HMAC headers (POLY_BUILDER_*) |
signed builderCode field |
| Fee model | embedded feeRateBps |
fee = C × feeRate × p × (1-p), protocol-set, taker-only |
| Constructor | positional args | options object, chainId → chain, tickSizeTtlMs removed |
Base: https://gamma-api.polymarket.com — no auth required.
List of active event aggregates (multiple markets per event).
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&tag_slug=soccer&limit=50"Query params:
active(bool) — only currently open eventsclosed(bool) — include closed/resolvedtag_slug—soccer,nba,nfl,crypto,politics,ufc,tennis, ...limit(int, default 20, max 500)offset(int) — paginateorder—startDate,endDate,volume,liquidityascending(bool)
Key fields in response per event:
id,title,slug,negRisk,startDate,endDate,tagsmarkets[]— each withquestion,conditionId,clobTokenIds,outcomes,outcomePrices,bestBid,bestAsk,liquidityNum,volumeNum,spread,orderMinSize,orderPriceMinTickSize
Flat list of markets (not grouped by event):
curl "https://gamma-api.polymarket.com/markets?closed=false&limit=100"Base: https://clob.polymarket.com — HMAC L2 auth required for most endpoints.
POLY_ADDRESS: <wallet 0x...>
POLY_TIMESTAMP: <unix seconds>
POLY_API_KEY: <from create_or_derive_api_creds>
POLY_PASSPHRASE: <from create_or_derive_api_creds>
POLY_SIGNATURE: <HMAC-SHA256(secret, timestamp + method + path + body)>
The POLY_BUILDER_* HMAC headers from V1 are removed in V2.
GET /book?token_id=<id>— full orderbookGET /midpoint?token_id=<id>— mid priceGET /price?token_id=<id>&side=BUY|SELL— best priceGET /tick-size?token_id=<id>— minimum tickGET /markets/{conditionId}/clob— V2: returnsmts,mos,fd,t,rfqe
POST /order— submit signed orderDELETE /order/{id}— cancelDELETE /orders— cancel allGET /orders— list open ordersGET /balance-allowance?asset_type=COLLATERAL— pUSD balance + exchange approval
Polymarket returns:
bidsin ASCENDING price order → best bid isbids[-1]asksin DESCENDING price order → best ask isasks[-1]
Many bots silently assume bids[0] / asks[0] and compute the wrong midpoint.
Base: https://data-api.polymarket.com — no auth.
GET /trades?user=<wallet>&limit=50— recent trades for a walletGET /positions?user=<wallet>&sizeThreshold=1— current open positionsGET /value?user=<wallet>— PnL / net worthGET /trades?limit=50— recent trades across all users (public feed)
Returned trade fields: proxyWallet, side, asset (= tokenId), conditionId, size, price, timestamp, title, outcome, transactionHash.
struct Order {
uint256 salt; // random uint256 for uniqueness
address maker; // wallet placing the order
address signer; // signer (= maker for EOA)
uint256 tokenId; // CLOB token (YES or NO)
uint256 makerAmount; // amount offered (6-decimals)
uint256 takerAmount; // amount expected (6-decimals)
uint8 side; // 0 = BUY, 1 = SELL
uint8 signatureType; // 0 = EOA, 1 = POLY_PROXY, 2 = POLY_GNOSIS_SAFE
uint256 timestamp; // ms (V2: replaces nonce)
bytes32 metadata; // V2: app-defined, zero by default
bytes32 builder; // V2: builderCode for attribution
}makerAmount= USD you're putting up (6-decimal USDC units)takerAmount= shares you expect =makerAmount / priceside = 0
makerAmount= shares you're sellingtakerAmount= USD you expect =makerAmount × priceside = 1
{
"name": "Polymarket CTF Exchange",
"version": "2",
"chainId": 137,
"verifyingContract": "0xE111180000d2663C0091e4f400237545B87B996B"
}NegRisk markets:
{
"name": "Polymarket Neg Risk CTF Exchange",
"version": "2",
"chainId": 137,
"verifyingContract": "0xe2222d279d744050d28e00520010520000310F59"
}{
"name": "ClobAuthDomain",
"version": "1",
"chainId": 137
}This is the single biggest pitfall in migrating — both domains have fields literally named version and it's easy to update the wrong one.
- Build a ClobAuth typed-data message (uses the
ClobAuthDomain) - Sign with wallet private key
- POST to
/auth/api-keywith signature → receive{ api_key, api_secret, api_passphrase } - Store these — use them for all subsequent L2 calls
prehash = timestamp + method.upper() + path + body_json
signature = hmac_sha256(api_secret, prehash).hex()Attach as POLY_SIGNATURE header.
- Build
V2Orderstruct - EIP-712 sign it against the Exchange domain (version "2"!)
- Submit to
POST /orderas{...orderFields, signature: "0x..."}
V2 formula:
fee = C × feeRate × p × (1 − p)
Where:
C= trade notional (collateral amount, in USDC units)feeRate= per-market rate, fetched fromgetClobMarketInfo().fd.ratep= execution price (between 0 and 1)(1 − p)makes fee symmetric (highest at p=0.5, zero at extremes)
Makers pay no fees. Only takers.
- Domain version mixup — Exchange = "2", Auth = "1". Described above.
- Orderbook ordering — bids ASC, asks DESC. Use
bids[-1]andasks[-1]. - 6-decimal scaling — amounts on-chain are scaled by 10⁶.
$100 = 100_000_000. - pUSD collateral — API traders must wrap USDC.e → pUSD themselves before placing V2 orders.
- Fee embedded in order — V1 had
feeRateBps. V2 doesn't. Don't set it. - Stale
py-clob-client— stops working April 22. Installpy-clob-client-v2. chainIdconstructor kwarg — renamed tochainin V2.- Nonce vs timestamp — V2 uses millisecond timestamp, not nonce. Not interchangeable.
- Builder signing — V1 HMAC headers gone, embed
builderCodein signed Order struct. - NegRisk vs standard — separate exchange contracts + separate EIP-712 domains. Check
event.negRiskto pick the right one.
pip install py-clob-client-v2 # V2 (use this)
pip install py-clob-client # V1 (stops April 22, 2026)npm install @polymarket/clob-client-v2 # V2
npm install @polymarket/clob-client # V1 (stops)@polymarket/builder-signing-sdk— no longer needed, builder attribution is in the signed Order
- Official V2 migration guide: https://docs.polymarket.com/v2-migration
- Full changelog: https://docs.polymarket.com/changelog
- Bug bounty program ($5M via Cantina): https://cantina.xyz/bounties
- Related repos in this series:
- polymarket-v2-migration-kit — audit your V1 codebase for V2 migration
- polymarket-v2-example-bot — minimal V2 reference bot (Python, no SDK)
- polymarket-backtest — event-driven V2-aware backtest framework
- polymarket-arb — cross-market arbitrage scanner
- odds-arb-scanner — multi-sportsbook arb via the-odds-api
- match-monitor — live Polymarket + scores correlation
- poly-whale-watcher — wallet-level trade tracker
Found a gap, mistake, or new endpoint? PRs welcome. This is meant to be the reference, so completeness matters.
MIT / CC-BY-4.0 (code examples / prose).