Polymarket CLOB V2 Migration Plan
Generated: 2026-04-29 | Target: Upgrade all Polymarket API calls to CLOB v2
Reference: @polymarket/clob-client-v2@1.0.2 (npm, TypeScript source)
Status: β COMPLETE β Signature verified working
Overview
The project uses Polymarket's CLOB API across multiple modules. The v2 upgrade involves:
1. Order signing format (EIP-712 struct changed from 12 β 11 fields)
2. Order wire format (API POST body format)
3. New/renamed endpoints (where applicable)
4. py_clob_client dependency version bump (in requirements.txt)
Current State
| Component | File | API Usage |
|---|---|---|
| CLOB Client (core) | src/mm/clob_client.py | Full REST client: orders, orderbook, markets |
| Web App | src/web/app.py | Direct HTTP: /book, /tick-size, gamma-api, data-api, lb-api |
| Weather MM Runner | src/mm/weather_mm_runner.py | Direct HTTP: /book, gamma-api events |
| Market Selector | src/mm/market_selector.py | Via CLOBClient |
| Paper Trader | src/mm/paper_trader.py | Via CLOBClient |
| Config | src/mm/config.py | Defines base URLs |
| Scrapers | src/scrapers/collector.py | gamma-api, data-api, lb-api |
| Scrapers | src/scrapers/import_top.py | lb-api, data-api |
| Scrapers | src/scrapers/reimport_trades.py | data-api |
Migration Steps
Step 1: Clean up order wire format (clob_client.py)
File: src/mm/clob_client.py
The _sign_order_v2() method returns convenience fields price and size inside the signed order dict. These are NOT part of the CLOB v2 wire format (NewOrderV2 interface). They should be removed from the API payload to avoid potential issues.
v2 wire format (from @polymarket/clob-client-v2 NewOrderV2):
{
"salt": int,
"maker": "0x...",
"signer": "0x...",
"taker": "0x0000...",
"tokenId": "123...",
"makerAmount": "500000",
"takerAmount": "500000",
"side": "BUY",
"signatureType": 0,
"timestamp": "1714400000",
"expiration": "0",
"metadata": "0x0000...",
"builder": "0x0000...",
"signature": "0x..."
}
Changes needed in _sign_order_v2() return dict:
price convenience field from returned dictsize convenience field from returned dictprice and size as separate attributes or log-onlyChanges needed in create_order() and create_order_l1():
price/size for logging before sending, or store in a separate variableorder payloadStep 2: Remove deprecated v1 EIP-712 struct references (clob_client.py)
File: src/mm/clob_client.py
The code already uses v2 EIP-712 order struct. Verify there are no remaining v1 references:
EIP712_ORDER_TYPES_V2 β correct βnonce, feeRateBps in EIP-712 struct β correct βDouble-check: The EIP-712 domain still uses 'version': '2' and 'name': 'Polymarket CTF Exchange' β these are correct per v2 spec.
Step 3: Update CLOB REST endpoint paths (clob_client.py)
File: src/mm/clob_client.py
Compare current endpoints with v2 npm client:
| Purpose | Current Path | v2 Path | Change? |
|---|---|---|---|
| List markets | GET /markets | GET /markets | No |
| Get market | GET /markets/{cid} | GET /markets/{cid} | No |
| Orderbook | GET /book?token_id= | GET /book?token_id= | No |
| Midpoint | GET /midpoint?token_id= | GET /midpoint?token_id= | No |
| Price | GET /price?token_id=&side= | GET /price?token_id=&side= | No |
| Spread | GET /spread?token_id= | GET /spread?token_id= | No |
| Last trade | GET /last-trade-price?token_id= | GET /last-trade-price?token_id= | No |
| Tick size | GET /tick-size?token_id= | GET /tick-size?token_id= | No |
| Neg risk | GET /neg-risk?token_id= | GET /neg-risk?token_id= | No |
| Fee rate | GET /fee-rate?token_id= | GET /fee-rate?token_id= | No |
| Version | GET /version | GET /version | No |
| Place order | POST /order | POST /order | No |
| Cancel order | DELETE /order | DELETE /order | No |
| Cancel all | DELETE /cancel-all | DELETE /cancel-all | No |
| Open orders | GET /data/orders | GET /orders | YES β οΈ |
| Auth keys | POST /auth/api-key | POST /auth/api-key | No |
| Derive key | GET /auth/derive-api-key | GET /auth/derive-api-key | No |
Action: Change GET /data/orders β GET /orders in get_orders() method.
Step 4: Add v2 bulk endpoints (optional enhancement)
The v2 client adds bulk endpoints for efficiency:
| New Endpoint | Purpose |
|---|---|
POST /books | Bulk orderbook fetch |
POST /midpoints | Bulk midpoint fetch |
POST /prices | Bulk price fetch |
POST /spreads | Bulk spread fetch |
POST /last-trades-prices | Bulk last trade price |
These are optional - existing single-token endpoints still work. The weather MM runner and market selector could benefit from bulk orderbook fetching when querying many tokens.
Step 5: Update Gamma API usage (multi-file)
Gamma API has no v1/v2 versioning β it's a separate REST API unchanged between CLOB versions. No changes needed.
Files using Gamma API:
src/mm/clob_client.py β get_gamma_markets(), get_gamma_market() β no changesrc/mm/weather_mm_runner.py β /events?slug= β no changesrc/web/app.py β /events?slug= β no changesrc/scrapers/collector.py β /markets β no changeStep 6: Update data-api usage (multi-file)
data-api.polymarket.com has no v1/v2 versioning β it's the off-chain data service. No changes needed.
Files using data-api:
src/web/app.py β /positions, /activity β no changesrc/scrapers/reimport_trades.py β /activity β no changesrc/scrapers/import_top.py β /positions, /activity β no changesrc/scrapers/collector.py β /leaderboard, /positions, /trades, /activity β no changeStep 7: Update lb-api usage (multi-file)
lb-api.polymarket.com has no v1/v2 versioning β it's the leaderboard API. No changes needed.
Files using lb-api:
src/web/app.py β /profit β no changesrc/scrapers/import_top.py β /profit β no changeStep 8: Update requirements.txt
File: requirements.txt
Bump py_clob_client to latest:
- py_clob_client>=0.17
+ py_clob_client>=0.34.6
Note: The project uses a custom CLOBClient implementation rather than the py_clob_client library. The version bump is for any indirect usage or future compatibility. The custom client already implements v2 signing and payload format.
Step 9: Update proxy domain list (app.py)
File: src/web/app.py, line ~90
The proxy domain list already includes all current endpoints:
_PROXY_DOMAINS = {
'www.hko.gov.hk', 'data.weather.gov.hk', 'www.weather.gov.hk',
'polymarket.com', 'gamma-api.polymarket.com', 'lb-api.polymarket.com',
'data-api.polymarket.com', 'clob.polymarket.com',
}
No changes needed.
Step 10: Verify L2 auth header format
File: src/mm/clob_client.py, _l2_sign() method
Compare with v2 npm client (createL2Headers):
POLY_ADDRESS βPOLY_SIGNATURE (HMAC-SHA256, base64 url-safe) βPOLY_TIMESTAMP βPOLY_API_KEY βPOLY_PASSPHRASE βNo changes needed β L2 auth format is identical.
Summary of Actual Changes Needed
| # | File | Change | Impact |
|---|---|---|---|
| 1 | src/mm/clob_client.py | Remove price/size from order wire dict | Required |
| 2 | src/mm/clob_client.py | Change /data/orders β /orders | Required |
| 3 | requirements.txt | Bump py_clob_client>=0.34.6 | Recommended |
| 4 | src/mm/clob_client.py | Add optional bulk endpoints | Optional |
Everything else (EIP-712 v2 struct, L2 auth, Gamma API, data-api, lb-api) is already correct and needs no changes.
Risk Assessment
/data/orders β /orders endpoint change β needs testingTesting Plan
1. Call GET /version on clob.polymarket.com to confirm v2 is live
2. Place a test order via create_order() and verify it appears in open orders
3. Verify get_orders() returns correctly after endpoint change
4. Run weather MM runner --scan to verify orderbook fetching works
5. Check web dashboard loads without errors
Execution Order
The changes should be made in this order:
1. requirements.txt β version bump (safe, no runtime impact)
2. clob_client.py β remove price/size from wire format + fix endpoint path
3. Test manually
4. All other files confirmed no changes needed