Polymarket API and data access guide. Learn how to connect, find markets, get real-time data via WebSocket, access order books, place orders via CLOB SDK, an...
---
name: innotech-polymarket-api
description: Polymarket API and data access guide. Learn how to connect, find markets, get real-time data via WebSocket, access order books, place orders via CLOB SDK, and understand market mechanics.
---
# Polymarket API & Data Access Guide
**Purpose**: Comprehensive reference for connecting to, understanding, and using Polymarket APIs
**Last Updated**: 2026-03-23
---
## ๐ฏ What This Skill Covers
1. โ
**Connect to Polymarket** - API endpoints, authentication
2. โ
**Find Markets** - Search, filter, time-based pattern discovery
3. โ
**Get Real-time Data** - WebSocket usage and event types
4. โ
**Access Order Books** - Liquidity, bid/ask spreads, depth
5. โ
**Place Orders** - CLOB SDK, market/limit orders, decimal precision
6. โ
**Market Mechanics** - How 5-min markets work, winner determination, timing
7. โ
**Known Pitfalls** - Data reliability, timing issues, common bugs
**This skill does NOT include**:
- โ Trading strategies
- โ Signal analysis methodology
---
## ๐๏ธ Architecture Overview
### **API Components**
| Component | URL | Purpose | Auth? |
|-----------|-----|---------|-------|
| **Gamma API** | `https://gamma-api.polymarket.com` | Market info, prices, metadata | No |
| **CLOB API** | `https://clob.polymarket.com` | Order books, trades, market structure | No |
| **CLOB Auth API** | `https://clob-auth.polymarket.com` | JWT token for trading | Yes |
| **Data API** | `https://data-api.polymarket.com` | Historical data, order books | No |
| **WebSocket** | `wss://ws-subscriptions-clob.polymarket.com/ws/market` | Real-time price/book updates | No |
### **Data Flow for 5-Minute BTC Up/Down Markets**
```
1. Generate timestamp โ slug: btc-updown-5m-{timestamp}
2. Fetch market info from Gamma API โ get asset IDs
3. Subscribe to WebSocket with asset IDs โ real-time bid/ask
4. Place orders via CLOB SDK โ buy UP or DOWN tokens
5. Market closes (5 min) โ Polymarket resolves winner
6. Verify winner via Gamma API outcomePrices (1.0 = winner)
```
---
## ๐ Finding Markets
### **5-Minute Markets โ Timestamp Pattern**
```python
import time
def get_current_interval(interval_seconds=300):
"""Calculate current 5-minute interval timestamp"""
current_time = int(time.time())
return (current_time // interval_seconds) * interval_seconds
def generate_market_timestamps(num_markets=8):
"""Generate N market timestamps: current + next (N-1) intervals"""
base = get_current_interval()
return [base + i * 300 for i in range(num_markets)]
# Supported cryptos: btc, eth, sol, xrp
# Slug pattern: {crypto}-updown-5m-{timestamp}
# Example: btc-updown-5m-1772699400
```
### **API Search Methods**
```python
import requests
# By slug (most reliable for 5-min markets)
resp = requests.get("https://gamma-api.polymarket.com/markets", params={"slug": "btc-updown-5m-1772699400"})
# By keyword search
resp = requests.get("https://gamma-api.polymarket.com/markets", params={"_s": "bitcoin"})
# Active markets
resp = requests.get("https://gamma-api.polymarket.com/markets", params={"active": "true", "limit": 100})
```
---
## ๐ Asset IDs (Token IDs)
**Critical**: Each outcome (UP/DOWN) has a unique asset ID required for WS subscriptions and trading.
### **Getting Asset IDs**
```python
import json
def get_asset_ids(market):
"""Get asset IDs from clobTokenIds field (preferred)"""
clob_token_ids_str = market.get('clobTokenIds')
if clob_token_ids_str:
return json.loads(clob_token_ids_str) # List of 2 IDs: [UP_ID, DOWN_ID]
return []
```
**Important**:
- โ
`clobTokenIds` is a **JSON string**, not an array โ must `json.loads()`
- โ
Index 0 = UP, Index 1 = DOWN (for btc-updown markets)
- โ ๏ธ Fall back to `tokens[].token_id` only if `clobTokenIds` missing
---
## ๐ก WebSocket โ Real-time Data
### **Connection & Subscription**
```python
import aiohttp, asyncio, json, time
async def monitor_market(asset_ids):
async with aiohttp.ClientSession() as session:
ws = await session.ws_connect(
"wss://ws-subscriptions-clob.polymarket.com/ws/market",
heartbeat=None,
timeout=aiohttp.ClientWSTimeout(ws_close=30.0)
)
# Subscribe
await ws.send_json({
"assets_ids": asset_ids,
"type": "market",
"custom_feature_enabled": True
})
# Heartbeat every 10 seconds
last_ping = time.time()
async for msg in ws:
if msg.data == "PONG": continue
if time.time() - last_ping >= 10:
await ws.send_str("PING")
last_ping = time.time()
if msg.type == aiohttp.WSMsgType.TEXT:
data = json.loads(msg.data)
# Handle events...
```
### **โ ๏ธ CRITICAL: Event Type Reliability**
| Event Type | Description | Reliability | Use? |
|------------|-------------|-------------|------|
| **`book`** | Full orderbook snapshot | โญโญโญ | โ
YES |
| **`best_bid_ask`** | Best bid/ask update | โญโญโญ | โ
YES |
| **`price_change`** | Past trade records | โญ | โ NO |
| **`last_trade_price`** | Last trade price | โญ | โ NO |
**๐ฅ Key Lesson**: `price_change` = past trades, NOT current orderbook state. Using it as real-time bid/ask causes **impossible states** (ask < bid). Only use `book` and `best_bid_ask`.
### **โ ๏ธ CRITICAL: Book Event Structure**
```python
# โ WRONG: bids/asks are NOT under 'book' key
bids = data.get('book', {}).get('bids', []) # EMPTY!
# โ
CORRECT: bids/asks at TOP LEVEL
bids = data.get('bids', [])
asks = data.get('asks', [])
```
### **Order Book Fields**
```python
# Each bid/ask entry:
{
'price': '0.4550', # Price level (0-1)
'size': '7270' # Size in USD at this price
}
# Liquidity = sum of all bid sizes + sum of all ask sizes
total_liquidity = sum(float(b.get('size', 0)) for b in bids) + sum(float(a.get('size', 0)) for a in asks)
```
---
## ๐ฐ Placing Orders โ CLOB SDK
### **Authentication**
```python
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
host = "https://clob.polymarket.com"
chain_id = 137 # Polygon
client = ClobClient(host, key=key, chain_id=chain_id)
client.set_api_creds(ApiCreds(
api_key="YOUR_API_KEY",
api_secret="YOUR_API_SECRET",
api_passphrase="YOUR_API_PASSPHRASE"
))
```
### **๐ฅ CRITICAL: Decimal Precision Rules**
| Amount Type | Max Decimals | Example |
|-------------|-------------|---------|
| **Maker amount (tokens)** | **4** | 10.7419 |
| **Taker amount (USD)** | **2** | 3.33 |
| **Price** | **4** | 0.3100 |
**Rule: Calculate tokens FIRST, then derive USD**
```python
# โ
CORRECT: Explicit precision control
raw_tokens = amount_usd / price # e.g. 3.33 / 0.31 = 10.74193548
tokens = round(raw_tokens, 4) # 10.7419 (max 4 decimals)
usd_amount = round(tokens * price, 2) # 3.33 (max 2 decimals)
price_rounded = round(price, 4) # 0.3100 (max 4 decimals)
# โ WRONG: Let SDK auto-calculate โ may produce > 4 decimal tokens
# โ WRONG: Market order with SDK auto-calculation โ same issue
```
### **Limit Order (Recommended โ More Control)**
```python
from py_clob_client.order_builder.constants import BUY
order_args = OrderArgs(
token_id=asset_id,
price=price_rounded, # 0.3100 (max 4 decimals)
size=tokens, # 10.7419 (max 4 decimals)
side=BUY,
expiration=0, # GTC (Good Till Cancelled)
)
# A limit order at market price = instant fill with full precision control
```
### **Market Order (From Official Docs)**
```python
market_order = client.create_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100, # Dollar amount! SDK calculates tokens
price=0.50, # Slippage protection (can be 0)
order_type=OrderType.FOK
)
client.post_order(market_order, OrderType.FOK)
```
**Market Order Notes**:
- `amount` = USD amount (SDK calculates tokens internally)
- `price` = slippage protection ceiling, NOT exact execution price
- โ ๏ธ SDK may produce >4 decimal tokens โ prefer limit orders for safety
### **โ ๏ธ ALWAYS Read Official Docs Before Trading**
- https://docs.polymarket.com/trading/orders/create
- https://docs.polymarket.com/trading/orders/overview
**Never guess API behavior โ read docs first.** Multiple failed versions were caused by not reading official documentation.
---
## โฐ 5-Minute Market Mechanics
### **How Markets Work**
1. **New market every 5 minutes** โ timestamp-based: `btc-updown-5m-{unix_ts}`
2. **Market duration**: Exactly 5 minutes (300 seconds)
3. **Winner determination**: Polymarket resolves based on BTC price movement during the 5-minute interval
- UP wins โ outcomePrices: UP=1.0, DOWN=0.0
- DOWN wins โ outcomePrices: UP=0.0, DOWN=1.0
4. **Market appears on Polymarket**: ~30-60 seconds before interval start
5. **Orderbook becomes active**: Shortly after market appears
### **Timing โ What Happens When**
| Time | Event |
|------|-------|
| T-60s | Market appears on Gamma API |
| T-30s | Orderbook starts getting liquidity |
| T+0 | 5-minute interval starts |
| T+0 ~ T+30s | Ask prices around 0.50, active trading |
| T+240s | Most trading done, prices converge |
| T+300s | Market closes |
| T+300s ~ T+360s | Winner being resolved |
| T+360s+ | Gamma API `outcomePrices` shows 1.0/0.0 (resolved) |
### **โ ๏ธ CRITICAL: Winner Resolution Timing**
```python
# โ WRONG: Fetch winner immediately after market close
# Gamma API returns trading prices (0.60/0.40), NOT resolved prices (1.0/0.0)
# Can take 60+ seconds to resolve
# โ
CORRECT: Wait for outcomePrices to show 1.0/0.0
# After market close, poll Gamma API until resolved
# outcomePrices [1.00, 0.00] = UP winner confirmed
# outcomePrices [0.00, 1.00] = DOWN winner confirmed
```
---
## ๐ Data Reliability โ What to Trust
### **Price Data Hierarchy**
| Data Source | Use For | Accuracy | Latency |
|-------------|---------|----------|---------|
| `book` (WS) | Orderbook, bid/ask | โญโญโญ | Real-time |
| `best_bid_ask` (WS) | Quick price check | โญโญโญ | Real-time |
| `outcomePrices` (Gamma) | Market probability | โญโญ | 5-30s delayed |
| `outcomePrices` (Gamma, resolved) | Winner verification | โญโญโญ | 60s+ after close |
| `price_change` (WS) | Past trades only | โ | N/A |
| `best_bid_ask` ask price | Trading probability | โ ๏ธ | NOT true probability |
### **โ ๏ธ `best_bid_ask` Ask Price โ Market Probability**
- Ask price = lowest sell order in orderbook
- This is **not** the market's consensus probability
- It reflects orderbook dynamics, not market sentiment
- All versions using ask price as probability showed ~50% accuracy
---
## ๐ Market Rotation
### **Interval-Based Rotation (Correct Method)**
```python
def get_current_interval():
"""Get current 5-minute interval boundary"""
current_time = int(time.time())
return (current_time // 300) * 300
def should_rotate(current_interval, last_interval):
"""Check if we've entered a new interval"""
return current_interval != last_interval
# โ WRONG: Time-based (rotates at wrong time)
# time_since_rotation = time.time() - last_rotation
# if time_since_rotation >= 300: rotate() # Off by up to 15 seconds!
# โ
CORRECT: Interval-based (rotates exactly when interval changes)
# if get_current_interval() != current_base_timestamp: rotate()
```
---
## โ ๏ธ Known Pitfalls & Lessons Learned
### **1. Never Use `price_change` as Orderbook Data**
- `price_change` = past trade records
- BUY in `price_change` = someone bought at this price IN THE PAST
- This is NOT the current best ask
- Using it causes impossible states (ask < bid)
### **2. Decimal Precision Will Break Your Orders**
- Maker amount (tokens): max 4 decimals
- Taker amount (USD): max 2 decimals
- Calculate tokens first, derive USD second
- Never trust SDK auto-calculation
- Use limit orders for full control
### **3. Read Official Docs Before Implementing**
- Multiple wasted versions from guessing API behavior
- Official docs: https://docs.polymarket.com/trading/orders/create
### **4. Winner Resolution Takes Time**
- Gamma API doesn't return 1.0/0.0 immediately after close
- Poll until outcomePrices resolves to 1.0/0.0
- Verify with Gamma API outcomePrices post-session
### **โ ๏ธ Pitfall #5: Market Resolution Timing**
- Gamma API doesn't return 1.0/0.0 immediately after close
- Can take 60+ seconds for outcomePrices to resolve
- Poll until you see 1.0/0.0, don't assume immediate resolution
### **6. Market Appearance Timing is Variable**
- Markets don't always appear exactly 60s before start
- Sometimes 30s, sometimes 90s
- Fetch ask immediately when market appears โ don't delay
### **7. Ask Price at Market Start โ 0.50**
- Fresh market ask is ~0.50 (fair odds)
- Ask drifts quickly (within seconds) based on BTC movement
- If you see ask = 0.99, market is already closed/ending
---
## ๐ API Reference
### **Gamma API Endpoints**
| Endpoint | Method | Description | Auth? |
|----------|--------|-------------|-------|
| `/markets` | GET | List/search markets | No |
| `/markets/{id}` | GET | Get market by ID | No |
| `/markets?slug={slug}` | GET | Get market by slug | No |
| `/markets/{id}/price` | GET | Current prices | No |
### **WebSocket Events**
| Event | Direction | Reliable? | Structure |
|-------|-----------|-----------|-----------|
| `book` | SโC | โ
| `bids[]`, `asks[]` at **top level** |
| `best_bid_ask` | SโC | โ
| `best_bid`, `best_ask` |
| `price_change` | SโC | โ | Past trades, not orderbook |
| `last_trade_price` | SโC | โ | Last trade, not orderbook |
### **Rate Limits**
| API | Limit | Best Practice |
|-----|-------|---------------|
| Gamma API | ~100 req/min | Use WebSocket instead of polling |
| Data API | ~50 req/min | Cache responses |
| WebSocket | No hard limit | PING every 10s, batch subscriptions |
---
## ๐ง CLOB SDK Quick Reference
```python
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType, ApiCreds
from py_clob_client.order_builder.constants import BUY
# Initialize
client = ClobClient("https://clob.polymarket.com", key=key, chain_id=137)
client.set_api_creds(ApiCreds(api_key=..., api_secret=..., api_passphrase=...))
# Limit order (recommended)
order = OrderArgs(token_id=ASSET_ID, price=0.50, size=10.0, side=BUY, expiration=0)
# size = tokens (max 4 decimals), price (max 4 decimals)
# Market order
market_order = client.create_market_order(token_id=ASSET_ID, side=BUY, amount=100, price=0, order_type=OrderType.FOK)
# amount = USD, price = slippage ceiling
# Nonces: Must be unique per order. Use counter or UUID.
```
### **Official Documentation**
- Orders: https://docs.polymarket.com/trading/orders/create
- Overview: https://docs.polymarket.com/trading/orders/overview
---
## ๐ Version History
- **v2.0.0 (2026-03-23)**:
- โ
Added CLOB SDK trading section (limit/market orders, decimal precision)
- โ
Added 5-min market mechanics (timing, winner determination)
- โ
Added data reliability guide (what to trust, what not to)
- โ
Added known pitfalls section (7 critical lessons)
- โ
Added winner verification timing guide
- โ
Added winner verification timing guide
- โ
Added market rotation (interval-based vs time-based)
- โ
Updated WebSocket reliability table
- โ
Removed arbitrage scanner example (not applicable to 5-min markets)
- **v1.2.0 (2026-03-05)**:
- โ
Fixed WebSocket book event structure
- โ
Added real-time liquidity tracking
- โ
Added multi-cryptocurrency monitoring
- **v1.0.0 (2026-03-03)**:
- Initial release
don't have the plugin yet? install it then click "run inline in claude" again.