Polymarket is the largest prediction market by volume, processing billions in monthly trades across politics, crypto, sports, and world events. Its API ecosystem is the most comprehensive in the prediction market space — but it’s split across multiple services with different authentication patterns, and the official docs, while improving, still leave gaps.

This guide is the single reference for building on Polymarket. Whether you’re querying market data for a dashboard, building a trading bot, or launching a full agent that places autonomous bets, everything you need is here.

Last verified against Polymarket’s API: February 2026. We update this guide whenever the API changes. Check the Polymarket Changelog for the latest updates.


Architecture Overview

Polymarket’s API isn’t one API — it’s five distinct services, each handling a different concern. Understanding this split is essential before writing any code.

ServiceBase URLAuth RequiredPurpose
CLOB APIhttps://clob.polymarket.comPartial (trading endpoints)Order book, prices, order management
Gamma APIhttps://gamma-api.polymarket.comNoMarket discovery, metadata, events
Data APIhttps://data-api.polymarket.comNoUser positions, trade history, leaderboards
CLOB WebSocketwss://ws-subscriptions-clob.polymarket.com/ws/Optional (for user channel)Real-time orderbook and order updates
RTDSwss://ws-live-data.polymarket.comNoLow-latency crypto prices, comments

There is also a Bridge API at https://bridge.polymarket.com for deposits and withdrawals, which proxies the fun.xyz service.

The mental model: Use the Gamma API to discover markets. Use the CLOB API to read prices and trade. Use the Data API to track positions and history. Use WebSockets for real-time updates.


How Polymarket Works Under the Hood

Before diving into endpoints, you need to understand the on-chain architecture because it affects how you interact with the API.

Polymarket runs on the Polygon blockchain. Markets use the Conditional Token Framework (CTF), an ERC-1155 standard where each market outcome is a tradable token. When you “buy YES” on a market, you’re actually acquiring YES outcome tokens.

The CLOB (Central Limit Order Book) is hybrid-decentralized: order matching happens off-chain for speed, but settlement happens on-chain for security. Orders are EIP-712 signed messages — you sign a structured order with your private key, and the operator matches it off-chain, then settles the swap on-chain via the Exchange contract.

Key implications for developers:

  • You need a Polygon wallet (private key) to trade
  • USDC is the collateral asset — all positions are denominated in USDC on Polygon
  • Token IDs are critical — every market outcome has a unique token ID (not a ticker symbol)
  • Prices range from 0.00 to 1.00 — representing the probability (and cost in USDC) of that outcome
  • YES + NO prices should sum to ~$1.00 — any deviation is an arbitrage opportunity
  • Tick sizes matter — most markets use 0.01 ticks, but some use 0.001

Getting Started: Your First API Call (No Auth Required)

The fastest way to start is reading public market data. No wallet, no keys, no authentication.

Fetch All Active Markets (Gamma API)

import requests

# Fetch open markets from the Gamma API
response = requests.get(
    "https://gamma-api.polymarket.com/markets",
    params={
        "closed": False,
        "limit": 10
    }
)

markets = response.json()

for market in markets:
    print(f"{market['question']}")
    print(f"  Token ID (YES): {market['clobTokenIds']}")
    print(f"  Outcome Prices: {market['outcomePrices']}")
    print(f"  Volume: ${float(market.get('volume', 0)):,.0f}")
    print()

Get a Price (CLOB API)

# Get the current price for a specific outcome token
token_id = "<your-token-id>"  # Get this from the Gamma API response

price = requests.get(
    f"https://clob.polymarket.com/price",
    params={
        "token_id": token_id,
        "side": "BUY"
    }
)

print(f"Current buy price: {price.json()['price']}")

Get the Order Book (CLOB API)

book = requests.get(
    f"https://clob.polymarket.com/book",
    params={"token_id": token_id}
)

data = book.json()
print(f"Best bid: {data['bids'][0]['price'] if data['bids'] else 'No bids'}")
print(f"Best ask: {data['asks'][0]['price'] if data['asks'] else 'No asks'}")
print(f"Midpoint: {data.get('mid', 'N/A')}")

Authentication

Public endpoints (prices, order books, market listings) require no authentication. Trading endpoints (placing orders, canceling orders, checking your positions) require EIP-712 signed requests.

