
- Auth
- Wallet signature, then an API key derived from it. Keep the private key off the bot host if you can.
- Read
- Gamma API for markets and metadata, no auth. CLOB API for the book.
- Trade
- CLOB API, signed requests. Buys as market orders, sells as limit orders.
- Taker fee
- 0.07 x p x (1-p) per share on crypto markets. Makers pay nothing.
- Settlement
- Short crypto markets settle on a 60-second oracle average against the window open.
- Geography
- Blocks the US, UK, France and several other countries.
- Docs
- docs.polymarket.com
Five steps, simplified on purpose. The snippets show the shape of each call, not production code: no retries, no error handling, no rate-limit backoff. The official client library handles signing; the examples use it.
Install the client and derive credentials
Polymarket cut over to CLOB v2 in 2026, so use the v2 client. Credentials are derived from a wallet signature once, then reused.
pip install py-clob-client-v2 from py_clob_client.client import ClobClient HOST = "https://clob.polymarket.com" client = ClobClient(HOST, key=PRIVATE_KEY, chain_id=137, signature_type=1) creds = client.create_or_derive_api_key() # sign once, keep the result client.set_api_creds(creds)Accounts created by email use a different signature type from wallet accounts. Several types authenticate fine but only the right one sees your balance, so check the balance call before trading.
Find the market and its token ids
Gamma is the read-only catalogue. Slugs for the short crypto markets are deterministic, and a closed market disappears from slug queries but stays reachable by numeric id.
import requests GAMMA = "https://gamma-api.polymarket.com" m = requests.get(f"{GAMMA}/markets", params={"slug": "btc-updown-5m-1757500800"}).json()[0] up_token, down_token = m["clobTokenIds"] # one token per outcome market_id = m["id"] # keep this: it survives the closeRead the book
book = client.get_order_book(up_token) best_ask = float(book.asks[0].price) # what a buy pays now best_bid = float(book.bids[0].price) # what a sell gets now spread = best_ask - best_bid # skip the window if this is wideLog every read with the clock you read it on. A window without a fresh read is not a trade you could have made.
Place an order
A fill-or-kill buy must be a market order for a dollar amount with at most two decimals. Sells work as limit orders that take what is there.
from py_clob_client.clob_types import MarketOrderArgs, OrderArgs, OrderType buy = client.create_market_order(MarketOrderArgs(token_id=up_token, amount=25.00, side="BUY")) resp = client.post_order(buy, OrderType.FOK) assert resp.get("success"), resp # raise on anything else, never assume a fill sell = client.create_order(OrderArgs(token_id=up_token, price=0.90, size=30, side="SELL")) client.post_order(sell, OrderType.FAK)An order can error on the wire and still fill. Poll your trades after any exception and reconcile before the next window.
Read fills and redeem
Winnings do not redeem themselves. After settlement the shares sit in the wallet until you redeem the condition, and an unredeemed balance eventually blocks new orders.
fills = client.get_trades() # your executions, with fee paid per fill # Redemption is an on-chain call per condition id. The relayer client wraps it; # without it, claim in the web interface every day.
What to check before real money
- Confirm the fee on your first real fill matches 0.07 x p x (1-p). It did for every fill logged.
- Order minimum is 5 shares; tiny percentage stakes get rounded up or rejected.
- Rate limits are generous for one bot, but batch book reads where the API allows it.
- Rewards for makers exist on some markets and require a minimum order size, currently 50 shares. A 10-share quote earns nothing.