← Developer Blog

Polymarket API for Tennis: Gamma, CLOB & Live Scores

How Polymarket's tennis APIs work — Gamma for public market data (tag 864), CLOB for execution — and where a free live-scores API fits as match state.

· · By the Live Tennis API team

Polymarket exposes two distinct APIs for tennis: the Gamma API serves public market data (events, markets, prices) under tennis tag 864 and needs no key, while the CLOB API handles order placement and execution and requires wallet-signed auth. Neither returns live tennis scores — that match-state layer comes from a dedicated tennis data feed.

If you are building anything that reads or reacts to tennis prediction markets, it helps to keep those three jobs separate in your head: discover markets, read/place orders, and know what is actually happening on court. This article walks each one, with a runnable Gamma snippet, and shows where the Live Tennis API slots in as the score/status source.

The three layers, and which API owns each

Job Who owns it Auth Notes
Discover tennis markets & read prices Polymarket Gamma API Keyless Public market metadata, outcomes/outcomePrices
Place & manage orders Polymarket CLOB API Wallet-signed Execution is yours to build; use py-clob-client
Live match scores & status Live Tennis API X-API-Key Live matches, per-set scores, match status

Polymarket's APIs are Polymarket's. They tell you what markets exist and let you trade them. They do not tell you that a player just got broken, took a medical timeout, or retired. That is the gap the tennis data layer fills — and it is why a bot that reads market prices alone is flying half-blind.

Polymarket Gamma API: discovering tennis markets

