API · Reference

The CLOB (Central Limit Order Book) at clob.polymarket.com is where orders rest and match. You read the book, prices and tick size with no auth, and trade (place / cancel orders, read your balance) with API credentials and signing. This is the CLOB V2 reference: collateral is pUSD, fees are on-chain, and makers pay zero.

Read the order book (no auth)

from py_clob_client_v2 import ClobClient   # pip install py-clob-client-v2
client = ClobClient(host="https://clob.polymarket.com", chain_id=137)   # read-only: no key
book = client.get_order_book(token_id)
mid  = client.get_midpoint(token_id)
print(book.bids[0].price, book.asks[0].price, mid)
// polymarket_client_sdk_v2 (official, repo rs-clob-client-v2)
use polymarket_client_sdk_v2::clob::{Client, Config};
use polymarket_client_sdk_v2::clob::types::request::OrderBookSummaryRequest;
let client = Client::new("https://clob.polymarket.com", Config::default())?;
let book = client.order_book(&OrderBookSummaryRequest::builder().token_id(token_id).build()).await?;
curl -s "https://clob.polymarket.com/book?token_id=$TOKEN_ID"

Sample response

{
  "market": "0x...",
  "bids": [ { "price": "0.62", "size": "1400" }, { "price": "0.61", "size": "900" } ],
  "asks": [ { "price": "0.64", "size": "1100" }, { "price": "0.65", "size": "2000" } ]
}

Read endpoints

EndpointReturns
GET /book?token_id=Full order book (bids / asks).
GET /price?token_id=&side=Best bid or ask.
GET /midpoint?token_id=Mid = (best bid + best ask) / 2.
GET /spread?token_id=Best ask − best bid.
GET /tick-size?token_id=Minimum price increment (round your price to it).

Limits are high: CLOB ~9,000 requests / 10s, /book and /price 1,500 / 10s, and over-limit requests are throttled, not rejected. More on 429s.

Place & cancel an order (auth)

One call builds, signs (the V2 order struct) and posts your order. You choose an order type:

TypeBehaviour
GTCGood-Till-Cancelled: rests on the book until filled or cancelled.
GTDGood-Till-Date: rests until an expiry timestamp.
FOKFill-Or-Kill: fill the whole order immediately or cancel it.
FAKFill-And-Kill: fill what it can immediately, cancel the rest.
from py_clob_client_v2 import (ClobClient, OrderArgs, OrderType,
                               PartialCreateOrderOptions, Side, OrderPayload)

# authenticated client (creds from create_or_derive_api_key - see Authentication)
client = ClobClient(host="https://clob.polymarket.com", chain_id=137, key=PK, creds=creds)

resp = client.create_and_post_order(
    order_args=OrderArgs(token_id=token_id, price=0.62, side=Side.BUY, size=10),
    options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False),  # read both off the market
    order_type=OrderType.GTC,            # GTC, GTD, FOK or FAK
)
# resp -> {"success": true, "orderID": "0x...", "status": "live"}
client.cancel_order(OrderPayload(orderID=resp["orderID"]))   # cancel
Two per-market settings. Pass the market's real tick_size ("0.01" or "0.001") and set neg_risk=True for multi-outcome "negative risk" markets - read both off Gamma (orderPriceMinTickSize, negRisk) before signing. Also: minimum order size is 5 shares, and your price must already be rounded to the tick or the order is rejected.
V2 order facts. The signed struct dropped nonce, feeRateBps, taker and expiration and added timestamp, metadata and builder; the Exchange EIP-712 domain version is "2". Fees are collected on-chain at match: makers pay 0, only takers pay. Before trading you must approve pUSD + conditional tokens to the three V2 contracts (see the allowance fix).

Fees: only takers pay, and the rate curves

Makers are never charged. Takers pay a fee that is not flat - it scales with the market's uncertainty and varies by category. The formula:

fee = shares × feeRate × p × (1 - p)      # p = share price, 0..1