How Authentication Works

  1. You have a private key — either from an EOA (MetaMask), an email/Magic wallet, or a browser wallet
  2. You derive API credentials — the client library generates a key/secret pair from your wallet signature
  3. You sign each trading request — using L2 headers (POLY-ADDRESS, POLY-SIGNATURE, POLY-TIMESTAMP, POLY-NONCE)

Wallet Types and Signature Types

Polymarket supports three wallet configurations:

Wallet Typesignature_typefunder RequiredNotes
EOA (MetaMask)0 (default)NoDirect wallet, must set token allowances
Email / Magic wallet1Yes — your proxy addressMost common for Polymarket users
Browser wallet proxy2Yes — your proxy addressCoinbase Wallet, etc.

The funder address is the actual address holding your funds on Polymarket. When using proxy wallets, the signing key differs from the funded address.

Python Authentication Setup

from py_clob_client.client import ClobClient

HOST = "https://clob.polymarket.com"
CHAIN_ID = 137  # Polygon mainnet

# For EOA (MetaMask) users:
client = ClobClient(
    HOST,
    key="<your-private-key>",
    chain_id=CHAIN_ID
)

# For email/Magic wallet users:
client = ClobClient(
    HOST,
    key="<your-private-key>",
    chain_id=CHAIN_ID,
    signature_type=1,
    funder="<your-proxy-wallet-address>"
)

# Derive and set API credentials (do this once, then reuse)
client.set_api_creds(client.create_or_derive_api_creds())

TypeScript Authentication Setup

import { ClobClient, Side } from "@polymarket/clob-client";

const client = new ClobClient(
    "https://clob.polymarket.com",
    137,  // Polygon chain ID
    signer,  // ethers.js Signer
    creds    // API credentials
);

Rust Authentication Setup

use polymarket_client_sdk::clob::{Client, Config};
use alloy::signers::local::LocalSigner;
use std::str::FromStr;

let private_key = std::env::var("PRIVATE_KEY").expect("Need a private key");
let signer = LocalSigner::from_str(&private_key)?
    .with_chain_id(Some(137));

let client = Client::new("https://clob.polymarket.com", Config::default())?
    .authentication_builder(&signer)
    .authenticate()
    .await?;

Token Allowances (EOA Users Only)

If you’re using a direct EOA wallet (not a proxy), you must approve the Exchange contracts before trading:

# You need to approve USDC and conditional tokens for the exchange contracts
# This only needs to be done once per wallet
# See: https://docs.polymarket.com/developers/CLOB/quickstart

Proxy wallet users (email or browser wallet) do not need to set allowances — the proxy handles this.


CLOB API Reference

The CLOB API is the core trading interface. It handles prices, order books, and order management.

Public Endpoints (No Auth)

GET /price

Returns the current price for a token.

GET https://clob.polymarket.com/price?token_id=<id>&side=BUY

Parameters:

  • token_id (required) — The outcome token ID
  • side (required) — BUY or SELL

GET /midpoint

Returns the midpoint between best bid and best ask.

GET https://clob.polymarket.com/midpoint?token_id=<id>

GET /book

Returns the full order book for a token.

GET https://clob.polymarket.com/book?token_id=<id>

Response includes bids, asks, and market metadata. As of late 2025, the book endpoint also returns key market metadata fields that previously required separate Gamma API queries.

GET /books

Batch endpoint — fetch order books for multiple tokens in one request.

from py_clob_client.clob_types import BookParams

books = client.get_order_books([
    BookParams(token_id="<token-id-1>"),
    BookParams(token_id="<token-id-2>"),
])

Authenticated Endpoints (Trading)

All trading endpoints require L2 authentication headers.

POST /order — Place a Single Order

All orders on Polymarket are limit orders. Market orders are simulated by setting a marketable price against resting liquidity.

Order types:

  • GTC (Good Til Cancelled) — Rests on the book until filled or cancelled
  • FOK (Fill or Kill) — Must execute immediately and completely, or is rejected entirely
  • FAK (Fill and Kill) — Fills whatever is available immediately, cancels the rest

Place a limit order (Python):

from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY

order = OrderArgs(
    token_id="<token-id>",
    price=0.50,       # Price in USDC (0.00 to 1.00)
    size=10.0,        # Number of shares
    side=BUY
)

signed = client.create_order(order)
response = client.post_order(signed, OrderType.GTC)
print(response)

Place a market order (Python):

from py_clob_client.clob_types import MarketOrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY

