← Developer Blog

Find Tennis Markets on Polymarket (Gamma API)

Discover live Polymarket tennis markets in Python with the free Gamma API: tag 864, filtering, market shape, and parsing prices — runnable code.

· · By the Live Tennis API team

Polymarket exposes every tennis market through its free, keyless Gamma API at https://gamma-api.polymarket.com. Tennis markets carry tag id 864. Query /markets (or /events) with tag_id=864&active=true&closed=false and you get the questions, outcomes, and current market prices as plain JSON — no wallet or account required to read them.

This article covers the read side: how to list tennis markets, what a market object actually looks like, how to filter down to the ones you care about (live singles moneylines vs. tournament futures), and how to parse the price fields — which are not what you'd expect. The Gamma API is public and rate-friendly for polite polling. You do not need our API or anyone's key to fetch market prices; you need it later, for the live match state you'll join against these prices.

One request with curl

Start by confirming the endpoint works. This returns two live tennis markets:

curl -s "https://gamma-api.polymarket.com/markets?tag_id=864&active=true&closed=false&limit=2" | python3 -m json.tool

The important query parameters:

The market shape (and the price gotcha)

A Gamma market object carries the fields you need to build a signal. Trimmed to the useful ones:

{
  "id": "1088471",
  "question": "Will Jannik Sinner win the 2026 Men's US Open?",
  "slug": "will-jannik-sinner-win-the-2026-mens-us-open",
  "conditionId": "0x65bbe9ee...",
  "outcomes": "[\"Yes\", \"No\"]",
  "outcomePrices": "[\"0.435\", \"0.565\"]",
  "volumeNum": 257002.62,
  "liquidityNum": 87623.83,
  "endDate": "2026-09-13T00:00:00Z",
  "active": true,
  "closed": false,
  "enableOrderBook": true,
  "groupItemTitle": "Jannik Sinner"
}

The gotcha: outcomes and outcomePrices are JSON-encoded strings, not arrays. You have to json.loads() them a second time. A price of "0.435" means the market implies a ~43.5% probability of that outcome; the two prices in a binary market sum to roughly 1.0. Treat them as market-implied probabilities in the 0-1 range, not a decimal price format.

List and filter tennis markets in Python

import json
import requests

GAMMA = "https://gamma-api.polymarket.com"
TENNIS_TAG = 864


def fetch_tennis_markets(limit=500):
    """Page through all currently-open tennis markets on Polymarket."""
    markets, offset, page = [], 0, 100
    while True:
        resp = requests.get(
            f"{GAMMA}/markets",
            params={
                "tag_id": TENNIS_TAG,
                "active": "true",
                "closed": "false",
                "limit": page,
                "offset": offset,
            },
            timeout=15,
        )
        resp.raise_for_status()
        batch = resp.json()
        if not batch:
            break
        markets.extend(batch)
        offset += page
        if len(batch) < page or len(markets) >= limit:
            break
    return markets


def parse_prices(market):
    """outcomes / outcomePrices arrive as JSON strings — decode both."""
    outcomes = json.loads(market.get("outcomes") or "[]")
    prices = json.loads(market.get("outcomePrices") or "[]")
    return dict(zip(outcomes, (float(p) for p in prices)))


markets = fetch_tennis_markets()
print(f"{len(markets)} open tennis markets")

for m in markets[:10]:
    prices = parse_prices(m)
    quote = "  ".join(f"{name} {p:.3f}" for name, p in prices.items())
    print(f"- {m['question']}\n    {quote}  (vol ${m.get('volumeNum', 0):,.0f})")

Separating live moneylines from futures

A tag_id=864 sweep mixes three kinds of market: head-to-head moneylines ("Player A vs Player B" for a specific match), futures ("Will X win the US Open?"), and props (set winner, total games). For an automated bot that reacts to live scores, you usually want the two-player moneylines. There's no single flag for that, so filter heuristically:

