livetennisapi-ai

August 18, 2026 · View on GitHub

Live Tennis API as Vercel AI SDK tools. Give any AI SDK model real-time tennis scores, players, fixtures, tournaments, rankings, head-to-head, the 1968–2022 results archive, market prices and model win-probability — ATP, WTA, Challenger, ITF and juniors.

ci license: MIT

npm install livetennisapi-ai

ai v7 is a peer dependency — this package uses whichever copy your app already has.

Usage

import { generateText, gateway, isStepCount } from 'ai';
import { livetennisTools } from 'livetennisapi-ai';

const { text } = await generateText({
  model: gateway('openai/gpt-5-mini'),
  prompt: 'Which tennis matches are live right now, and who does the model favour?',
  tools: livetennisTools({ apiKey: process.env.LIVETENNISAPI_KEY }), // twjp_...
  stopWhen: isStepCount(3),
});

console.log(text);

API key

Resolved in this order:

  1. the explicit apiKey option — livetennisTools({ apiKey: 'twjp_…' })
  2. process.env.LIVETENNISAPI_KEY

Get a free key, no card, at https://livetennisapi.com/subscribe/free. The underlying client sends it as Authorization: Bearer twjp_….

Prefer the explicit option when one process serves several users: each call to livetennisTools() returns a tool set bound to exactly one key, sharing no state with any other, so two users can hold two different plans in the same process.

With no key at all the tools still return normally — they answer with an explanation of how to get one, rather than throwing. See Errors are values.

Picking a subset

Every tool is also exported individually. Worth doing: each tool's schema and description is sent to the model on every request, so an app that only needs live scores pays for the other twenty-one in tokens on every turn.

import { getLiveMatches, getMatchScore } from 'livetennisapi-ai';

const tools = {
  get_live_matches: getLiveMatches({ apiKey }),
  get_match_score: getMatchScore({ apiKey }),
};

The 24 tools

ToolIndividual exportDoesPlan
get_live_matchesgetLiveMatchesMatches in progress, with live scoresFREE
get_upcoming_matchesgetUpcomingMatchesMatches due to start soonFREE
get_matchgetMatchFull detail for one matchFREE
get_match_scoregetMatchScoreScore only — lowest latencyFREE
search_playerssearchPlayersFind players by nameFREE
get_playergetPlayerOne player's profile and rankingFREE
get_fixturesgetFixturesThe forward scheduleFREE
search_tournamentssearchTournamentsThe tournament catalogue behind tournament_idFREE
get_tournamentgetTournamentOne tournament by stable idFREE
check_api_statuscheckApiStatusIs the API up, and which plan is this key onFREE
get_recent_resultsgetRecentResultsCompleted matches with winners, filterableBASIC¹
search_archive_matchessearchArchiveMatchesResults archive 1968–2022 (1,485,752 matches)BASIC¹
get_archive_matchgetArchiveMatchOne archive result, serve stats where recordedBASIC¹
search_archive_playerssearchArchivePlayersArchive bios: hand, DOB, career-high rankBASIC¹
get_archive_careergetArchiveCareerCareer W-L / titles / serve sums over the archiveBASIC¹
get_h2hgetH2HAll-time head-to-head across both erasBASIC¹
get_match_eventsgetMatchEventsMatch timeline — breaks, games, momentumPRO
get_match_oddsgetMatchOddsMatch-winner market: bid, ask, midPRO
get_rankingsgetRankingsThe full published ranking table per systemPRO
get_match_analysisgetMatchAnalysisModel win probability and thesisULTRA
get_player_rankingsgetPlayerRankingsPoint-in-time rankings for specific playersULTRA
get_match_statisticsgetMatchStatisticsIn-play stats: derived + measured familiesULTRA
get_charting_playergetChartingPlayerCareer shot-level charting profileULTRA
get_charting_matchgetChartingMatchEvery charting stat family for one matchULTRA

¹ or any History plan — History grants work even on a FREE core key.

Plans: FREE = live & upcoming matches, scores, players, fixtures, tournaments · BASIC = + historical results, the results archive (1968–2022) and head-to-head · PRO = + match events, market prices and the rankings listing · ULTRA = + model analysis, win probability, per-player as-of rankings, in-play statistics, shot-level charting and the live WebSocket feed. Pricing at https://livetennisapi.com/#pricing

check_api_status reports which plan your key is actually on, which is the fastest way to find out why another tool is declining to return data.

Rate limits

PlanPer minutePer dayPrice
FREE30100$0
BASIC601,000$9.99/mo
PRO30010,000$29.99/mo
ULTRA600500,000$99.99/mo

On a free key (100/day), poll no faster than every 15 minutes. An always-on dashboard should run on BASIC or higher.

Errors are values

A tier wall, a rejected key, a missing key, a rate limit and an empty result do not throw. Each returns a normal result carrying ok: false and a message explaining the remedy:

{
  ok: false,
  message: 'This data requires the ULTRA plan, and the configured API key is on a lower tier. …'
}

This is deliberate. Marking a tier wall as an error makes models retry it or abandon the task; as a value, the model relays the upgrade path to the user — the only person who can act on it.

The three 429 shapes are told apart, because each has a different correct reaction:

  • per-minute — wait Retry-After seconds and go again;
  • daily quota — the message carries the exact resets_at instant the allowance returns (derived from the service's local midnight), so the model stops retrying into a wall;
  • abuse_throttled — a ~24-hour block for clients that kept hammering through 429s. The message names the resume time and tells the model to fix the retry loop, not to wait it out request by request.

Name-keyed tools (get_h2h, get_archive_career, get_charting_player) refuse an ambiguous name fragment rather than guessing — the result relays the candidate list so the model can retry with a specific name.

Successful calls return ok: true, a human-readable message, and the structured data:

{
  ok: true,
  message: '2 live match(es): …',
  matches: [{ id: 101, tournament: 'Test Open', player1: 'Player One', score: '6-4 3-2', … }],
}

Every tool declares an outputSchema describing exactly that shape. Note that the AI SDK does not validate tool output at runtime, so the schema is a contract this package's own test suite enforces, not one the SDK enforces for you.

Also available

The same 24 tools are available as an MCP server — livetennisapi-mcp — for Claude, Cursor and other MCP clients. The underlying REST/WebSocket client is livetennisapi.

Development

npm install
npm run typecheck
npm run build
npm test          # builds, then runs both suites against a local stub — no network, no key

test/tools-output.mjs drives all 24 tools twice — once with no key, once against a stub upstream — and parses every result through the tool's own outputSchema. test/generate-text.mjs runs a full generateText loop against a mock model, which is what proves the zod schemas survive conversion to JSON Schema on the way to a provider.

License

MIT

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.