Polymarket Perfect-Fit Delta
This document defines the exact changes needed for a drop-in Polymarket API/CLOB interface. Scope of comparison:- Current PolySimulator API v1 implementation (
/v1/*), includingPOST /v1/clob/order - Public Polymarket CLOB/Data expectations from the official developer docs
- A bot written for Polymarket should run against PolySimulator with no payload rewrites and minimal URL/config changes.
- Users must still create keys easily in PolySimulator (
/v1/keysUX). - Trading requests must behave like Polymarket CLOB (headers, routes, payload shape, order lifecycle semantics).
Implementation Status
Updated: July 2025 — PR #329Phases Completed (Closed Beta)
| Phase | Status | Details |
|---|---|---|
| B — Starting Balance PnL Fix | ✅ Done | get_balance() and _get_portfolio_impl() now use api_balance (1,000). |
| C — Public CLOB Read Aliases | ✅ Done | Six unauthenticated endpoints added: GET /price, POST /prices, GET /midpoint, GET /spread, GET /book, GET /prices-history. All accept token_id query param. Mounted on public_router in data.py. |
| D — Order Status Alignment | ✅ Done | clob_order() now returns lowercase status values ("matched", "live", "unmatched") matching Polymarket’s insert-order convention. |
| E — Bulk Cancel Endpoints | ✅ Done | DELETE /cancel-all and DELETE /cancel-market-orders added with {canceled, not_canceled} response shape matching Polymarket. Supports market (condition_id) or asset_id (token_id) query params. |
Phase Deferred
| Phase | Status | Reason |
|---|---|---|
| F — L2 Auth (Polymarket HMAC headers) | 🔜 Deferred | Not required for closed beta launch. Current X-API-Key auth is sufficient for simulator users. L2 auth (POLY_ADDRESS, POLY_SIGNATURE, POLY_TIMESTAMP, POLY_API_KEY, POLY_PASSPHRASE) will be implemented when real Polymarket bot migration demand materializes. Schema design (api_l2_credentials, api_l2_replay_guard) is documented below and ready for implementation. |
Copilot Review Fixes (PR #329)
Also included in this PR:- Auth allowlist: O(N) wildcard scan → O(1) domain extraction
- Settlement: Removed redundant updown market check
- Docker prod subnet: Changed
172.29.0.0/16→172.30.0.0/16to avoid staging collision - Smoke tests: Fixed docstring, removed 502 tolerance, expanded safety assertions
- live-migration.mdx: Aligned env var names (
POLY_*notPOLYMARKET_*) - CLAUDE.md: Replaced duplicate staging workflow with pointer to canonical source
Current vs Target
| Area | Current PolySimulator | Target Perfect-Fit |
|---|---|---|
| Read endpoints auth | Mostly require X-API-Key | CLOB read endpoints public (no auth) |
| Read endpoint paths | /v1/markets/*, /v1/prices/batch | Canonical CLOB paths (/price, /prices, /book, /books, /midpoint, /midpoints, /spread, /prices-history) |
| Trading auth | X-API-Key | Polymarket L2 headers (POLY_ADDRESS, POLY_SIGNATURE, POLY_TIMESTAMP, POLY_API_KEY, POLY_PASSPHRASE) |
| Order payload | Simplified token/price/size model | Accept signed Polymarket order object and order type semantics |
| Order lifecycle surface | Single compat route + native order APIs | Canonical create/list/cancel/cancel-all/cancel-market-style endpoints |
| Error contract | API v1 app-specific codes | Polymarket-compatible auth/trading/rate-limit response shapes and status codes |
Design Decision: Dual-Mode Auth
Use one compatibility layer that accepts either auth model:- Native mode:
X-API-Key(current behavior, easy onboarding) - Polymarket mode: full L2 header set (
POLY_*) with HMAC validation
- Keeps onboarding simple for users who just want simulator access.
- Allows existing Polymarket bots/SDKs to work without auth rewrites.
- Enables progressive rollout with minimal risk.
Endpoint Delta
1. Read Surface (Public CLOB-style)
Must add canonical routes and make them unauthenticated:| Method | Target Route | Current Equivalent | Required Delta |
|---|---|---|---|
GET | /price | POST /v1/prices/batch or cached market price | Add token-based single-price read route |
GET | /prices | POST /v1/prices/batch | Add query/body multi-token read route |
GET | /book | GET /v1/markets/{condition_id}/book | Add token_id-native route |
POST | /books | none | Add batch book snapshot route |
GET | /midpoint | derived from book/prices | Add explicit midpoint endpoint |
GET / POST | /midpoints | none | Add multi-token midpoint endpoints |
GET | /spread | none | Add best-bid/best-ask spread route |
GET | /prices-history | GET /v1/markets/{condition_id}/candles | Add token-native CLOB history route |
- Keep existing
/v1/*endpoints for SDK/native users. - Implement these as aliases over existing cache and CLOB client internals.
2. Trading Surface (CLOB-style)
Must add canonical trading routes with Polymarket request/response semantics:| Method | Target Route | Current Equivalent | Required Delta |
|---|---|---|---|
POST | /order | POST /v1/clob/order | Accept fully signed order payload; preserve orderID response shape |
POST | /orders | POST /v1/orders/batch | Accept Polymarket-style batch envelope and per-order types |
DELETE | /order or /cancel-style | DELETE /v1/orders/{order_id} | Support canonical cancel-by-orderID body/query contract |
DELETE | /cancel-all | none | Add cancel-all open orders endpoint |
DELETE | /cancel-market-orders | none | Add market/token-scoped bulk cancel endpoint |
GET | open/active orders route | GET /v1/orders | Add Polymarket-compatible query/response contract |
- The simulator can remain virtual settlement underneath, but HTTP surface must match Polymarket contracts.
- Keep existing native trading routes for backward compatibility.
3. Auth/Credential Compatibility Endpoints
Add Polymarket-style auth endpoints in parallel:| Method | Target Route | Purpose |
|---|---|---|
POST | /auth/api-key | Create L2 API credentials from valid L1 headers |
GET | /auth/derive-api-key | Re-derive existing L2 API credentials |
- Returning credentials here is for compatibility and should be optional in UI flows.
- PolySimulator users can continue using
/v1/keyswithout wallet/L1 setup.
Authentication Delta
1. Add L2 Header Auth (Required)
For trading routes, accept and validate:POLY_ADDRESSPOLY_SIGNATURE(HMAC-SHA256 request signature)POLY_TIMESTAMPPOLY_API_KEYPOLY_PASSPHRASE
- Add an auth adapter that can validate both current
X-API-Keyand Polymarket-style L2 headers. - Bind Polymarket credentials to existing user/API-key entities.
- Enforce timestamp drift window and replay protection.
2. L1 Credential Derivation Flow (Recommended)
Add optional endpoints to derive/store L2 creds from wallet signatures to support client parity workflows. Minimum requirement for perfect-fit bots:- If credentials are already provisioned, L2 headers must work identically on trading routes.
Detailed Implementation Plan
Phase 0: Guardrails and Flags
- Add feature flags:
API_CLOB_COMPAT_ENABLED=1API_CLOB_POLY_AUTH_ENABLED=1API_CLOB_STRICT_MODE=0
- Default rollout mode:
- Keep current
/v1/*stable. - Expose compatibility routes behind flags in staging first.
- Ownership:
backend/app/api_v1/auth.py: auth adaptersbackend/app/api_v1/trading.py: trading aliases and payload parsingbackend/app/api_v1/data.py: public read aliases
Phase 1: Easy API Key Onboarding (No Wallet Required)
- Keep
/v1/keys/bootstrapand/v1/keysas primary onboarding path. - Update docs to position this as the recommended simulator-first flow.
- Add helper metadata in key responses:
compat_modes:['x-api-key', 'poly-l2-if-provisioned']recommended_headers: default toX-API-Key
- Add UI/API quick action:
- “Generate key and test /v1/health + /v1/markets in one click”
- New user can generate key and call market/account endpoints in under 60 seconds.
Phase 2: Data Model for Polymarket-Like L2 Credentials
Add storage for wallet-linked compatibility credentials while preserving existingapi_keys table.
Recommended schema additions:
- Create Alembic migration in repo for source control.
- Apply equivalent SQL in managed environments with
mcp_supabase_apply_migration. - Verify advisors after migration (
mcp_supabase_get_advisors, typesecurityandperformance).
- Never store L2 secret in plaintext.
- Encrypt
poly_secret_ciphertextwith KMS-managed envelope key. - Store
secret_kidfor key rotation.
Phase 3: Auth Adapter Implementation
- Implement
get_api_or_poly_user()dependency inbackend/app/api_v1/auth.py. - Decision tree:
- If
POLY_API_KEYheader exists, run L2 validation path. - Else fall back to
X-API-Keypath.
- L2 validation path:
- Resolve credential by
POLY_API_KEYandPOLY_PASSPHRASE. - Validate timestamp skew (recommended +/- 30s).
- Recompute HMAC signature for
(timestamp, method, path, body)canonical string. - Reject replay using
api_l2_replay_guarduniqueness.
- Map validated credential to
Userand internal permissions.
- Same trading route succeeds with either auth mode.
- Replay attempts fail with
401/400compatible error body.
Phase 4: Route Aliases and Contract Parity
- Add public read aliases in
backend/app/api_v1/data.py:
/price,/prices,/book,/books,/midpoint,/midpoints,/spread,/prices-history
- Add trading aliases in
backend/app/api_v1/trading.py:
/order,/orders, cancel endpoints,/cancel-all,/cancel-market-orders, user open orders route.
- Keep existing
/v1/*endpoints unchanged. - Ensure alias routes are mounted with expected auth behavior:
- read routes public
- trading routes authenticated
- Official client examples hit compatibility routes without payload rewrites.
Phase 5: Payload and Response Normalization
- Request parsing:
- Accept both
token_idandtokenId. - Accept both string and numeric side representations where Polymarket clients emit either.
- Accept signed-order fields even if virtual mode ignores settlement-specific fields.
- Response shape:
- Preserve canonical fields (
orderID,status,errorMsg,canceled,not_canceled). - Keep all decimal numerics as strings.
- Cancel responses:
- Return
canceledlist andnot_canceledmap consistently.
Phase 6: Lifecycle Semantics and Risk Controls
- Confirm behavior parity for
GTC,GTD,FOK,IOC/FAK. - Add heartbeat endpoint behavior compatible with bot expectations.
- Enforce cancel-only mode semantics:
- New orders rejected.
- Cancels still accepted.
Phase 7: Testing and Certification
- Contract tests:
- Replay TypeScript
@polymarket/clob-clienthappy paths. - Replay Python
py-clob-clienthappy paths.
- Negative tests:
- invalid
POLY_SIGNATURE - stale
POLY_TIMESTAMP - replayed signature
- missing required header
- Schema tests:
- camelCase and snake_case request equivalence
- string-numeric precision invariants
- Existing suite:
- Must keep
/v1/*tests green.
- Compatibility suite passes in staging.
- Existing API v1 suite remains green.
Supabase Migration Runbook
Use this in deployment docs/runbooks when applying schema changes:- Create migration SQL and apply in dev branch database.
- Validate app startup and auth flows.
- Apply to staging with
mcp_supabase_apply_migration. - Run
mcp_supabase_get_advisors:
securityperformance
- Confirm no high-severity advisor regressions.
add_api_l2_credentials_and_replay_guard
Schema Delta
1. Order Request
CurrentPOST /v1/clob/order accepts a simplified payload (token_id, side, price, size, optional fields).
Perfect-fit route must additionally accept Polymarket signed order structures used by @polymarket/clob-client and py-clob-client, including fields commonly present in signed payloads:
maker,signer,takertokenId/token_idmakerAmount,takerAmountsidenumeric or enum formnonce,expiration,saltfeeRateBpssignatureType,signature
- Accept both camelCase and snake_case aliases.
- Preserve decimal precision as strings in responses.
- Preserve canonical field names in response (
orderID,status,errorMsg, etc.).
2. Time-In-Force / Order Type
Must align with Polymarket semantics for:GTCGTD(requires expiration handling)FOKIOC/FAKbehavior where applicable
3. Errors
Normalize status codes and payloads for these classes:- auth failures (
401invalid/missing auth headers) - throttling (
429) - temporary trading states (
503disable/cancel-only style responses) - validation errors (
400structured field diagnostics)
Behavior Delta
1. Public vs Authenticated Partition
Polymarket expectation:- CLOB read endpoints are public.
- Trading endpoints require authenticated L2 headers.
- Remove API-key dependency from CLOB read-compatible routes.
- Keep existing authenticated
/v1/*routes unchanged.
2. Token-Native Primary Keys
Polymarket routes are token-centric. Action:- Prefer
token_idas first-class identifier on CLOB-compatible routes. - Continue internal condition/outcome mapping behind adapter layers.
Recommended Rollout
Phase 1: Non-breaking Alias Layer
- Add canonical CLOB routes in parallel with
/v1/*routes. - Add dual-auth adapter (
X-API-Key+ L2 headers) on new trading routes. - Add payload alias normalization (snake_case + camelCase).
Phase 2: Strict Compatibility Mode
- Add env flag (for example
API_CLOB_STRICT_MODE=1) to enforce strict Polymarket request/response contracts. - Run compatibility tests against official TS/Python client request fixtures.
Phase 3: SDK Validation Harness
- Add contract tests replaying representative client calls:
- create/post single order
- batch order submit
- cancel by ID
- cancel all
- market/token scoped cancel
- book/price/midpoint/history reads
Phase 4: Default-on Compatibility
- Enable compatibility routes by default after two stable staging releases.
- Keep
X-API-Keymode indefinitely for simulator UX simplicity.
Out of Scope Clarification
Perfect-fit in this document refers to:- HTTP endpoints
- authentication contract
- request/response schema
- order lifecycle semantics at API surface
Source Anchors (Current Implementation)
- Trading and CLOB-compatible route:
backend/app/api_v1/trading.py - Market-data routes:
backend/app/api_v1/data.py - Auth and API-key logic:
backend/app/api_v1/auth.py - Key management and WS token minting:
backend/app/api_v1/keys.py - Existing compatibility doc:
docs-site/concepts/clob-compatibility.mdx
- Polymarket docs (authentication, order lifecycle, cancel endpoints, public market data)
@polymarket/clob-clientusage patterns (createOrDeriveApiKey, post/cancel flows, heartbeat)py-clob-clientusage patterns (post/cancel/get orders compatibility)