Gamma (https://gamma-api.polymarket.com) is the public, keyless data API. Tennis markets carry tag 864. The two useful endpoints are /events (grouped markets, e.g. a whole tournament winner) and /markets (individual yes/no markets).

A key gotcha: outcomes and outcomePrices come back as JSON-encoded strings, not arrays — you have to parse them a second time.

import requests, json

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

# Open tennis markets, tag 864
resp = requests.get(
    f"{GAMMA}/markets",
    params={"tag_id": 864, "closed": "false", "limit": 20},
    timeout=15,
)
resp.raise_for_status()

for m in resp.json():
    # These fields are STRINGS containing JSON — parse again.
    outcomes = json.loads(m.get("outcomes") or "[]")
    prices = json.loads(m.get("outcomePrices") or "[]")
    pairs = ", ".join(f"{o}={p}" for o, p in zip(outcomes, prices))
    print(f'{m["question"]}')
    print(f'  {pairs}')
    print(f'  conditionId={m.get("conditionId")}\n')

The conditionId on each market is the handle you carry into the CLOB layer for order books and execution. The resolutionSource and description fields carry the market's own resolution wording — read those, because how a market settles (including on a retirement or walkover) is defined there, by Polymarket, not by any data feed.

Grouped tournament markets live under /events with the same tag_id=864, and each event nests a markets array — handy for "who wins the tournament" style questions.

Polymarket CLOB API: execution is yours

The CLOB (Central Limit Order Book) API is where actual trading happens: order books, order placement, cancellation, balances. It is authenticated with your wallet signature, and the maintained client is py-clob-client. Orders, wallets, private keys, and USDC are entirely the builder's responsibility — a data feed never touches them, and this article does not cover placing orders. Consult Polymarket's own CLOB docs for the current auth flow, tick sizes, and rate limits.

The clean division of labour: Gamma answers "what markets exist and what do they cost?", CLOB answers "put my order in the book." Your logic in between decides whether to act — and that decision is only as good as your read on the live match.

Where live tennis scores fit

Gamma gives you a market price; it does not tell you the score that price is reacting to. To close that loop you need a live match-state feed. The Live Tennis API free tier (30 req/min, 100/day, no card) covers exactly the read side a market bot needs:

import requests

TENNIS = "https://api.livetennisapi.com/api/public/v1"
HEADERS = {"X-API-Key": "YOUR_FREE_KEY"}

live = requests.get(
    f"{TENNIS}/matches",
    params={"status": "live"},
    headers=HEADERS,
    timeout=15,
).json()

for match in live["data"]:            # list endpoints return {"data": [...], "meta": {...}}
    print(match["id"], match["status"], match.get("event_status"), match.get("outcome"),
          match["players"]["p1"]["name"],
          "vs",
          match["players"]["p2"]["name"])

Crucially, the match object carries more than the lifecycle status (upcoming / live / completed / cancelled): it also carries event_status (the feed's own designator — Retired, Walk Over, Cancelled, Postponed, Interrupted) and a closed-vocabulary outcome (completed, retired, walkover, default, abandoned; null until settled), plus withdrew. That means a bot can detect a retirement in the data as soon as it lands (an in-play retirement is stamped within seconds of the feed stating it; a walkover declared before first serve comes through a short pre-start status poll, since no live socket can push a match that never went live), then read the relevant market's own resolution wording to decide what to do. Detecting the event and reading the venue's rule are two separate steps; the feed does the first, the venue's published rules govern the second. (We go deeper on that in Tennis retirements & walkovers on prediction markets.)

Putting it together

A minimal read loop looks like this:

  1. Gamma → pull open tennis markets (tag 864), keep conditionId and current outcomePrices.
  2. Live Tennis API → match those markets to live matches and poll score + status.
  3. Your logic → compare the market price against what the score is telling you; flag divergences or a status change (e.g. a retirement).
  4. CLOB (optional, your responsibility) → if you choose to act, place the order via py-clob-client.

The open-source polymarket-tennis toolkit (MIT, observe-only) demonstrates steps 1–2: Gamma discovery, matching tennis matches to markets, and a joined live view. It is a reading and matching harness — it does not place orders.

Is the Polymarket API free? Limits?

Gamma is public and keyless for reading market data — you do not sign in to query prices. The CLOB API is free to use in the sense that there is no subscription, but it requires wallet auth and involves on-chain USDC and gas when you actually trade. For current rate limits on both, check Polymarket's docs rather than assuming — limits change. On the tennis-data side, the free Live Tennis API key is 30 req/min and 100 req/day, which is comfortable for polling a handful of live matches; higher volumes and extras (history, market prices/events, win-probability, live per-point, WebSocket) sit on the paid tiers.

For the full end-to-end build across both venues, see the pillar guide How to build a Polymarket tennis trading bot. None of this is financial advice — it is plumbing.

Frequently asked questions

What API does Polymarket use for tennis?

Polymarket has two: the Gamma API (https://gamma-api.polymarket.com), a public keyless data API where tennis markets carry tag_id 864, and the CLOB API for order placement and execution, which requires wallet-signed auth. Gamma is for reading markets and prices; CLOB is for trading. Neither returns live match scores.

Is the Polymarket API free?

Gamma, the market-data API, is public and needs no key or account to read prices. The CLOB trading API has no subscription fee but requires wallet authentication and involves on-chain USDC and gas when you place orders. Check Polymarket's official docs for current rate limits on both.

What is the difference between the Polymarket Gamma API and CLOB API?

Gamma serves public market metadata — events, markets, outcomes, and outcomePrices — and is keyless. CLOB (Central Limit Order Book) handles order books and execution and needs wallet auth via py-clob-client. In short: Gamma tells you what markets exist and what they cost; CLOB places your orders.

How do I get live tennis scores for a Polymarket bot?

Polymarket's own APIs do not return live scores. Use a dedicated tennis feed such as the Live Tennis API — its free tier (GET /matches?status=live and /matches/{id}/score) gives live matches, per-set scores, and each match's status plus its `event_status`/`outcome` fields (retirements, walkovers, cancellations), so your bot can react to what is happening on court.

Why do Polymarket outcomePrices come back as a string?

In the Gamma API, the outcomes and outcomePrices fields are JSON-encoded strings, not native arrays. You must parse them a second time (e.g. json.loads(m['outcomePrices'])) before you can index into them. This trips up most people writing their first Gamma script.

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