Polymarket looks like a normal exchange from the user side — click buy, click sell, see your P&L. Under that surface, it's a stack of four very different technologies bolted together: conditional tokens on Polygon, USDC for collateral, a central limit order book run by Polymarket's operator, and UMA's optimistic oracle for resolution. If you want to build on Polymarket, integrate it as a data source, or just reason about its failure modes, you need a real model of what each layer does.
This post is the engineering-level explainer. We'll walk top-to-bottom: what a market actually is on-chain, how orders match, how money moves, how outcomes get decided, and where the pitfalls are.
The atomic unit on Polymarket is not "a bet." It's a pair of ERC-1155 conditional tokens deployed via Gnosis's Conditional Tokens Framework (CTF). For any binary market — say, "Will the Lakers win the 2026 NBA Championship?" — the smart contract mints two distinguishable tokens:
Crucially, 1 YES + 1 NO = 1 USDC of collateral, always. This invariant is what makes a prediction market self-pricing: anyone with 1 USDC can mint one of each token (called "splitting") and sell them; anyone holding one of each can "merge" them back into 1 USDC. The arbitrage forces YES price + NO price to stay close to 100¢ in liquid markets.
Each token has a unique tokenId — a uint256 derived from the condition's question hash and the outcome index. This ID is what every API call and order references. The conditional tokens are ERC-1155 rather than ERC-20, which means a single contract holds positions for thousands of markets simultaneously, and you can transfer multiple positions in one call.
# Pseudocode for getting your position
positions = ctf_contract.balanceOfBatch(
owners=[wallet_address] * len(token_ids),
ids=token_ids
)
Gotcha: Polymarket's "neg-risk" markets (multi-outcome events like "Which team wins the Super Bowl?") wrap the underlying CTF tokens in a separate adapter (NegRiskAdapter), and the on-chain token IDs you trade in the CLOB do not match the IDs you redeem. We'll cover this in the redemption section.
All collateral, fees, and payouts on Polymarket are denominated in USDC — the US-dollar-pegged stablecoin issued by Circle. Polymarket uses the Polygon network (a PoS Ethereum L2) for settlement, which is why fees are pennies and confirmation is sub-second.
For a developer building a bot, the practical consequences:
Account funding works like any DEX: you deposit USDC into Polymarket's contract (the deposit creates an entry in their off-chain order book system), then trade. Withdrawals settle back to your wallet on-chain.
For trading via the API, Polymarket uses a Gnosis Safe proxy pattern. Your EOA (externally-owned account, the regular wallet from your seed phrase) is the signer, but the actual holder of positions is a 1-of-1 Safe proxy deployed for you. This separation is what lets the off-chain order book operator submit orders on your behalf without ever holding your funds.
# .env config for proxy trading
POLY_PRIVATE_KEY=0x... # EOA private key (signer)
POLY_SIG_TYPE=2 # 0=EOA, 1=POLY_PROXY, 2=POLY_GNOSIS_SAFE
POLY_FUNDER=0x... # The Safe address (holder)
When you sign an order, SIG_TYPE=2 tells the matching engine to verify your signature against the Safe's single-owner permission, not the EOA's direct ownership of the tokens.
Polymarket runs an off-chain order book operated by its central matching engine. This is the part that doesn't live on-chain — on-chain matching would be too slow and too expensive for the cadence of sports trading. The on-chain layer is reserved for settlement: once two orders match off-chain, the matching engine submits an on-chain transaction that exchanges tokens between the two parties' Safes.
From an API perspective the CLOB looks like Binance or Coinbase Advanced:
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137, # Polygon mainnet
key=os.getenv("POLY_PRIVATE_KEY"),
funder=os.getenv("POLY_FUNDER"), # Safe proxy address
signature_type=2, # Safe signature
)
client.set_api_creds(client.create_or_derive_api_creds())
# Buy 100 YES shares at 45c
order = client.create_order(OrderArgs(
token_id=lakers_yes_token_id,
price=0.45,
size=100,
side="BUY",
))
resp = client.post_order(order, OrderType.GTC) # Good-til-canceled
The matching engine handles partial fills, time-in-force (GTC, GTD, FOK), and a queue of orders by price-time priority. When two orders cross, the on-chain settlement is batched with other matches for gas efficiency — sub-second under normal load.
Polymarket charges taker fees on most markets. As of 2026, the standard configuration is:
For a sharp trader, the maker/taker split matters enormously: posting passive liquidity (resting orders that get hit) is cost-free, while taking liquidity (market orders or limit orders that cross the spread) costs 2¢. On a 60¢ market that's a 3.3% one-way cost — before any model edge. Edge scanning on Polymarket has to account for this in the gate.
Polymarket exposes WebSocket streams for both market data (price book, last trades) and user data (your order updates, fills). The market feed is what bots subscribe to for real-time decision-making.
import asyncio
import websockets, json
async def stream(token_ids):
async with websockets.connect("wss://ws-subscriptions-clob.polymarket.com/ws/market") as ws:
await ws.send(json.dumps({
"auth": {}, # market channel is unauthenticated
"type": "Market",
"markets": token_ids, # list of CLOB token IDs
}))
async for msg in ws:
ev = json.loads(msg)
if ev["event_type"] == "price_change":
print(ev["asset_id"], ev["changes"])
Practical notes: market WebSockets occasionally drop, especially during high-volume sports events. A production bot needs a reconnection loop with state recovery (re-fetch top-of-book on reconnect; don't trust your in-memory state). It's also wise to combine WebSocket data with periodic REST snapshots (every 30-60 seconds) for consistency checking.
The hardest part of any prediction market is deciding what actually happened. Polymarket outsources this to UMA's Optimistic Oracle, a decentralized resolution mechanism that works on a "propose, dispute if needed" basis.
Flow:
For 95%+ of markets — "Did the Lakers win?", "Did Trump win the election?" — the outcome is uncontested and resolution is automatic within hours of the event. The other 5% are messy: ambiguously-worded markets, edge cases ("Did the player start the game?"), late-breaking schedule changes, or genuinely disputed outcomes. These can take days to resolve and have occasionally produced controversial decisions when the literal text of the market disagrees with the "obvious" intent.
Trader takeaway: always read the resolution criteria before trading. The text is what UMA resolves on, not your interpretation of the event. We've seen markets resolve "wrong" by intuition but "right" by the literal rules — and the literal rules are what UMA enforces.
For markets with more than two outcomes (e.g., "Which team wins the Super Bowl?"), Polymarket uses a negative-risk adapter. Each outcome is its own binary market (YES = "this team wins", NO = "this team doesn't"), but they're linked: exactly one YES across all outcomes will resolve true, the rest resolve false.
For a bot, the consequences are:
NEG_RISK_ADAPTER = "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296"
# Use this contract to redeem winnings on neg-risk markets, NOT the bare CTF.
Putting all four layers together, here's the lifecycle of a single trade on Polymarket:
From signal to redemption is typically 2-6 hours for a sports market; an open-ended election market can take months. The bot's job is to keep state across this whole lifecycle — track which trades are settled, which are pending, which need to be redeemed manually.
Once you understand the four layers, the surface area is huge:
The deeper insight: Polymarket is one of the few venues where a small developer with a good model and a $1k account can compete on roughly equal terms with institutional capital. There are no minimum sizes, no sharp-account restrictions, no "VIP rebates" only the whales get. The order book is the order book; if your edge is real, the venue will pay you for it.
ZenHodl publishes calibrated win probability APIs for 10+ sports — the model layer that drives our own Polymarket trading bots. If you want to focus on strategy, not on building the CLOB integration from scratch, the API is your shortcut.
See API Docs →