market_order = MarketOrderArgs(
    token_id="<token-id>",
    amount=25.0,       # Dollar amount to spend
    side=BUY,
    order_type=OrderType.FOK
)

signed = client.create_market_order(market_order)
response = client.post_order(signed, OrderType.FOK)

Place a limit order (TypeScript):

const order = await client.createAndPostOrder(
    {
        tokenID: "<token-id>",
        price: 0.50,
        size: 10,
        side: Side.BUY
    },
    {
        tickSize: "0.01",
        negRisk: false  // true for neg-risk markets
    }
);

Post-only orders:

The postOnly flag ensures your order is added to the book as a maker order. If it would immediately match (cross the spread), it’s rejected instead of executed. This is critical for market-making strategies where you only want to earn the maker rebate.

order = OrderArgs(
    token_id="<token-id>",
    price=0.48,
    size=100.0,
    side=BUY
)

signed = client.create_order(order)
# postOnly cannot be combined with FOK or FAK
response = client.post_order(signed, OrderType.GTC, post_only=True)

POST /orders — Batch Orders

Place up to 15 orders in a single request. Essential for market makers updating multiple price levels.

orders = []
for price in [0.48, 0.49, 0.50]:
    order = OrderArgs(
        token_id="<token-id>",
        price=price,
        size=50.0,
        side=BUY
    )
    orders.append(client.create_order(order))

response = client.post_orders(orders, OrderType.GTC)

The batch limit was increased from 5 to 15 orders per call in 2025.

DELETE /order — Cancel a Single Order

response = client.cancel(order_id="<order-id>")

DELETE /orders — Cancel All Orders

response = client.cancel_all()

Gamma API Reference

The Gamma API is your market discovery layer. Use it to find markets, get metadata, and understand the structure of events.

Understanding Gamma’s Data Model

Polymarket organizes data hierarchically:

Series (e.g., "US Presidential Election")
  └── Event (e.g., "2028 Presidential Election Winner")
       └── Market (e.g., "Will Kamala Harris win?")
            └── Outcomes (YES / NO, each with a token ID)

Key Endpoints

GET /events — List Events

GET https://gamma-api.polymarket.com/events?closed=false&limit=20

Returns events with their associated markets. Each event can contain multiple markets.

GET /markets — List Markets

GET https://gamma-api.polymarket.com/markets?closed=false&limit=50

Key fields in the response:

  • question — The human-readable market question
  • clobTokenIds — Array of token IDs for each outcome (critical for trading)
  • outcomePrices — Current prices as a JSON string
  • volume — Total trading volume in USDC
  • liquidity — Current available liquidity
  • endDate — When the market resolves
  • conditionId — The on-chain condition identifier
  • slug — URL-friendly market identifier

GET /events/{id} — Get Event Details

GET https://gamma-api.polymarket.com/events/<event-id>

Returns full event details including all child markets.

GET /markets?tag= — Filter by Category

Polymarket tags markets with categories. Common tags: politics, crypto, sports, science, pop-culture.

# Get all sports markets
response = requests.get(
    "https://gamma-api.polymarket.com/markets",
    params={"tag": "sports", "closed": False}
)

Sports-Specific Endpoints

Polymarket has dedicated sports endpoints for structured sports market data:

GET https://gamma-api.polymarket.com/sports

Data API Reference

The Data API provides user-specific and aggregate analytics data.

Base URL: https://data-api.polymarket.com

Key Endpoints

GET /positions — User Positions

Returns current positions for a wallet address, including token balances and unrealized P&L.

GET /activity — User Activity

Returns trade history, deposits, withdrawals.

GET /trades — Trade History

Historical trade data for analysis and backtesting.

The Data API is fully public and requires no authentication. You can query any wallet’s positions and activity.


WebSocket API

For real-time applications — trading bots, live dashboards, arbitrage systems — the WebSocket API is essential.

Connection

wss://ws-subscriptions-clob.polymarket.com/ws/

Channels

Market Channel (Public): Orderbook updates and price changes for specific tokens.

import asyncio
import websockets
import json

async def stream_prices():
    uri = "wss://ws-subscriptions-clob.polymarket.com/ws/"

    async with websockets.connect(uri) as ws:
        # Subscribe to market updates for a specific token
        subscribe_msg = {
            "type": "subscribe",
            "channel": "market",
            "assets_id": "<token-id>"
        }
        await ws.send(json.dumps(subscribe_msg))

        async for message in ws:
            data = json.loads(message)
            print(f"Update: {data}")

