| name | Polymarket API Development |
| description | Complete guide for Polymarket developer APIs including CLOB, Gamma, WebSocket, Data API, and SDKs |
Polymarket Developer API Guide
This skill provides comprehensive documentation for building trading applications on Polymarket.
Architecture Overview
flowchart TB
subgraph APIs
GAMMA[Gamma API<br/>Market Discovery]
CLOB[CLOB API<br/>Trading]
WS[WebSocket<br/>Real-time Updates]
DATA[Data API<br/>Positions & History]
RTDS[RTDS<br/>Low-latency Streaming]
end
subgraph SDKs
PY[py-clob-client<br/>Python]
TS[@polymarket/clob-client<br/>TypeScript]
end
GAMMA --> |clobTokenIds| CLOB
CLOB <--> WS
SDKs --> APIs
1. API Endpoints
| API | Base URL | Purpose |
|---|
| Gamma API | https://gamma-api.polymarket.com | Market discovery & metadata |
| CLOB API | https://clob.polymarket.com | Prices, orderbooks & trading |
| Data API | https://data-api.polymarket.com | Positions, activity & history |
| WebSocket | wss://ws-subscriptions-clob.polymarket.com | Real-time updates |
2. Data Model
Hierarchy
Event (e.g., "2024 US Election")
โโโ Market (e.g., "Will Biden win?")
โโโ Outcomes (Yes/No with clobTokenIds)
Key Fields
- event.id / event.slug - Event identifier
- market.id / market.conditionId - Market identifier
- market.clobTokenIds - Array of
[YES_TOKEN_ID, NO_TOKEN_ID] for trading
- market.outcomes - JSON string
"[\"Yes\", \"No\"]"
- market.outcomePrices - JSON string
"[\"0.65\", \"0.35\"]" (probabilities)
- market.tickSize - Minimum price increment (usually
"0.01" or "0.001")
- market.negRisk - Boolean or None,
true for multi-outcome events (requires NegRiskAdapter for CTF operations)
[!IMPORTANT]
ID Types Matter: token_id (clobTokenIds) is used for orderbook/price queries. condition_id is used for get_market() and CTF operations. They are NOT interchangeable.
3. Gamma API - Market Discovery
Fetch Active Events
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=10"
Query Parameters
| Parameter | Description |
|---|
active | Boolean, filter active events |
closed | Boolean, filter closed events |
limit | Number of results |
offset | Pagination offset |
slug | Filter by event slug |
tag_slug | Filter by category (e.g., crypto, sports) |
Get Market by Slug
curl "https://gamma-api.polymarket.com/markets?slug=will-bitcoin-reach-100k"
Response Structure
{
"id": "123456",
"slug": "will-bitcoin-reach-100k",
"title": "Will Bitcoin reach $100k?",
"markets": [
{
"id": "789",
"question": "Will Bitcoin reach $100k?",
"clobTokenIds": ["TOKEN_YES_ID", "TOKEN_NO_ID"],
"outcomes": "[\"Yes\", \"No\"]",
"outcomePrices": "[\"0.65\", \"0.35\"]",
"tickSize": "0.01",
"negRisk": false
}
]
}
4. CLOB API - Trading
Get Current Price
curl "https://clob.polymarket.com/price?token_id=TOKEN_ID&side=buy"
Get Orderbook
curl "https://clob.polymarket.com/book?token_id=TOKEN_ID"
Response:
{
"market": "0x...",
"asset_id": "TOKEN_ID",
"bids": [
{"price": "0.64", "size": "500"},
{"price": "0.63", "size": "1200"}
],
"asks": [
{"price": "0.66", "size": "300"},
{"price": "0.67", "size": "800"}
]
}
Get Market Info
curl "https://clob.polymarket.com/markets/CONDITION_ID"
Trading Fees
- Maker: 0% (provides liquidity)
- Taker: ~1.5-2% (takes liquidity)
5. WebSocket - Real-time Updates
Connection
wss://ws-subscriptions-clob.polymarket.com/ws/market
wss://ws-subscriptions-clob.polymarket.com/ws/user
Market Channel Subscription
{
"type": "subscribe",
"channel": "market",
"assets_ids": ["TOKEN_YES_ID", "TOKEN_NO_ID"]
}
User Channel (Authenticated)
{
"type": "subscribe",
"channel": "user",
"auth": {
"apiKey": "YOUR_API_KEY",
"secret": "YOUR_SECRET",
"passphrase": "YOUR_PASSPHRASE"
},
"markets": ["CONDITION_ID"]
}
Message Types
| Channel | Event Types |
|---|
market | price_change, book_update, trade |
user | order_update, trade, position_update |
Keep-Alive
Send PING every 10 seconds to maintain connection.
6. Python SDK (py-clob-client)
Installation
pip install py-clob-client
Initialize Client
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
import os
HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
client = ClobClient(HOST, key=os.getenv("PRIVATE_KEY"), chain_id=CHAIN_ID)
creds = client.derive_api_key()
api_creds = ApiCreds(
api_key=creds["apiKey"],
api_secret=creds["secret"],
api_passphrase=creds["passphrase"]
)
client = ClobClient(
HOST,
key=os.getenv("PRIVATE_KEY"),
chain_id=CHAIN_ID,
creds=api_creds,
signature_type=0,
funder=os.getenv("FUNDER_ADDRESS")
)
Place Order
from py_clob_client.clob_types import OrderArgs, OrderType, PartialCreateOrderOptions
from py_clob_client.order_builder.constants import BUY, SELL
condition_id = "0x..."
market = client.get_market(condition_id)
token_info = market["tokens"][0]
tick_size = str(market["minimum_tick_size"])
order = client.create_order(
OrderArgs(
token_id=token_info["token_id"],
price=0.50,
size=10.0,
side=BUY,
),
PartialCreateOrderOptions(
tick_size=tick_size,
neg_risk=market.get("neg_risk", False),
)
)
response = client.post_order(order, OrderType.GTC)
print(f"Order ID: {response['orderID']}")
Order Types
from py_clob_client.clob_types import OrderType
order_type = OrderType.GTC
order_type = OrderType.FOK
order_type = OrderType.GTD
Cancel Orders
cancel_resp = client.cancel(order_id)
client.cancel_all()
Fetch Orderbook
book = client.get_order_book(token_id)
print(f"Bids: {len(book.bids)} levels, Asks: {len(book.asks)} levels")
print(f"Best bid: {book.bids[0]}")
7. TypeScript SDK (@polymarket/clob-client)
Installation
npm install @polymarket/clob-client ethers@5
Initialize Client
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers";
const HOST = "https://clob.polymarket.com";
const CHAIN_ID = 137;
const signer = new Wallet(process.env.PRIVATE_KEY);
let client = new ClobClient(HOST, CHAIN_ID, signer);
const userApiCreds = await client.createOrDeriveApiKey();
client = new ClobClient(
HOST,
CHAIN_ID,
signer,
userApiCreds,
0,
signer.address
);
Place Order
import { Side, OrderType } from "@polymarket/clob-client";
const market = await client.getMarket("TOKEN_ID");
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.50,
size: 10,
side: Side.BUY,
},
{
tickSize: market.tickSize,
negRisk: market.negRisk,
},
OrderType.GTC
);
console.log("Order ID:", response.orderID);
8. Data API - Positions & History
Get User Positions
curl "https://data-api.polymarket.com/positions?user=0xYOUR_PROXY_ADDRESS&limit=10"
Response fields (verified):
{
"proxyWallet": "0x...",
"asset": "2849827...",
"conditionId": "0x...",
"size": 200,
"avgPrice": 0.85,
"initialValue": 170,
"currentValue": 169,
"cashPnl": -1,
"percentPnl": -0.5882,
"realizedPnl": -412,
"curPrice": 0.845,
"redeemable": false,
"mergeable": false,
"negativeRisk": false,
"title": "Market Title",
"outcome": "No",
"outcomeIndex": 1
}
Query Parameters
| Parameter | Description |
|---|
user | Required - Proxy wallet address |
limit | Max results (default 100, max 500) |
redeemable | Filter redeemable positions |
mergeable | Filter mergeable positions |
9. CTF Operations (Token Management)
CTF (Conditional Token Framework) operations for splitting/merging outcome tokens.
Contract Addresses (Polygon)
| Contract | Address |
|---|
| CTF (Conditional Tokens) | 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 |
| NegRiskAdapter | 0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296 |
| USDC.e | 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 |
Market Types
[!CAUTION]
NegRisk markets require NegRiskAdapter. Standard CTF calls will fail with SafeMath: subtraction overflow.
- Standard markets (
negRisk: false): Use CTF contract directly
- NegRisk markets (
negRisk: true): Must use NegRiskAdapter contract
Split (USDC โ Outcome Tokens)
collateralToken = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
parentCollectionId = bytes32(0)
conditionId = "0x..."
partition = [1, 2]
amount = 10 * 10**6
Merge (Outcome Tokens โ USDC)
CTF.mergePositions(collateralToken, parentCollectionId, conditionId, partition, amount)
NegRiskAdapter.mergePositions(conditionId, amount)
Redeem (After Resolution)
Claim USDC for winning outcome tokens after market resolves.
See helpers/ctf_merge_split.py for complete implementation including Gnosis Safe proxy support.
10. Authentication
Signature Types
| Type | Value | Description |
|---|
| EOA | 0 | Standard wallet (MetaMask, etc.) |
| Gnosis Safe | 1 | Gnosis Safe multisig wallet |
| Polymarket Proxy | 2 | Most common - Polymarket proxy wallet |
[!TIP]
Most Polymarket accounts use signature_type=2. Check your exchanges/polymarket.py for the correct value.
API Credentials
- API Key: Persistent identifier
- Secret: Used for HMAC signing
- Passphrase: Additional auth layer
Credentials are derived from your wallet signature and are deterministic.
11. Common Patterns
Market Discovery Flow
events = requests.get(
"https://gamma-api.polymarket.com/events",
params={"active": "true", "tag_slug": "crypto", "limit": 10}
).json()
for event in events:
for market in event["markets"]:
token_ids = market["clobTokenIds"]
yes_token = token_ids[0]
no_token = token_ids[1]
BBO Monitoring
def get_bbo(token_id):
book = requests.get(
f"https://clob.polymarket.com/book?token_id={token_id}"
).json()
best_bid = book["bids"][0] if book["bids"] else None
best_ask = book["asks"][0] if book["asks"] else None
return best_bid, best_ask
WebSocket BBO Stream
import websocket
import json
def on_message(ws, message):
data = json.loads(message)
if data.get("event_type") == "price_change":
print(f"Price update: {data}")
ws = websocket.WebSocketApp(
"wss://ws-subscriptions-clob.polymarket.com/ws/market",
on_message=on_message
)
subscribe_msg = {
"type": "subscribe",
"channel": "market",
"assets_ids": ["TOKEN_YES_ID", "TOKEN_NO_ID"]
}
ws.send(json.dumps(subscribe_msg))
12. Error Handling
Common Issues
| Error | Cause | Solution |
|---|
Invalid Signature | Wrong signature type | Check signatureType matches wallet type |
L2 Auth Not Available | Missing API creds | Call derive_api_key() or createOrDeriveApiKey() |
Not Enough Balance | Insufficient USDC | Deposit USDCe on Polygon |
Invalid Order | Bad price/size | Check tickSize and minimum order requirements |
Geoblock | Restricted region | Use allowed jurisdiction or VPN |
Rate Limits
- REST API: ~100 requests/minute
- WebSocket: Keep-alive with PING every 10s
- Order placement: Subject to per-user limits
13. Verified Tips & Gotchas
[!TIP]
These patterns were verified through actual API testing.
Closed Markets Have No Orderbook
Markets with closed: true return "No orderbook exists for the requested token id". Always check market.closed before querying orderbook.
negRisk Can Be None
Gamma API may return negRisk: None instead of true/false. Handle this case:
neg_risk = market.get("neg_risk") or False
Orderbook Response Includes Hash
The /book endpoint returns a hash field useful for detecting changes:
{"hash": "56c2fb39603bc7eef0386d00749f11fa852f22f5", ...}
CTF Rate Limits
When running multiple merge operations, use:
- Private RPC (Alchemy/Infura) instead of
polygon-rpc.com
- Serial execution with delays between operations
- Global lock to prevent concurrent merge transactions
Gnosis Safe Integration
For proxy wallet operations, use execTransaction with proper signature:
15. RTDS - Real-Time Data Socket
Low-latency WebSocket for market makers and crypto prices.
Connection
wss://ws-live-data.polymarket.com
Available Topics
- Crypto Prices - Real-time cryptocurrency price updates
- Comments - Comment events and reactions
Message Structure
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1706547890123,
"payload": { ... }
}
Keep-Alive
Send PING every 5 seconds (more aggressive than CLOB WebSocket).
See RTDS TypeScript client: real-time-data-client
16. Environment Variables
Required .env configuration:
PRIVATE_KEY=0x...
POLYMARKET_PROXY_ADDRESS=0x...
RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEY
POLY_BUILDER_API_KEY=...
POLY_BUILDER_SECRET=...
POLY_BUILDER_PASSPHRASE=...
15. Verification Status
| Feature | Status | Notes |
|---|
| Gamma API | โ
Verified | Returns clobTokenIds, negRisk, conditionId |
| CLOB API | โ
Verified | Price & Orderbook fetch working |
| Data API | โ
Verified | Positions endpoint returns correct fields |
| Authentication | โ
Verified | signature_type=2 (Proxy) works |
| Order Management | โ
Verified | Create/Post/Cancel orders working |
| WebSocket | โ
Verified | Connection & Subscription confirmed |
| RTDS | โ ๏ธ Connection Verified | Connected but no data stream in short test |
| CTF Operations | ๐ Docs Only | Split/Merge/Redeem not tested on-chain |
| NegRiskAdapter | ๐ Docs Only | Contract interaction not tested on-chain |
Resources