The Polymarket Gamma API is Polymarket Global’s read-only market discovery layer at https://gamma-api.polymarket.com — no authentication, no API key. Use /events and /markets to list, /public-search?q= for keyword search (the parameter is q — query= returns 422), and read clobTokenIds off a market to get the token IDs you need for CLOB trading. Rate limits are 4,000 requests per 10s overall, with /markets at 300/10s, /events at 500/10s, and /public-search at 350/10s. Polymarket US does not serve Gamma — its equivalent is https://gateway.polymarket.us/v1/search?query=.
curl -s "https://gamma-api.polymarket.com/markets?closed=false&active=true&limit=5"
Endpoints verified against the live API on 2026-08-30.
Overview
Gamma indexes every event, market, tag, and sports category on the platform, and you can start querying it immediately without credentials.
Use the Gamma API to:
- Discover markets by category, volume, liquidity, or keyword search
- Get token IDs and condition IDs needed for CLOB trading
- Build scanners that surface high-volume or mispriced markets
- Retrieve event structures to understand how multi-outcome questions decompose into binary markets
The Gamma API is read-only. It does not support placing orders, streaming prices, or querying on-chain balances. For those capabilities, you need the CLOB API, WebSocket feeds, or the Subgraph.
When to Use Which API
Polymarket exposes several APIs, each optimized for a different use case. The Gamma API is the starting point for nearly every workflow because it is where you discover markets and retrieve the identifiers needed by other APIs.
| Need | API | Endpoint |
|---|---|---|
| Find markets and events | Gamma | /events, /markets, /public-search |
| Get real-time prices and orderbooks | CLOB | /price, /book |
| Place and manage orders | CLOB | /order, /orders |
| Get price history for backtesting | CLOB | /prices-history |
| Get user positions and trades | Data | /positions, /trades |
| Get on-chain token balances | Subgraph | GraphQL query |
A typical workflow looks like this: query the Gamma API to find a market, extract its token IDs, then pass those token IDs to the CLOB API for live prices, order placement, or historical data.
Data Model
Understanding the relationship between Events and Markets is essential before working with any endpoint.
Events
Events are top-level questions. An event like “Who will win the 2024 Presidential Election?” groups together all the individual tradable outcomes under a single umbrella.
Each event has:
- A unique numeric ID and a URL-friendly slug
- A title and description describing the question
- One or more Markets as sub-outcomes
- Tags for categorization (e.g., “politics”, “crypto”, “sports”)
- Metadata like
startDate,endDate, andvolume
Markets
Markets are the tradable binary outcomes within events. Each market represents a single Yes/No question with its own order book and pricing.
Each market has:
conditionId— the unique identifier for CTF (Conditional Token Framework) contracts on-chainquestionId— a hash of the market question used by the resolution oracleclobTokenIds— an array of two token IDs, one for the Yes outcome and one for No (ERC-1155 tokens)outcomesandoutcomePrices— parallel arrays mapped 1:1, sooutcomes[0]corresponds tooutcomePrices[0]enableOrderBook— a boolean indicating whether CLOB trading is available for this marketvolume— total trading volume in USDCliquidity— current liquidity depth
A single event can contain many markets. For example, an election event might have separate markets for each candidate, each independently tradable.
Slugs
Slugs are URL-friendly identifiers like fed-decision-in-october or bitcoin-above-100k-2025. You can use slugs to query both the /events and /markets endpoints, which is convenient when building integrations that reference markets by their human-readable names rather than numeric IDs.
Endpoint Reference
All endpoints are prefixed with https://gamma-api.polymarket.com. Responses are JSON.
GET /events
Retrieve a list of events with optional filtering, sorting, and pagination.
curl "https://gamma-api.polymarket.com/events?active=true&limit=10&order=volume_24hr&ascending=false"
Returns an array of event objects, each containing a nested markets array with full market details.
GET /events/{id}
Retrieve a single event by its numeric ID.
curl "https://gamma-api.polymarket.com/events/12345"
Returns the full event object including all child markets, tags, and metadata.
GET /markets
Retrieve a list of markets with optional filtering. Useful when you want to query across events or find specific markets by condition ID.
curl "https://gamma-api.polymarket.com/markets?active=true&limit=10"
GET /markets/{id}
Retrieve a single market by its numeric ID or condition ID.
curl "https://gamma-api.polymarket.com/markets/67890"
Returns the full market object with token IDs, prices, outcomes, volume, and all metadata.
GET /public-search
Full-text search across events and markets. This is the best endpoint for keyword-based discovery.
The search parameter is q, not query. Verified on 2026-08-30: ?query=bitcoin returns 422 Unprocessable Entity no matter what else you send, while ?q=bitcoin returns 200. This endpoint also ignores limit — the page size parameter is limit_per_type.
curl -s "https://gamma-api.polymarket.com/public-search?q=bitcoin&limit_per_type=5"
The response has two top-level keys — events and pagination:
{
"events": [
{ "slug": "what-price-will-bitcoin-hit-in-august-2026", "markets": [ /* 46 markets */ ] },
{ "slug": "bitcoin-above-on-august-29-2026", "markets": [ /* 12 markets */ ] }
],
"pagination": { "hasMore": true, "totalResults": 122383 }
}
Matching markets are nested inside each event’s markets array, and each one carries a populated clobTokenIds pair — so a single search call gives you everything you need to place a CLOB order. limit_per_type defaults to 5 events; use pagination.hasMore to decide whether to keep paging.
GET /v1/search — the Polymarket US equivalent
Polymarket US does not serve Gamma. Its discovery layer is the gateway host, and the search endpoint sits under a /v1 prefix — and unlike Gamma, it takes query= rather than q=:
https://gateway.polymarket.us/v1/search?query=bitcoin&limit=100
The /v1 is mandatory — https://gateway.polymarket.us/search?query=bitcoin returns 404 Not Found. Like Gamma’s /public-search, no authentication is required. Verified against the live API on 2026-08-30:
curl -s "https://gateway.polymarket.us/v1/search?query=bitcoin&limit=100" \
| jq '{keys: (keys), events: (.events | length), first: .events[0].ticker}'
{
"keys": ["events"],
"events": 6,
"first": "btc-above-yr-12-31-2026"
}
Four differences from Gamma’s /public-search that break naive ports:
- The parameter names differ. Gamma wants
qandlimit_per_type; the US gateway wantsqueryandlimit. Sending Gamma’sq=here is silently ignored rather than rejected. - There is no
paginationobject. The response has exactly one top-level key,events, so there is nohasMoreortotalResultsto page against. limitcounts events, not markets.limit=100returned 6 events containing 51 markets between them;limit=2returned 2 events. It is a cap, not a target — a narrow query returns fewer.conditionIdandclobTokenIdsarenullon every market. All 51 markets in the response above carried nulls for both, where Gamma populates them. You cannot get CLOB token IDs out of Polymarket US search; use the event/marketslugoridand resolve through the authenticatedapi.polymarket.ustrading host instead.
query is optional. Omitting it (?limit=2) returns a default listing rather than an error.
A market object inside events[].markets[] looks like this:
{
"id": "269271",
"slug": "cpc-btc-above-yr-12-31-2026-200k",
"question": "Will Bitcoin be above ___ in 2026?",
"outcomes": "[\"Yes\",\"No\"]",
"outcomePrices": "[\"0.0400\",\"0.0500\"]",
"bestBidQuote": { "value": "0.0400", "currency": "USD" },
"bestAskQuote": { "value": "0.0500", "currency": "USD" },
"status": "MARKET_STATUS_OPEN",
"orderPriceMinTickSize": 0.01,
"minimumTradeQty": 0.01
}
Two parsing notes: outcomes and outcomePrices are JSON-encoded strings, so they need a second json.loads() pass — the same quirk Gamma has. And status uses a prefixed enum (MARKET_STATUS_OPEN), not the bare open/closed strings Gamma returns, so a shared status check across both hosts needs normalizing.
import json, requests
r = requests.get("https://gateway.polymarket.us/v1/search",
params={"query": "bitcoin", "limit": 100}, timeout=30)
for event in r.json()["events"]:
for market in event["markets"]:
outcomes = json.loads(market["outcomes"]) # ["Yes", "No"]
prices = json.loads(market["outcomePrices"]) # ["0.0400", "0.0500"]
print(event["ticker"], market["slug"], dict(zip(outcomes, prices)))
GET /tags, /series, /sports, /teams
Categorization endpoints for browsing the market taxonomy:
/tags— returns all available category tags (politics, crypto, sports, etc.)/series— returns event series (e.g., recurring monthly predictions)/sports— returns sports categories for sports-specific markets/teams— returns team entities linked to sports markets
These are useful for building navigation UIs or filtering markets by category programmatically.
Filtering, Sorting, and Pagination
The Gamma API supports a consistent set of query parameters across its listing endpoints.
Filter Parameters
| Parameter | Type | Description |
|---|---|---|
active | boolean | Filter to only active (open) markets or events |
closed | boolean | Filter to only closed (resolved) markets or events |
tag_id | string | Filter by a specific category or tag identifier |
exclude_tag_id | string | Exclude markets or events with a specific tag |
related_tags | boolean | When true, include markets from related tags |
slug | string | Fetch a specific event or market by its URL slug |
Combine filters to narrow results precisely. For example, active=true&tag_id=crypto returns only open crypto markets.
Sort Options
Use the order parameter to sort results and ascending to control direction (defaults to descending).
| Value | Description |
|---|---|
volume_24hr | 24-hour trading volume (most popular for scanners) |
volume | Total all-time trading volume |
liquidity | Current liquidity depth in the order book |
start_date | When the market opened for trading |
end_date | When the market is scheduled to close |
competitive | How competitive the market pricing is (close to 50/50) |
closed_time | When the market was resolved (for closed markets) |
Pagination
Gamma has two pagination systems, and the one nearly every tutorial shows you dies after 2,000 rows.
limit + offset works on /events and /markets, but offset is capped at 2000. Ask for one more and the request fails:
curl -s "https://gamma-api.polymarket.com/markets?limit=1&offset=2001"
{"type":"validation error","error":"offset too large, use /markets/keyset for deeper pagination"}
That is an HTTP 422, not an empty array — so the classic “loop until the response is empty” pattern does not terminate cleanly, it throws (or, if you ignore status codes, silently ends your dataset at row 2,000). /events returns the same error naming /events/keyset. offset=2000 is still fine; 2001 is not, and the cap applies to offset alone — offset=2000&limit=500 is accepted.
Also note limit is clamped to 100 on these endpoints. Requesting limit=500 or limit=1000 returns 100 rows with a 200 status, no warning. Any loop that advances offset by its requested limit rather than by len(batch) will skip records.
Keyset pagination is the supported way past 2,000 rows. Both /markets/keyset and /events/keyset accept the same filter and sort parameters as their offset-based counterparts, but return a wrapped object with a cursor instead of a bare array:
curl -s "https://gamma-api.polymarket.com/markets/keyset?limit=3&closed=false&active=true"
{
"$schema": "https://gamma-api.polymarket.com/schemas/MarketsKeysetListResponse.json",
"markets": [ { "id": "559651", "question": "Xi Jinping out before 2027?", ... } ],
"next_cursor": "bjZlbp--Id8uILt2O_myoOvX-CNl-MzVGdWQ_udL8nt7InYiOjEsImsiOiJtYXJrZXRz..."
}
Feed next_cursor back as after_cursor on the next request. Three footguns here, all verified live:
- The parameter is
after_cursor, notcursor. Gamma ignores unknown query parameters silently — it returns 200 with no warning. So?cursor=<token>re-serves page 1 forever, and awhile next_cursor:loop becomes an infinite loop that never advances. The same is true ofnext_cursor=,after=, and every other plausible spelling. This trips people up often enough that it has been filed as a server-side bug — Polymarket/agents#227, “cursor parameter ignored, returns same first page” (Apr 26, 2026) — and closed as off-topic rather than answered. It is not a server bug. Rename the parameter toafter_cursorand paging works. offsetis rejected outright on keyset endpoints —{"type":"validation error","error":"offset is not allowed on keyset endpoints"}(422). You cannot mix the two schemes.limitclamps to 100 here too.limit=1000returns 100 rows.
import requests
GAMMA = "https://gamma-api.polymarket.com"
def get_all_active_markets():
"""Paginate every active market via keyset — no 2,000-row ceiling."""
markets = []
cursor = None
while True:
params = {"active": "true", "closed": "false", "limit": 100}
if cursor:
params["after_cursor"] = cursor # NOT "cursor" — that is silently ignored
resp = requests.get(f"{GAMMA}/markets/keyset", params=params, timeout=30)
resp.raise_for_status()
body = resp.json()
batch = body.get("markets", [])
if not batch:
break
markets.extend(batch)
cursor = body.get("next_cursor")
if not cursor:
break
return markets
Swap markets for events (both the path and the response key) to walk events instead. Keyset endpoints also exist for /comments/keyset, /reports/keyset, and /spotlights/keyset.
On the “May 1, 2026 sunset”: Polymarket announced that the offset-based /markets and /events list endpoints would be deprecated on May 1, 2026 in favour of the keyset endpoints. As of 2026-08-30 they are still live and still return 200 — the deprecation has not been enforced, it just came with the offset ceiling. Treat them as on borrowed time and build new pagination on keyset.
Use offset paging only when you know you are staying inside the first 2,000 rows — a top-50 leaderboard, a single tag’s markets. For a full sync, backfill, or anything unbounded, start with keyset.
Endpoint behaviour verified against the live Gamma API and https://gamma-api.polymarket.com/openapi.json on 2026-08-30.
Price History for Backtesting
Price history is not available through the Gamma API. To get historical price data for backtesting, use the CLOB API’s /prices-history endpoint.
The workflow is:
- Use the Gamma API to discover a market and extract its
clobTokenIds - Pass the token ID to the CLOB API’s
/prices-historyendpoint - Specify a time range and fidelity (resolution) for the data points
import requests
def get_price_history(token_id, start_ts=None, end_ts=None, interval="1h", fidelity=60):
"""Fetch historical price data from the CLOB API.
Args:
token_id: The CLOB token ID (from Gamma API's clobTokenIds field)
start_ts: Start timestamp (Unix seconds)
end_ts: End timestamp (Unix seconds)
interval: Candle interval (e.g., '1h', '1d')
fidelity: Data point resolution in minutes
Returns:
Dict with 'history' array of {t: timestamp, p: price} objects
"""
params = {"market": token_id, "interval": interval, "fidelity": fidelity}
if start_ts:
params["startTs"] = start_ts
if end_ts:
params["endTs"] = end_ts
resp = requests.get(
"https://clob.polymarket.com/prices-history",
params=params
)
return resp.json()
# Get 1-hour candles for the last 7 days
history = get_price_history("<token-id>", interval="1h")
for point in history.get("history", []):
print(f"{point['t']}: {point['p']}")
Each data point in the history array contains:
t— the timestamp for the data pointp— the price at that timestamp (0.00 to 1.00, representing probability)
For backtesting, combine Gamma API market discovery with CLOB price history to build datasets spanning multiple markets across any time range.
Caching Strategies
Market metadata from the Gamma API — questions, token IDs, event structures, and tag lists — changes infrequently. Caching aggressively reduces your request count and keeps you well under rate limits.
import requests
import time
class GammaCache:
"""Simple TTL cache for Gamma API responses."""
def __init__(self, ttl=300):
self._cache = {}
self._ttl = ttl
def get(self, endpoint, params=None):
"""Fetch from cache or make a fresh request."""
key = f"{endpoint}:{params}"
if key in self._cache:
data, ts = self._cache[key]
if time.time() - ts < self._ttl:
return data
resp = requests.get(
f"https://gamma-api.polymarket.com{endpoint}",
params=params
)
data = resp.json()
self._cache[key] = (data, time.time())
return data
Recommended TTL values by data type:
| Data Type | Recommended TTL | Rationale |
|---|---|---|
| Market metadata (questions, token IDs) | 5 minutes | Rarely changes after creation |
| Event structures | 5 minutes | New markets may be added to events |
| Tag and category lists | 1 hour | Tags are relatively stable |
| Search results | 1 minute | Results shift as volume changes |
| Prices (via CLOB, not Gamma) | Do not cache | Use WebSocket for real-time data |
For production scanners, consider persisting cached data to disk or a database so you can restart without re-fetching everything.
Rate Limits
The Gamma API enforces rate limits via Cloudflare throttling. Exceeding limits returns HTTP 429 responses.
| Endpoint | Limit |
|---|---|
| General (all endpoints) | 4,000 / 10s |
| /markets + /events listing | 900 / 10s |
| /events | 500 / 10s |
| /public-search | 350 / 10s |
| /markets | 300 / 10s |
| /comments | 200 / 10s |
| /tags | 200 / 10s |
Best practices for staying within limits:
- Cache aggressively — most metadata does not change between requests
- Use larger page sizes — fetching 100 items in one request is better than 10 requests of 10
- Add backoff on 429s — if throttled, wait at least 10 seconds before retrying
- Batch your discovery — scan markets once, store the results, then query the CLOB API for live data
For the full rate limit reference across all Polymarket APIs, see the Polymarket Rate Limits Guide.
Building a Market Scanner
Here is a complete example that queries the Gamma API for high-volume markets with active order books and extracts the data needed for further analysis or trading.
import requests
import time
def scan_top_markets(min_volume=100000, limit=20):
"""Find the highest-volume active markets with CLOB order books.
Args:
min_volume: Minimum total volume in USDC to include
limit: Number of events to fetch from the Gamma API
Returns:
List of market dicts sorted by 24h volume descending
"""
resp = requests.get(
"https://gamma-api.polymarket.com/events",
params={
"active": "true",
"limit": limit,
"order": "volume_24hr",
"ascending": "false"
}
)
events = resp.json()
results = []
for event in events:
for market in event.get("markets", []):
# Skip markets without CLOB trading
if not market.get("enableOrderBook"):
continue
volume = float(market.get("volume", 0))
if volume < min_volume:
continue
outcomes = market.get("outcomes", [])
prices = market.get("outcomePrices", [])
results.append({
"question": market.get("question"),
"condition_id": market.get("conditionId"),
"token_ids": [
market.get("clobTokenIds", [None, None])[0],
market.get("clobTokenIds", [None, None])[1]
],
"volume_24h": volume,
"outcomes": dict(zip(outcomes, prices))
})
return sorted(results, key=lambda x: x["volume_24h"], reverse=True)
# Find top markets by volume
top = scan_top_markets(min_volume=50000)
for market in top[:10]:
print(f"{market['question']}")
for outcome, price in market['outcomes'].items():
print(f" {outcome}: {price}")
This scanner gives you everything you need to:
- Monitor market activity — run it on a schedule to track which markets are trending
- Feed a trading bot — pass the
token_idsto the CLOB API for live pricing and order placement - Build a dashboard — store results in a database and visualize volume trends over time
- Backtest strategies — use the
token_idswith the CLOB/prices-historyendpoint to pull historical data
FAQ
What is the Polymarket Gamma API?
The Gamma API at gamma-api.polymarket.com provides market discovery and metadata for Polymarket. It indexes events, markets, tags, series, and sports data. No authentication is required. Use it to find markets, get token IDs, and discover events.
How do I get Polymarket price history for backtesting?
Price history is available via the CLOB API’s /prices-history endpoint, not the Gamma API. Pass a token_id and time range to get historical price data points. Use the Gamma API to discover markets and get token IDs, then use the CLOB API for price history.
What is the difference between Events and Markets in the Gamma API?
Events are top-level questions (e.g., “Who will win the 2024 election?”). Markets are specific tradable binary outcomes within events, each with its own token IDs and condition ID. A single event can contain multiple markets for multi-outcome predictions.
What are the rate limits for the Gamma API?
The general limit is 4,000 requests per 10 seconds. Specific endpoint limits: /events is 500/10s, /markets is 300/10s, and /public-search is 350/10s. All limits are enforced via Cloudflare throttling.
See Also
- Polymarket API Guide — Full API reference covering CLOB, Gamma, and Data APIs
- Polymarket Subgraph Guide — On-chain data via GraphQL
- Polymarket WebSocket Guide — Real-time price and order book streaming
- Polymarket Rate Limits Guide — Complete rate limit reference across all APIs
- py_clob_client Reference — Python SDK methods for CLOB trading
- Prediction Market API Reference — Cross-platform API comparison
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.
