livetennisapi-haystack
Haystack 2.x integration for the
Live Tennis API: live scores, matches, players, head-to-heads,
the 1968-2022 results archive, rankings and in-play statistics across ATP, WTA, Challenger,
ITF and juniors — as Haystack Documents for RAG and agent pipelines.
Every component returns Documents whose content is a clean human-readable summary and
whose meta carries the structured fields — directly usable in prompts, document stores and
agent tools. Built on the official
livetennisapi Python client (retries, error
mapping, typed models) — no hand-rolled HTTP.
Installation
pip install livetennisapi-haystack
Grab a free API key at https://livetennisapi.com/subscribe/free and export it — the
components read LIVETENNISAPI_KEY by default and never accept a plain-string key:
export LIVETENNISAPI_KEY="twjp_your_key_here"
Quickstart
from livetennisapi_haystack import LiveTennisMatchFetcher
fetcher = LiveTennisMatchFetcher() # key from LIVETENNISAPI_KEY
result = fetcher.run(status="live", limit=5)
for doc in result["documents"]:
print(doc.content)
# e.g. "Carlos Alcaraz (ESP, #2) vs Jannik Sinner (ITA, #1) — match at Wimbledon,
# grass court, round QF, best of 5. Live now. Score: sets 1-1, games 6-4, 3-6,
# 2-1, points 30-15. Carlos Alcaraz (ESP, #2) is serving."
In a pipeline (runnable with only LIVETENNISAPI_KEY)
from haystack import Pipeline
from livetennisapi_haystack import LiveTennisMatchFetcher, LiveTennisPlayerSearch
pipe = Pipeline()
pipe.add_component("matches", LiveTennisMatchFetcher(limit=5))
pipe.add_component("players", LiveTennisPlayerSearch(limit=3))
result = pipe.run({"matches": {"status": "live"}, "players": {"query": "alcaraz"}})
for doc in result["matches"]["documents"] + result["players"]["documents"]:
print("-", doc.content)
RAG over live scores
from haystack import Pipeline
from haystack.components.builders.chat_prompt_builder import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from livetennisapi_haystack import LiveTennisMatchFetcher
prompt_template = [
ChatMessage.from_system("You are a tennis commentator."),
ChatMessage.from_user(
"Current matches:\n"
"{% for document in documents %}{{ document.content }}\n{% endfor %}\n"
"Answer the following question: {{ query }}\nAnswer:"
),
]
pipe = Pipeline()
pipe.add_component("matches", LiveTennisMatchFetcher(limit=10))
pipe.add_component("prompt_builder", ChatPromptBuilder(template=prompt_template, required_variables={"query", "documents"}))
pipe.add_component("llm", OpenAIChatGenerator(model="gpt-4o-mini"))
pipe.connect("matches.documents", "prompt_builder.documents")
pipe.connect("prompt_builder.prompt", "llm.messages")
query = "Who is closest to winning right now?"
result = pipe.run({"matches": {"status": "live"}, "prompt_builder": {"query": query}})
print(result["llm"]["replies"][0].text)
A complete runnable script lives at examples/live_demo.py.
Components
| Component | What it fetches | API endpoint(s) | Tier |
|---|---|---|---|
LiveTennisMatchFetcher |
Live / upcoming / completed matches, one match by id; filters: tour, player, country, from_/to |
/matches, /matches/{id} |
FREE (status="completed" listings: BASIC or any History plan) |
LiveTennisPlayerSearch |
Player search by name, ranked players first | /players |
FREE |
LiveTennisH2HFetcher |
Head-to-head between two players — results archive (1968-2022) + current matches (2023-now) in one record | /h2h |
BASIC |
LiveTennisArchiveFetcher |
The results archive: 1,485,752 matches 1968-2022 (mode="matches"), player bios (mode="players"), career aggregates (mode="career") |
/history/archive/* |
BASIC |
LiveTennisRankingsFetcher |
A published ranking table (atp, wta, itf_jt, itf_mt, itf_wt), optionally as of a past week |
/rankings |
PRO |
LiveTennisMatchStatisticsFetcher |
In-play statistics: aces, double faults, serve split, hold/break %, break points | /matches/{id}/statistics |
ULTRA |
All tour-filterable components accept tour values "atp", "wta", "challenger",
"itf" and "juniors"; each value covers its singles and doubles draws.
Quotas
| Tier | Requests/min | Requests/day | Price |
|---|---|---|---|
| FREE | 30 | 100 | $0 |
| BASIC | 60 | 1,000 | $9.99/mo |
| PRO | 300 | 10,000 | $29.99/mo |
| ULTRA | 600 | 500,000 | $99.99/mo |
At 100/day, poll no faster than every ~15 minutes on a free key; for an always-on dashboard, BASIC is the tier to recommend. Full details at https://docs.livetennisapi.com.
Authentication
The components resolve the key through Haystack's Secret (from LIVETENNISAPI_KEY by
default) and hand it to the official client, which sends it as an Authorization: Bearer
header — the API's preferred scheme (X-API-Key and ?token= also exist for clients that
cannot set headers). Serialized pipelines carry only the environment-variable reference,
never the key value.
Behavior worth knowing
- 403 tier wall: when your key is valid but the plan does not unlock an endpoint, the
component returns a single readable
Document(taggedmeta["error"] = "upgrade_required") instead of raising — an agent can tell the user; a RAG pipeline can filter it out. The case you will actually hit:status="completed"listings return 403 on a free key — they need the BASIC tier ($9.99/mo) or any History plan (https://livetennisapi.com/subscribe/upgrade).status="live"/"upcoming"and single-match fetches viamatch_id(even for a completed match) work on the free tier. - 429s: the official client transparently retries the per-minute window (and if it still
surfaces, the component fails loud — that is a transient error). The two NON-retryable
shapes become readable Documents instead: the daily cap (tagged
meta["error"] = "rate_limited", withresets_at— the absolute instant the day quota resets, derived from a local midnight) and the abuse throttle (tagged"abuse_throttled", withretry_at_epoch— a 24-hour block for chronic over-cap clients; fix the retry loop, retrying is what earns it). - Ambiguous names: the name-keyed endpoints (
/h2h, archive career) refuse a fragment matching more than one player; the component turns that into a Document taggedmeta["error"] = "ambiguous_name"carrying the candidate list, so an agent can ask which one was meant. - Sparse data is normal:
score.serveris nullable (between points the feed may not know who serves next — the summary simply omits the serving sentence), doubles teams have no individual rankings, points are strings ("0","15","30","40","AD"), and archive-era fields (statsbefore 1991, per-match dates) are honestlyNone. The components tolerate all of it and render only what exists. - Serialization: every component implements
to_dict/from_dict; the API key is stored as aSecretenvironment-variable reference, never as a value, so pipelines serialize safely to YAML. Note that Haystack 3.0 refuses to deserialize third-party components unless their module is allow-listed, so reload pipelines withPipeline.loads(yaml_str, allowed_modules=["livetennisapi_haystack.match_fetcher", ...])(orhaystack.core.serialization.allow_deserialization_module(...)). - Sync only for now:
run()— norun_asyncyet, although the official client has an async twin. Planned.
Links
- Docs: https://docs.livetennisapi.com
- Free API key: https://livetennisapi.com/subscribe/free
- Discord: https://discord.gg/f8WUZHgDm6
- GitHub org: https://github.com/livetennisapi
Development
pip install -e . pytest ruff
pytest # unit tests, fully mocked, no network
ruff check src tests examples
sh scripts/truthcheck.sh # product-facts pin (also runs in CI)
LIVETENNISAPI_KEY=... pytest -m integration # live tests, needs a key
Affiliate program
Know developers who need tennis data? The affiliate program pays 51% recurring commission for the life of every referred subscription — 30-day cookie, and the people you refer get 10% off.
License
livetennisapi-haystack is distributed under the terms of the
MIT license.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file livetennisapi_haystack-0.2.0.tar.gz.
File metadata
- Download URL: livetennisapi_haystack-0.2.0.tar.gz
- Upload date:
- Size: 37.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d85ce0218324007309e8f08e0a5140b67de70a2bda17d2eaf2bd81edbcc6953a
|
|
| MD5 |
36f70836c1b9940178faf5b88a894f85
|
|
| BLAKE2b-256 |
c3aa1858f50ec56a8ef71c625914051b7a57a19ca717fb7f88115a2fd42e7701
|
Provenance
The following attestation bundles were made for livetennisapi_haystack-0.2.0.tar.gz:
Publisher:
publish.yml on livetennisapi/livetennisapi-haystack
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
livetennisapi_haystack-0.2.0.tar.gz -
Subject digest:
d85ce0218324007309e8f08e0a5140b67de70a2bda17d2eaf2bd81edbcc6953a - Sigstore transparency entry: 2363277989
- Sigstore integration time:
-
Permalink:
livetennisapi/livetennisapi-haystack@6beb2afbc54c4040d283a3f8c814933e67a450fc -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/livetennisapi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6beb2afbc54c4040d283a3f8c814933e67a450fc -
Trigger Event:
push
-
Statement type:
File details
Details for the file livetennisapi_haystack-0.2.0-py3-none-any.whl.
File metadata
- Download URL: livetennisapi_haystack-0.2.0-py3-none-any.whl
- Upload date:
- Size: 31.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97a12671214604147b9eb04d3d0cc57c9a1170942ef10bc10598aa42bfa0a385
|
|
| MD5 |
1814c0700263377d78a1d2984e47434b
|
|
| BLAKE2b-256 |
0d86f48f6ccfb55ccc43c6ef960b69d8493b09413cf1a3218ab146645017fe07
|
Provenance
The following attestation bundles were made for livetennisapi_haystack-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on livetennisapi/livetennisapi-haystack
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
livetennisapi_haystack-0.2.0-py3-none-any.whl -
Subject digest:
97a12671214604147b9eb04d3d0cc57c9a1170942ef10bc10598aa42bfa0a385 - Sigstore transparency entry: 2363278676
- Sigstore integration time:
-
Permalink:
livetennisapi/livetennisapi-haystack@6beb2afbc54c4040d283a3f8c814933e67a450fc -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/livetennisapi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6beb2afbc54c4040d283a3f8c814933e67a450fc -
Trigger Event:
push
-
Statement type: