The Polymarket API: A Developer's Guide (2026)

The Polymarket API: A Developer's Guide (2026)

The Polymarket API is not one API. It is four REST surfaces plus a WebSocket feed, each on its own host, each with its own data model. Gamma serves market and event metadata, CLOB serves order books and prices, the Data API serves on-chain user positions and trades, and a leaderboard surface serves all-time PnL and volume rankings. A WebSocket channel pushes real-time book and price updates on top of CLOB.

Most integrations break not because the endpoints are hard, but because two or three undocumented details — the meaning of the side parameter, the ordering of order-book arrays, the fact that prices arrive as JSON strings — silently invert your numbers. This guide maps every API, gives you a correct snippet for each, and spells out the parts the docs gloss over. All hosts and behaviors below were checked against the official documentation at docs.polymarket.com as of 2026.

The Four Polymarket APIs

Each API is fully public for read access; Gamma and the Data API require no authentication at all, and CLOB's market-data endpoints are public (only order placement is authenticated). Start here, then jump to the section you need.

APIBase URLWhat it does
Gammahttps://gamma-api.polymarket.comMarkets, events, tags, series, search, public profiles — discovery and metadata
CLOBhttps://clob.polymarket.comOrder books, prices, midpoints, spreads — live pricing
Data APIhttps://data-api.polymarket.comUser positions, trades, activity, portfolio value, top holders
Leaderboardhttps://data-api.polymarket.comTrader rankings by PnL and volume (served via the Data API surface)
WebSocketwss://ws-subscriptions-clob.polymarket.com/ws/Real-time order-book snapshots and price changes (market and user channels)

One note on the leaderboard: older integrations used a standalone lb-api host. As of 2026 the official docs expose trader leaderboard rankings through the Data API host, so treat the leaderboard as a Data API surface rather than a separate base URL. Verify against the docs before hardcoding a host.

Gamma API: Markets and Events

Gamma answers the question "what markets exist and what do they look like?" It is the metadata layer: titles, descriptions, end dates, volume, the token IDs you need for pricing, and search. Base URL is https://gamma-api.polymarket.com, and it is fully public.

The two endpoints you will use constantly are /markets and /events. An event groups one or more markets (a single "2026 election" event can contain dozens of candidate markets). You can fetch by slug:

curl "https://gamma-api.polymarket.com/events?slug=fed-decision-in-october" \
  -H "User-Agent: my-app/1.0"

For discovery, the Gamma search endpoint (/public-search) takes a q query string and returns matching markets, events, and profiles in one response:

curl "https://gamma-api.polymarket.com/public-search?q=bitcoin" \
  -H "User-Agent: my-app/1.0"

The two Gamma details to remember

