PASS WITH FIXESTested on Composer 2.5, , result: PASS WITH FIXES.We built this toolkit from the prompt and ran it against live public international Polymarket data (6/6 tests passing): a paper buy filled against live asks, the SDK mid (0.155) matched our book mid, and the KILL file blocked orders, with the L1 and L2 signing demos checked against the official SDK using a throwaway key. No real keys, approvals, orders or money. The prompt below includes the fixes from that run (non-yes/no sports outcomes, python3, SDK field names).
Short answer:The international Polymarket CLOB API lives at https://clob.polymarket.com, with market metadata on the Gamma API at https://gamma-api.polymarket.com. Reads need no key. Trading needs L1 auth (an EIP-712 wallet signature that creates API credentials) and then L2 auth (HMAC-signed headers). This recipe builds a Python toolkit for books, prices and fees, explains both auth levels offline, and paper-trades against the live book.
Three public hosts: Gammahttps://gamma-api.polymarket.com (markets, events), CLOBhttps://clob.polymarket.com (books, prices, orders) and Datahttps://data-api.polymarket.com (trades, positions).
Official Python SDK: pip install polymarket-client (from polymarket import PublicClient, SecureClient). py-clob-client is the older client.
L1 auth = an EIP-712 signature (domain ClobAuthDomain, chain 137) proving you control a wallet; it creates or derives your API key. L2 auth = HMAC-SHA256 headers made with that key's secret, used on every trading call.
Gotcha: raw /book lists bids ascending and asks descending, so the best price is the last element. Take the max bid and min ask.
Gotcha: fees come from each market's feeSchedule (rate × shares × p × (1−p), takers only). Live rates differ from the category table, and many markets are fee-free.
Use a dedicated hot wallet with a small balance when you ever go live. See the Wallet-Key Safety Pack.
DifficultyIntermediate
Time45–60 min
Cost$0 (public data is free; nothing is funded)
Works withClaude Code, Cursor, ChatGPT / Codex, Grok
What will you build?
A Python toolkit for the international Polymarket CLOB: list markets, read the order book the right way round, compute fees from each market's own fee schedule, understand L1 and L2 auth with offline signing demos, and paper-trade against the live book with hard limits.
Who is it for?
Builders who want the international Polymarket order book in code and want to understand the API-key flow before any wallet is involved.
Not for:Live trading. This project never posts an order, and it doesn't need a private key to run.
Polymarket CLOB API Starter: Auth Explained, Hot Wallet, Paper Mode
This is the international Polymarket counterpart to the Polymarket US API Starter Kit. It goes one layer deeper: the CLOB order book, the fee model, and how the two levels of API authentication work, all without a funded wallet. When you're ready to simulate a strategy, the paper broker here walks the live book so your fills look like real fills.
What prompt do you paste into your AI coding tool?
Works in Claude Code, Cursor, Codex/ChatGPT, Grok or any agent that can write files. Paste it into an empty folder. Read what it builds before you run anything.
You are building a READ-ONLY + PAPER Python toolkit for the international
Polymarket CLOB API. Use only endpoints documented at https://docs.polymarket.com
or methods that exist in the official `polymarket-client` SDK. If you are not
sure an endpoint, field or method exists, stop and tell me instead of guessing.
Project: polymarket-clob-starter/
- Python 3.10+ (run everything with `python3`; many systems have no
`python` command), `polymarket-client` (official SDK: `from polymarket import
PublicClient`), `requests`, `python-dotenv`, `pytest`.
- pm_data.py
- _get(url, params): requests with 429 backoff (1s, 2s, 4s, then raise).
- gamma_market(slug) -> GET https://gamma-api.polymarket.com/markets?slug=<slug>
The response is a LIST. `outcomes` and `clobTokenIds` are JSON-encoded
strings: json.loads them. Map outcome label -> token id.
Outcomes are NOT always "Yes"/"No": sports and many other markets use
team or candidate names (e.g. ["Patriots", "Bears"]). Accept an outcome
by its label (case-insensitive) or by index 0/1, and treat yes/no as
aliases for index 0/1 only. Show the real labels in every output.
- get_book(token_id) -> GET https://clob.polymarket.com/book?token_id=<id>
IMPORTANT: bids come back ascending and asks descending, so the best
level is the LAST element. Sort explicitly: bids by price desc, asks by
price asc. best_bid = max bid price, best_ask = min ask price.
Return a Quote(token_id, best_bid, best_ask, mid, spread, tick_size,
min_order_size, bids, asks) and append one JSON line per call to
logs/market_data.jsonl.
- Do NOT use GET /price to find the best bid/ask. Its side naming is easy
to misread; derive bid/ask from the book.
- list_markets(n) using PublicClient().list_markets(closed=False,
order="volume24hr", ascending=False, page_size=n).first_page().items
The `order` argument uses the Gamma camelCase name ("volume24hr"), but
the SDK returns typed models with snake_case attributes: read
`m.volume_24hr`, `m.volume_num`, `m.question`, `m.slug` (not
m["volume24hr"] or m.volume24hr). Volume can be None; print 0.
- fee_schedule(slug): read the market's own `feeSchedule` from Gamma
({rate, exponent, takerOnly, rebateRate}); `feesEnabled` false or a null
schedule means no fee. Never hardcode a category rate.
- fee_usdc(shares, price, rate, exponent=1) =
shares * rate * (price * (1 - price)) ** exponent, rounded to 5 decimals
(minimum 0.00001 when > 0). Takers only; makers pay nothing.
- auth_explain.py (OFFLINE, educational, never sends anything):
- l1_typed_data(address, timestamp, nonce=0): the EIP-712 payload with
domain {name "ClobAuthDomain", version "1", chainId 137} and message
ClobAuth {address, timestamp (string), nonce, message "This message
attests that I control the given wallet"}.
- l2_signature(secret, timestamp, method, path, body=""): urlsafe-base64
HMAC-SHA256 of timestamp+METHOD+path+body, keyed with the urlsafe-
base64-DECODED secret.
- l2_headers(...): POLY_ADDRESS, POLY_SIGNATURE, POLY_TIMESTAMP,
POLY_API_KEY, POLY_PASSPHRASE.
- Tests must check both against the SDK's own helpers using a key generated
inside the test (eth_account.Account.create()), never a real key.
- paper.py: PaperBroker that fills BUY by walking the asks and SELL by
walking the bids of a fresh live book, charges fee_usdc with that market's
rate, and writes every fill to logs/paper_ledger.jsonl.
Limits: max $10 per order, max $25 position per market, stop for the day
after $10 paper loss. Reject prices off the tick size, sizes below
min_order_size, and sells larger than the paper position (no shorting).
If a file named KILL exists in the project root, refuse every order.
- cli.py: `markets`, `market <slug>`, `book <slug> [outcome]`,
`fee <shares> <price> <rate>`, `paper <slug> <outcome> <price> <shares>`
(outcome = label, 0/1, or yes/no as aliases for 0/1).
- NEVER import or call order-placing methods (SecureClient.place_*, post
order endpoints). No private keys anywhere in this project.
- .gitignore with .env, logs/. README with setup and 4 example commands.
- pytest tests with mocked HTTP for books (including the ascending-bids
quirk), fees (100 shares at 0.50 with rate 0.07 = 1.75), paper fills,
risk limits, and a test that greps the codebase for order placement.
Show me the file plan first. After writing, tell me exactly what to run.
How do you build it, step by step?
Set up a clean folder (polymarket-clob-starter) and open it in your AI tool. Add the Safety Pack rules file and .gitignore first.
Paste the prompt and approve the file plan. Check that every URL starts with https://gamma-api.polymarket.com, https://clob.polymarket.com or https://data-api.polymarket.com.
Install and run, no key needed:
python3 -m venv .venv && source .venv/bin/activate
pip install polymarket-client requests python-dotenv pytest
python3 cli.py markets
python3 cli.py market <slug-from-the-list> # shows the real outcome labels
python3 cli.py book <slug-from-the-list> 0 # or the label, e.g. Patriots
Sanity-check the book. The best bid must be below the best ask, and the mid should match PublicClient().get_midpoint(asset_id=...). If your bid is far below the ask, your code is reading the first element of an ascending list. That's the most common bug.
Check the fee schedule with python3 cli.py market <slug>. Many markets show a zero-fee schedule; others show a rate such as 0.03 or 0.05. The fee is shares × rate × p × (1 − p), and only the taker pays it.
Paper-trade a tiny order:python3 cli.py paper <slug> 0 <price> 5 (use the outcome label or index; sports markets have team names, not Yes/No). Read the fill price, fee and ledger line. Then touch KILL and confirm the next order is refused.
Read the auth demo (python3 auth_explain.py) to see what L1 and L2 signing produce. In real trading, L1 runs once to create or derive API credentials (apiKey, secret, passphrase), and L2 HMAC headers go on every authenticated request.
Run pytest. Everything passes offline.
Before anything live, work through the Wallet-Key Safety Pack: a dedicated hot wallet, a small balance, the key in an env file outside the repo, and a plan for revoking approvals. Use the polymarket-client methods for credentials and approvals only when you're there, and check https://polymarket.com/api/geoblock from the machine that will trade.
How do you test it in paper or demo mode first?
The paper broker is the point of this recipe. It fills against the real, current order book, so a large paper order pays the same slippage a real one would. Run it for a week before you write any strategy logic:
Ledger: every fill goes to logs/paper_ledger.jsonl with the book snapshot hash, price, shares and fee.
Fees: use the market's own feeSchedule. A strategy that looks profitable at zero fees can lose money at 0.05.
Limits: $10 per order, $25 per market and a $10 daily loss stop, all enforced in code. The KILL file stops everything.
What safety checks does it need before real money?
Tick every box before the bot touches real money. The full rules file, .gitignore and pre-commit hook are in the Safety Pack.
Key handling: API keys and private-key files live in environment variables or a secrets manager. Never in code, prompts, chat logs, screenshots or git. .env and *.pem are in .gitignore, and your AI tool is blocked from reading them (see the Safety Pack).
Position limits: hard caps in config (max contracts per order, max total exposure, max daily loss). The bot refuses any order above them, and the caps are checked in code, not just in the prompt.
Kill switch: one command or one file (touch KILL) stops new orders immediately, and a second command cancels every resting order through the venue's cancel-all endpoint.
Paper first: paper or demo mode is the default. Live trading needs an explicit --live flag and a typed confirmation, and you only flip it after days of clean paper logs.
This codebase has no private key and no order placement. A test greps for place_ and order endpoints, and it must stay green.
When you go live later, use a dedicated hot wallet that holds only what the bot can lose. Never your main wallet, and never a seed phrase pasted into an AI chat.
API credentials (key, secret, passphrase) can trade for the wallet that created them. Treat them like the private key: env file outside the repo, never logged.
Trading approvals for pUSD and outcome tokens are unlimited by default. Audit and revoke them with the Wallet-Key Safety Pack when a bot is retired.
Respect the geoblock endpoint and the platform's terms. Never use a VPN or proxy to get around restrictions.
Endpoints and rules were checked against these pages on Oct 22, 2026. APIs change, so if something here disagrees with the official docs, trust the docs and tell us.
Frequently asked questions
What is the Polymarket CLOB API?
It's the central limit order book API for international Polymarket at https://clob.polymarket.com. It serves order books, prices, spreads and price history publicly, and accepts signed orders from authenticated users. Market metadata (questions, outcomes, token IDs) comes from the separate Gamma API.
What's the difference between L1 and L2 authentication?
L1 is a one-time EIP-712 signature from your wallet that proves you control it, used to create or derive API credentials. L2 uses those credentials: each trading request carries HMAC-SHA256 headers (POLY_API_KEY, POLY_SIGNATURE, POLY_TIMESTAMP, POLY_PASSPHRASE, POLY_ADDRESS). Orders are still signed by the wallet as well.
How do I get a Polymarket API key?
You derive it with an L1 signature from your trading wallet, using the SDK's credential methods or the CLOB's /auth/api-key (create) and /auth/derive-api-key (derive) endpoints. There's no web form. That's why the wallet should be a dedicated hot wallet with a small balance.
Should I use py-clob-client?
py-clob-client is the older Python client and appears in many tutorials. The current official Python SDK is polymarket-client (from polymarket import PublicClient, SecureClient), which we used here. The REST endpoints are the same, so either works for reads.
Why does my script crash on sports markets?
Sports and many other markets don't use Yes/No outcomes. Their outcomes are team or candidate names such as ["Patriots", "Bears"]. Pick the outcome by its label or its index (0 or 1), not by the word "yes". Also note the SDK returns snake_case attributes (volume_24hr), even though the order argument uses Gamma's camelCase volume24hr.
Why does my order book look wrong?
The raw /book response lists bids from lowest to highest and asks from highest to lowest, so the best price on each side is the last entry. Take the maximum bid and minimum ask instead of the first element.
How are Polymarket fees calculated?
Fee = shares × rate × p × (1 − p), charged to takers only and rounded to 5 decimals in USDC. The rate comes from each market's feeSchedule. On the day we tested, the top markets ranged from 0 (fee-free) to 0.07, so always read it per market.
The Daily Bot Recipe
One new build recipe, one safety tip, and API changes worth knowing about. Free. No picks, ever.
A tested AI prompt that builds four small wallet-safety tools for crypto and prediction-market bots: a secret scanner pre-commit hook, an env-file guard, a kill switch and a read-only wallet audit that flags balances and unlimited approvals.
A copy-paste AI prompt and step-by-step guide to the Polymarket US API: public market data with no key, then authenticated reads. Includes the international Gamma API, read-only, with a geoblock check.
A tested AI prompt that builds a Hyperliquid API starter in Python: public info reads on mainnet and testnet, then testnet-only orders signed by an API (agent) wallet, with tick rounding, a $10 minimum and a dead-man switch.