asyncio.run(stream_prices())

User Channel (Authenticated): Real-time order status updates — fills, cancellations, etc. Requires authentication headers on the WebSocket connection.

Sports WebSocket

Polymarket provides a dedicated sports WebSocket feed for structured real-time sports market data.

RTDS (Real-Time Data Stream)

wss://ws-live-data.polymarket.com

A separate low-latency stream optimized for crypto price feeds and comment streams. Primarily useful for market makers who need sub-second crypto price data.


Rate Limits

Polymarket implements rate limits that vary by endpoint type. As of 2026, they’ve increased limits for CLOB endpoints.

General guidelines:

  • Public data endpoints are more generous
  • Trading endpoints have stricter limits
  • Market makers may qualify for higher limits through the Market Maker program
  • Batch endpoints (like /orders) help you stay within limits

If you’re hitting rate limits frequently, consider:

  1. Using WebSockets instead of polling for real-time data
  2. Batching order operations
  3. Caching Gamma API responses (market metadata changes infrequently)
  4. Applying for the Market Maker program for elevated limits

Key Concepts for Agent Builders

Finding Token IDs

Every market outcome has a unique token ID. This is the primary identifier you’ll use for all trading operations. You get token IDs from the Gamma API:

response = requests.get(
    "https://gamma-api.polymarket.com/markets",
    params={"slug": "will-bitcoin-hit-100k-by-2026"}
)

market = response.json()[0]
token_ids = market["clobTokenIds"]  # [YES_token_id, NO_token_id]

Understanding Neg-Risk Markets

Some Polymarket markets use a “negative risk” model where multiple outcomes share a single collateral pool. This is common in multi-outcome markets (e.g., “Who will win the election?” with 5+ candidates). When trading neg-risk markets, you need to set negRisk: true in your order parameters.

Inventory Management: Split and Merge

The Conditional Token Framework allows you to:

  • Split USDC into YES + NO token pairs
  • Merge YES + NO tokens back into USDC
  • Redeem winning tokens after market resolution

This is essential for market makers managing inventory across both sides of a market.

# Splitting: 1 USDC → 1 YES token + 1 NO token
# Merging: 1 YES token + 1 NO token → 1 USDC
# Redeem: 1 winning token → 1 USDC (after resolution)

Fees

Polymarket fees are applied symmetrically on output assets (proceeds):

  • Fees vary by market type (sports, crypto, general)
  • Maker rebates are available — makers earn USDC rebates funded by taker fees
  • Rebates are calculated per-market as of February 2026
  • Check the Maker Rebates Program documentation for current rates

Builder Program

If you’re building an application on top of Polymarket (not just a personal bot), look into the Builder Program. Builders can earn rewards for driving volume to Polymarket through their applications. The program has tiered levels based on volume contributed.


Official SDK Libraries

Polymarket maintains official client libraries:

LanguagePackageRepository
Pythonpy-clob-clientgithub.com/Polymarket/py-clob-client
TypeScript@polymarket/clob-clientgithub.com/Polymarket/clob-client
Rustpolymarket-client-sdkgithub.com/Polymarket/rs-clob-client

The Rust SDK is the newest addition and includes features like automatic heartbeats (if the client disconnects, all open orders are cancelled), cross-chain bridge support, and zero-cost abstractions with no dynamic dispatch in hot paths.

Install

# Python
pip install py-clob-client

# TypeScript
npm install @polymarket/clob-client

# Rust
cargo add polymarket-client-sdk

Putting It Together: A Minimal Trading Agent

Here’s a complete Python example that finds a market, checks the price, and places an order:

import requests
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY

# 1. Initialize authenticated client
client = ClobClient(
    "https://clob.polymarket.com",
    key="<your-private-key>",
    chain_id=137,
    signature_type=1,
    funder="<your-proxy-address>"
)
client.set_api_creds(client.create_or_derive_api_creds())

# 2. Discover a market via the Gamma API
markets = requests.get(
    "https://gamma-api.polymarket.com/markets",
    params={"closed": False, "limit": 5, "order": "volume", "ascending": False}
).json()

target = markets[0]
token_id = target["clobTokenIds"][0]  # YES token
print(f"Market: {target['question']}")
print(f"Current price: {target['outcomePrices']}")