First, outcome prices come back as a JSON-encoded string, not an array. A market object exposes outcomePrices as something like "[\"0.62\", \"0.38\"]". You have to JSON.parse it before indexing. Same pattern for outcomes and clobTokenIds. Reading market.outcomePrices[0] directly gives you the character [, not the price.

const res = await fetch(
  "https://gamma-api.polymarket.com/markets?slug=some-market",
  { headers: { "User-Agent": "my-app/1.0" } }
);
const [market] = await res.json();
const prices = JSON.parse(market.outcomePrices);   // ["0.62", "0.38"]
const tokenIds = JSON.parse(market.clobTokenIds);  // ["123...", "456..."]

Second, send a User-Agent header. Gamma fingerprints clients and will refuse requests from some default agents (bare scripting libraries with no UA). A real UA string avoids intermittent blocks. This is not in most quickstarts and costs people hours.

CLOB API: Order Books and Prices

CLOB answers "what is this token worth right now?" Base URL is https://clob.polymarket.com. Everything keys off a token_id — the per-outcome asset ID you pulled from Gamma's clobTokenIds. A binary market has two token IDs (YES and NO), each with its own order book.

The core read endpoints:

  • GET /book?token_id=... — full order book (bids and asks)
  • GET /price?token_id=...&side=buy — best price for one side of the book
  • POST /prices — batch pricing for many token/side pairs in one request
  • GET /midpoint?token_id=... — the average of best bid and best ask
curl "https://clob.polymarket.com/price?token_id=123456789&side=buy"

The official SDKs (@polymarket/clob-client for TypeScript, py-clob-client for Python) wrap these as getPrice(tokenID, side), getOrderBook(tokenID), getPrices(params), and getMidpoint(tokenID).

The side Parameter Gotcha

This is the single detail that breaks the most CLOB integrations, so read it twice.

The side parameter describes a side of the order book, not your intended action. side=buy (or BUY) returns the best bid — the highest price someone is currently willing to pay. side=sell (or SELL) returns the best ask — the lowest price someone is willing to sell at. If you reach for side=buy thinking "the price I pay to buy," you get the wrong number: you actually pay the ask, which is side=sell. The naming reads as your action; the value is the opposite book level.

The second half of the gotcha lives in the /book arrays. In the live response, the best price is not the first element. Bids come back ascending and asks come back descending, which means the best bid and the best ask both sit at the end of their arrays — index [length - 1], not [0].

const book = await fetch(
  "https://clob.polymarket.com/book?token_id=123456789"
).then(r => r.json());

const bestBid = book.bids[book.bids.length - 1].price; // highest bid, last element
const bestAsk = book.asks[book.asks.length - 1].price; // lowest ask, last element

A caveat worth flagging: the API reference describes /book as sorting bids descending and asks ascending (best first). Observed production responses put the best at the tail. Do not trust either the docs or this guide blindly — sort the arrays yourself by price and take the extreme you actually want. Math.max over bid prices and Math.min over ask prices is ordering-proof and survives any future change.

Finally, a property of binary markets that simplifies sanity checks: the YES and NO books are complementary. The best bid on YES equals one minus the best ask on NO (best_bid(YES) = 1 − best_ask(NO)). If those two numbers drift apart by more than the spread, your token IDs are crossed.

Data API: Positions, Trades and PnL

The Data API answers "what has this wallet done?" Base URL is https://data-api.polymarket.com, fully public, keyed by the on-chain user profile address (the proxy wallet, 0x-prefixed). This is the surface you use to track Polymarket whales, reconstruct a portfolio, or audit fills.

The endpoints map cleanly to questions:

  • GET /positions?user=0x... — current open positions per market
  • GET /trades?user=0x... — historical fills
  • GET /activity?user=0x... — combined activity feed (trades, splits, merges, redeems)
  • GET /value?user=0x... — total current USD value of open positions
  • GET /holders — top holders for a market (capped per token)
curl "https://data-api.polymarket.com/positions?user=0xYourProxyWalletAddress"

For rankings, the leaderboard surface (served via the same Data API host) returns traders ordered by profit or volume over a time window, with fields like proxyWallet, userName, pnl, and vol. That is the raw material behind any verified leaderboard of prediction-market traders.

# Trader leaderboard rankings (window: e.g. ALL, MONTH, WEEK, DAY)
curl "https://data-api.polymarket.com/profit?window=all&address=0x..."

A practical note: PnL here is on-chain realized-plus-unrealized derived from positions and fills. It is the right source for "how much has this wallet made," but the exact windowing and rounding are Polymarket's, so do not expect it to match a number you computed a different way. Treat it as authoritative, not as one input among many.

WebSockets: Real-Time Prices

REST is for snapshots; the WebSocket is for keeping a book live. Connect to wss://ws-subscriptions-clob.polymarket.com/ws/ and subscribe to the market channel (public, order-book and price updates) or the user channel (authenticated, your own order status).

const ws = new WebSocket(
  "wss://ws-subscriptions-clob.polymarket.com/ws/market"
);

ws.onopen = () => {
  ws.send(JSON.stringify({ assets_ids: ["123456789"], type: "market" }));
};

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  // "book" = full snapshot, "price_change" = incremental updates
};

The channel emits two message types that matter: a book snapshot when you subscribe (and periodically), and price_change messages for incremental updates between snapshots. Polymarket reworked the price_change schema so updates arrive as objects rather than raw field lists — if you are porting old code, expect the shape to differ. The correct pattern is: pull a REST /book snapshot to seed state, then apply price_change deltas from the socket, and reconcile against periodic book snapshots to catch any missed message.

The Hard Parts Nobody Documents