The p·(1-p) term means the fee peaks at 50/50 and shrinks toward the 1¢ and 99¢ edges - so a near-certain outcome is cheap to take, a coin-flip is dear. Per-category taker feeRate:

CategoryTaker feeRate
Crypto0.07 (7 bps) - the highest
Economics / Culture / Weather0.05
Finance / Politics / Tech / Mentions0.04
Sports0.03
Geopolitics & world events0 - fee-free

Read the live rate per token with GET /fee-rate-bps?token_id= rather than hardcoding it; fees round to 5 decimals (min 0.00001 pUSD). Makers paying zero is why most edge-free bots quote rather than take.

Negative-risk (multi-outcome) markets

Multi-candidate events ("who wins the election?") are neg-risk markets: their outcomes are linked, so a No share in one outcome converts into a Yes share in every other through the Neg Risk Adapter - capital-efficient, but mechanically different. They run on different contracts from binary markets, so you must pass neg_risk=True in the order options (read the market's negRisk flag off Gamma). Omit it and the order is signed against the wrong exchange and rejected.

Conditional tokens: split, merge, redeem (beyond the book)

Underneath every market is the Conditional Token Framework (CTF). Outcome tokens are ERC-1155 tokens, and every Yes/No pair is backed by exactly $1.00 of pUSD locked in the CTF contract. That gives you three primitives the order book alone does not:

OperationWhat it doesWhy a bot uses it
SplitLock $1 pUSD → mint 1 Yes + 1 NoCreate inventory without crossing the spread; quote both sides.
MergeBurn 1 Yes + 1 No → recover $1 pUSDExit a hedged pair instantly - no resolution wait, no taker fee.
RedeemAfter resolution, winning token → $1.00 pUSDCash out a resolved position (redeemPositions).

Split and merge are the basis of CTF arbitrage: if Yes + No trade below $1.00 on the book, buy both and merge back to $1.00; if they trade above $1.00, split $1 into a fresh pair and sell both. Redemption settles through the ConditionalTokens contract once the oracle posts the outcome on-chain - a position shows redeemable: true on the Data API when it is claimable. Position IDs derive via getConditionIdgetCollectionIdgetPositionId.

Advanced: RFQ & combo markets (for serious makers)

Beyond the order book, Polymarket runs a Request-for-Quote (RFQ) system, used especially for combo markets - existing markets bundled into multi-leg composite positions. The flow has three phases: a taker requests a quote, makers compete with quotes, and the chosen maker gets a last look to confirm or decline before execution.

  • Discover combos: GET /v1/rfq/combo-markets (public; limit 1-100, cursor, exclude). Each combo exposes two position IDs (Yes = index 0, No = index 1).
  • Quote as a maker: POST combos-rfq-api.polymarket.com/v1/maker/quotes (L2 auth). You generate the quote_id yourself, and send rfq_id, maker_address, signature_type, a signed Exchange order, and price_e6 / size_e6 as six-decimal fixed-point strings (the *_e6 convention avoids float precision loss).
  • Last look: while the RFQ is AWAITING_MAKER_CONFIRMATION, respond CONFIRM, DECLINE, or let it TIMED_OUT.

RFQ state machine: CREATED → COLLECTING_QUOTES → AWAITING_REQUESTER_ACCEPTANCE → AWAITING_MAKER_CONFIRMATION → EXECUTING → FILLED (else FAILED / EXPIRED / CANCELED / REJECTED). Subscribe to the RFQ WebSocket gateway for live state. This is niche - most bots only need the CLOB book above - but it is how multi-leg and combo liquidity gets priced.

Check balance & allowance

client.get_balance_allowance(...)   # collateral (pUSD) and conditional-token allowances

If this shows zero allowance, approve pUSD/CTF to the V2 exchange contracts before ordering.

Yes / No token IDs. Each binary market has two token IDs. Don't hardcode which is Yes. Read the parsed outcomes array (Gamma returns it, and clobTokenIds, as JSON-encoded strings you must decode) and map by name.

Next: Authentication & wallets · WebSocket: stream the book · Fix a CLOB error.