def is_binary_moneyline(market):
    outcomes = json.loads(market.get("outcomes") or "[]")
    # H2H match markets have exactly two player outcomes and a live order book;
    # "Yes/No" futures also have two outcomes, so also require the order book
    # and exclude the Yes/No pair.
    if len(outcomes) != 2 or not market.get("enableOrderBook"):
        return False
    return {o.lower() for o in outcomes} != {"yes", "no"}


live_h2h = [m for m in markets if is_binary_moneyline(m)]
print(f"{len(live_h2h)} head-to-head moneyline markets")

Grouped tournament futures (like the US Open winner) come back as many Yes/No markets that share an event; the /events endpoint (same tag_id=864) groups those under one title if you'd rather present the whole field together.

The proof point: this is a real, active category

This isn't a thin niche. On 2026-08-18, a live tag_id=864 sweep of the Gamma API returned 400+ open tennis moneyline markets — live Cincinnati Open singles, Challengers, ITF matches, and US Open futures — trading simultaneously. Tennis runs close to year-round across ATP, WTA, Challenger and ITF tours, so there is almost always a live board to work against.

Skip the boilerplate: the discovery module

Our open-source toolkit, livetennisapi/polymarket-tennis (MIT), wraps everything above in a discovery module: it calls Gamma, decodes the string-encoded price fields, classifies each market (match / futures / doubles), and hands you normalized Python objects instead of raw dicts. It's observe-only — no order execution, no wallets, no keys.

pip install git+https://github.com/livetennisapi/polymarket-tennis
pmtennis discover --matches-only --moneyline-only

Or from Python:

from polymarket_tennis import GammaClient, discover_tennis_markets

with GammaClient() as gamma:
    for market in discover_tennis_markets(gamma, market_types={"moneyline"},
                                          matches_only=True):
        print(market.question, market.prices)

Next: from prices to a signal

Market prices alone aren't a signal — you need the live match state (score, server, break point) to know whether a price is stale or ripe. Gamma gives you the price; the Live Tennis API gives you the live score. The free tier covers live matches and current scores — grab a free key (no card) and read the companion guide, Match a Polymarket tennis market to a live match, to join the two by player name. Placing orders — wallets, keys, the CLOB client — is your own responsibility and out of scope here.

Frequently asked questions

What is the Polymarket Gamma API?

Gamma is Polymarket's free, keyless public data API at https://gamma-api.polymarket.com. Its /markets and /events endpoints return questions, outcomes, current market prices, volume and liquidity as JSON. It's read-only market data — placing orders uses a separate authenticated CLOB client.

How do I find tennis markets on Polymarket?

Query the Gamma API with the tennis tag id 864: GET https://gamma-api.polymarket.com/markets?tag_id=864&active=true&closed=false. Add limit and offset to paginate. This returns every currently-open tennis market — moneylines, futures and props — with no API key required.

Do I need an API key to read Polymarket tennis prices?

No. Polymarket's Gamma API is public and keyless for reading market data, including prices. You only need authentication and a wallet to place orders, not to fetch questions, outcomes or prices.

Why are Polymarket outcome prices returned as strings?

Gamma returns the outcomes and outcomePrices fields as JSON-encoded strings (e.g. "[\"Yes\", \"No\"]"), so you must call json.loads() on them a second time after parsing the response. A price like "0.435" is the market-implied probability (~43.5%), and the outcomes in a binary market sum to about 1.0 — treat them as probabilities in the 0-1 range, not a decimal price format.

How many tennis markets are on Polymarket?

It's a large, active category. On 2026-08-18 a live Gamma API sweep with tag id 864 returned 400+ open tennis moneyline markets across ATP, WTA, Challenger and ITF events plus tournament futures, all trading at once. Because tennis runs nearly year-round, there is almost always a live board available.

Built with the Live Tennis API — real-time scores, players, odds and model win-probability for ATP, WTA, Challenger and ITF.

API reference SDKs on GitHub Plans from $9.99/mo