Skip to main content

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.

ci PyPI License: MIT

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 (tagged meta["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 via match_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", with resets_at — the absolute instant the day quota resets, derived from a local midnight) and the abuse throttle (tagged "abuse_throttled", with retry_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 tagged meta["error"] = "ambiguous_name" carrying the candidate list, so an agent can ask which one was meant.
  • Sparse data is normal: score.server is 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 (stats before 1991, per-match dates) are honestly None. 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 a Secret environment-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 with Pipeline.loads(yaml_str, allowed_modules=["livetennisapi_haystack.match_fetcher", ...]) (or haystack.core.serialization.allow_deserialization_module(...)).
  • Sync only for now: run() — no run_async yet, although the official client has an async twin. Planned.

Links

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

livetennisapi_haystack-0.2.0.tar.gz (37.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

livetennisapi_haystack-0.2.0-py3-none-any.whl (31.3 kB view details)

Uploaded Python 3

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

Hashes for livetennisapi_haystack-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d85ce0218324007309e8f08e0a5140b67de70a2bda17d2eaf2bd81edbcc6953a
MD5 36f70836c1b9940178faf5b88a894f85
BLAKE2b-256 c3aa1858f50ec56a8ef71c625914051b7a57a19ca717fb7f88115a2fd42e7701

See more details on using hashes here.

Provenance

The following attestation bundles were made for livetennisapi_haystack-0.2.0.tar.gz:

Publisher: publish.yml on livetennisapi/livetennisapi-haystack

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file livetennisapi_haystack-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for livetennisapi_haystack-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 97a12671214604147b9eb04d3d0cc57c9a1170942ef10bc10598aa42bfa0a385
MD5 1814c0700263377d78a1d2984e47434b
BLAKE2b-256 0d86f48f6ccfb55ccc43c6ef960b69d8493b09413cf1a3218ab146645017fe07

See more details on using hashes here.

Provenance

The following attestation bundles were made for livetennisapi_haystack-0.2.0-py3-none-any.whl:

Publisher: publish.yml on livetennisapi/livetennisapi-haystack

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page