# 3. Check the order book
book = client.get_order_book(token_id)
best_ask = float(book["asks"][0]["price"]) if book["asks"] else None
print(f"Best ask: {best_ask}")

# 4. Place a limit order below the current ask
if best_ask and best_ask > 0.05:
    my_price = round(best_ask - 0.02, 2)
    order = OrderArgs(
        token_id=token_id,
        price=my_price,
        size=10.0,
        side=BUY
    )
    signed = client.create_order(order)
    result = client.post_order(signed, OrderType.GTC)
    print(f"Order placed: {result}")

Common Patterns

Pattern 1: Price Monitoring Bot

Poll prices at an interval and trigger actions on threshold changes.

import time

def monitor_market(token_id, threshold_low, threshold_high):
    while True:
        mid = client.get_midpoint(token_id)
        price = float(mid)

        if price < threshold_low:
            print(f"ALERT: Price dropped to {price} — buying opportunity")
            # Place buy order logic here

        if price > threshold_high:
            print(f"ALERT: Price rose to {price} — selling opportunity")
            # Place sell order logic here

        time.sleep(5)  # Check every 5 seconds

Pattern 2: Cross-Market Arbitrage Scanner

Check if YES + NO prices deviate from $1.00 across markets.

def scan_arb_opportunities():
    markets = requests.get(
        "https://gamma-api.polymarket.com/markets",
        params={"closed": False, "limit": 100}
    ).json()

    for market in markets:
        prices = market.get("outcomePrices")
        if prices:
            try:
                parsed = [float(p) for p in prices.strip("[]").split(",")]
                total = sum(parsed)
                if total < 0.98 or total > 1.02:
                    print(f"ARB: {market['question']}")
                    print(f"  Prices sum to: {total:.4f}")
                    print(f"  Gap: {abs(1.0 - total):.4f}")
            except (ValueError, IndexError):
                continue

Pattern 3: WebSocket + LLM Agent

Stream market updates and feed them to an LLM for analysis.

import asyncio
import websockets
import json

async def agent_loop():
    uri = "wss://ws-subscriptions-clob.polymarket.com/ws/"

    async with websockets.connect(uri) as ws:
        # Subscribe to multiple markets
        for token_id in watched_tokens:
            await ws.send(json.dumps({
                "type": "subscribe",
                "channel": "market",
                "assets_id": token_id
            }))

        async for message in ws:
            data = json.loads(message)
            # Feed price update to your LLM/agent for analysis
            # agent.analyze(data)
            # If the agent recommends a trade, execute via CLOB API

Security Considerations

Building autonomous agents that handle real money demands careful security practices. See our Security Best Practices for Agent Betting guide for the full treatment. Key points:

  • Never hardcode private keys — use environment variables or a secrets manager
  • Use spending limits — configure your wallet with maximum position sizes
  • Implement kill switches — your bot should have a way to cancel all orders and stop trading instantly
  • Guard against prompt injection — if using LLMs, sanitize all market data before feeding it to the model
  • Test on small amounts first — Polymarket has no demo/testnet environment, so start with minimal positions
  • Monitor the heartbeat — the Rust SDK supports automatic heartbeats that cancel all orders if your client disconnects

Troubleshooting

“Order rejected” errors:

  • Check that your price aligns with the market’s tick size (usually 0.01)
  • Ensure you have sufficient USDC balance
  • For EOA wallets, verify token allowances are set
  • If using postOnly, your order may be crossing the spread

Authentication failures:

  • Verify your signature_type matches your wallet type
  • Ensure the funder address is correct for proxy wallets
  • API credentials may need to be re-derived if you get 401 errors

Rate limit errors:

  • Switch from polling to WebSockets for real-time data
  • Batch order operations using the /orders endpoint
  • Cache Gamma API responses (market metadata is stable)

Missing token IDs:

  • Token IDs come from the Gamma API, not the CLOB API
  • Use the clobTokenIds field from the /markets endpoint
  • Some markets may have their token IDs in a nested structure

Official Resources


Where This Fits in the Agent Betting Stack

This guide covers Layer 3 (Trading) of the Agent Betting Stack. Polymarket’s API is the execution layer — where your agent converts intelligence into positions.

To build a complete autonomous agent, you also need:


This guide is maintained by AgentBets.ai. Found an error or API change we missed? Let us know on Twitter.

Not financial advice. Built for builders.