Yes — you can feed a Polymarket tennis trading bot with free live scores. Live Tennis API's free tier (30 req/min, 100 req/day, no card) serves live matches, current scores, player rankings, and fixtures. Get a key, send X-API-Key, and poll the current match state.
The free tier gives you the read side — the live state your bot reads to form a signal. Market prices come from Polymarket's keyless Gamma API, and order execution is your own responsibility (more on that at the end). This article covers just the scores: curl, Python, and JavaScript against real endpoints.
What the free tier gives you
Base URL: https://api.livetennisapi.com/api/public/v1. Every request needs the header X-API-Key: <your-key>. Grab a free key at livetennisapi.com/subscribe/free — self-serve, no card.
Free-tier endpoints, all of which a live-scores bot needs:
| Endpoint | Returns |
|---|---|
GET /matches?status=live |
every match in play right now |
GET /matches/{id}/score |
current score for one match |
GET /players/{id} |
a player incl. current ranking & Elo |
GET /fixtures |
upcoming matches |
GET /usage |
your own rate/quota counters |
The free tier stops at the current state of a match — the live scoreline as it stands. Completed-match history and point-by-point tape are a paid tier, and you don't need them for a live signal.
curl: is it working?
Smoke-test your key before writing any code:
curl -s https://api.livetennisapi.com/api/public/v1/matches?status=live \
-H "X-API-Key: $LIVE_TENNIS_API_KEY"
That returns the live matches. Take an id from the list and read its score:
curl -s https://api.livetennisapi.com/api/public/v1/matches/<match_id>/score \
-H "X-API-Key: $LIVE_TENNIS_API_KEY"
Python: poll the live board
A small polling loop is all a scores feed needs. Respect the free-tier limits — 30 req/min and 100 req/day means one poll every few seconds at most, so keep the interval sane.
import os, time, requests
BASE = "https://api.livetennisapi.com/api/public/v1"
HEADERS = {"X-API-Key": os.environ["LIVE_TENNIS_API_KEY"]}
def live_matches():
r = requests.get(f"{BASE}/matches", params={"status": "live"},
headers=HEADERS, timeout=10)
r.raise_for_status()
return r.json()["data"] # list endpoints return {"data": [...], "meta": {...}}
def score(match_id):
r = requests.get(f"{BASE}/matches/{match_id}/score",
headers=HEADERS, timeout=10)
r.raise_for_status()
return r.json()
if __name__ == "__main__":
while True:
for m in live_matches():
print(m.get("id"), score(m["id"]))
time.sleep(20) # stay well inside 30 req/min
Fewer, wider calls are better than a tight loop over many matches. On the free tier you have a daily budget — one matches?status=live call plus a score read for each in-play match adds up fast, so poll only the matches you actually care about and widen the interval when the board is quiet.
JavaScript: the same feed with fetch
Node 18+ (or any modern runtime) has fetch built in — no dependencies:
const BASE = "https://api.livetennisapi.com/api/public/v1";
const HEADERS = { "X-API-Key": process.env.LIVE_TENNIS_API_KEY };
async function liveMatches() {
const r = await fetch(`${BASE}/matches?status=live`, { headers: HEADERS });
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return (await r.json()).data; // list endpoints return {data: [...], meta: {...}}
}
async function score(matchId) {
const r = await fetch(`${BASE}/matches/${matchId}/score`, { headers: HEADERS });
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
}
const matches = await liveMatches();
for (const m of matches) {
console.log(m.id, await score(m.id));
}
Watch your quota
Never guess whether you're near the limit — read it. GET /usage returns your own counters, and a 429 means you've hit the rate cap; back off and retry:
u = requests.get(f"{BASE}/usage", headers=HEADERS, timeout=10).json()
print(u) # remaining req/min and req/day for your key
Where this plugs into a Polymarket bot
Live scores are one half. The other half is market prices, which come from Polymarket's public Gamma API (https://gamma-api.polymarket.com) — keyless, and tennis markets carry tag id 864. Our API is not needed for prices; Gamma is the source.
Joining the two — a live scoreline next to the matching market's price — is exactly what the open-source livetennisapi/polymarket-tennis toolkit (MIT) does. It discovers tennis markets on Gamma, matches them to live matches, and pairs price with score. It is observe-only: no order execution, no wallets, no keys.
Placing orders — wallets, private keys, the CLOB client — is the builder's own responsibility. If you go there, Polymarket's official py-clob-client is the tool, and none of this is financial advice or a guarantee of anything. Start with the read side, which is what's free.
Next: the pillar walk-through, How to build a Polymarket tennis trading bot (Python), stitches discovery, matching, and this live-scores feed together end to end.