A recap of the details that cost real time, in one place:

  • side is the book side, not your action. side=buy returns the best bid, side=sell returns the best ask. Buying fills at the ask.
  • Best price is at the array tail. In live /book responses, bids and asks are ordered so the best sits at [length - 1]. Sort by price yourself instead of trusting index [0].
  • Gamma prices are JSON strings. outcomePrices, outcomes, and clobTokenIds are string-encoded arrays. Parse before you index.
  • Gamma needs a User-Agent. Requests without a real UA get intermittently blocked.
  • Binary books are complementary. best_bid(YES) = 1 − best_ask(NO). Use it as a correctness check.
  • Rate limits exist; back off. Read endpoints are generous but not infinite. Handle 429 with exponential backoff and page large result sets rather than hammering for the full history at once. (Treat any specific limit number as version-dependent — confirm against the current docs.)

How to Get Started

  1. Pick the right API: Gamma for market metadata, CLOB for prices/order books, Data API for positions and trades.
  2. Resolve the token IDs: get a market's clobTokenIds from Gamma before querying CLOB.
  3. Read prices correctly: remember side=buy returns the bid and side=sell the ask; best is the last array element.
  4. Subscribe to WebSockets for real-time: poll REST for snapshots, use the CLOB socket for live updates.
  5. Handle rate limits and pagination: back off on 429s and page large result sets.

Build vs Buy: When to Aggregate Instead

Here is the honest version. Wiring up the Polymarket API is a weekend. Keeping it correct in production is not. You are maintaining four REST surfaces plus a WebSocket, reconciling snapshot-and-delta state, normalizing string-encoded prices, parsing the side semantics into something your code can reason about, and deriving on-chain PnL from raw positions and fills. Then a schema changes — like the price_change migration — and you are debugging inverted numbers in a live dashboard.

For a single read-only widget, build it. For anything that needs trader analytics, real-time pricing across many markets, or a unified view of more than one venue, the math shifts toward consuming an aggregator. FrenFlow already does this work — aggregating prediction markets across Polymarket, Kalshi, Hyperliquid, and Predict.fun behind one normalized model, with a verified leaderboard and non-custodial copytrading on top. The same aggregation layer is why FrenFlow powers DEXTools' predictions. If your goal is to ship a product rather than maintain market-data plumbing, the aggregator is usually the shorter path. For copy-execution specifically, see our Polymarket copy trading breakdown.

Frequently Asked Questions

Does Polymarket have a public API?

Yes. Polymarket exposes several public REST APIs plus a WebSocket feed. The Gamma API (gamma-api.polymarket.com) and Data API (data-api.polymarket.com) require no authentication for reads, and the CLOB API's market-data endpoints (clob.polymarket.com) are public — only order placement is authenticated.

Is the Polymarket API free?

Yes, the read endpoints are free and require no API key. Gamma and the Data API are fully public; CLOB pricing and order-book data are public as well. Reasonable rate limits apply, so use backoff and pagination. Authenticated trading (placing orders) requires CLOB API credentials.

What is the difference between the Gamma and CLOB APIs?

Gamma is the metadata layer — it tells you which markets and events exist, their titles, descriptions, volume, and the token IDs for each outcome. CLOB is the pricing layer — given a token ID, it returns the live order book, best prices, and midpoints. You typically query Gamma first to discover a market and its clobTokenIds, then query CLOB with those IDs to get prices.

How do I get Polymarket prices via API?

Fetch a market's clobTokenIds from the Gamma API, then call the CLOB /price endpoint with a token_id and a side. Remember that side=buy returns the best bid and side=sell returns the best ask — so the price you pay to buy is the side=sell value. For the full order book, call /book, and sort by price to find the best bid and ask rather than assuming the first array element.

Can I get a trader's PnL from the Polymarket API?

Yes. The Data API exposes a wallet's positions, trades, and total portfolio value keyed by the on-chain proxy wallet address, and the leaderboard surface returns traders ranked by profit and volume over a chosen time window. Use the proxy wallet address (not a username) as the key, and treat the returned PnL as Polymarket's authoritative on-chain figure.


The Polymarket API rewards developers who respect its quirks: parse the strings, send the header, read the book side correctly, and seed your WebSocket from a REST snapshot. Get those four right and the rest is straightforward REST. When the maintenance burden of four APIs plus normalization outgrows the feature you are shipping, an aggregator that has already solved it — across multiple venues — is the pragmatic move.

FrenFlow Team

FrenFlow Team

Prediction Markets Experts

Building the future of Polymarket copy trading. We help traders discover opportunities and automate their prediction market strategies.

Ready to copy trade like a pro?

Follow the best Polymarket wallets. Auto-copy every position. Same block execution.

Start Copying Now

Copy Top Predictors

Block 0 execution on FrenFlow

Get Started