Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ All notable changes to the specification are recorded here.
The API surface is versioned as `v1`. Changes within `v1` are **additive only**;
removing a field or changing its type would require `v2`.

## [1.13.76] - 2026-10-28

### Added
- **`X-LTAPI-Signature-V1` on every webhook delivery.** The value is `t=<unix seconds>,v1=<hex>`, and the hex is HMAC-SHA256 of `<t>.<raw request body>` with your webhook secret. The timestamp is inside the signed string, so a captured delivery re-sent later under a new time no longer verifies. Each body also carries a top-level `delivery_id`, unique per delivery, to dedupe on. The `POST /webhooks` description lists the receiver checks: a 5-minute timestamp window, a constant-time compare and a dedupe on `delivery_id`. It also lists `score_withdrawn` among the `X-LTAPI-Event` values, which it had left out.

### Fixed
- **The webhook `events` enum matches what registration accepts.** `POST /webhooks` listed `stoppages`, which registration refuses with a 400, and the `Webhook` schema listed only `score` and `break_point`. Both now read `score`, `break_point`, `point`, `status`.

### Deprecated
- **`X-LTAPI-Signature`, the body-only webhook signature.** It does not cover the timestamp. We keep sending it unchanged until 2027-02-01, and deliveries sent from 00:00 UTC on that date do not carry it. Both headers use the same secret, so moving to the new header needs no re-registration.

## [1.13.75] - 2026-10-28

### Changed
Expand Down
2 changes: 1 addition & 1 deletion docs/auth-quota-and-health.html
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@
<header class="docs-site-header"><a class="docs-brand" href="./"><img src="logo.svg" width="28" height="28" alt="">Live Tennis API <span>Docs</span></a><nav class="docs-desktop-nav" aria-label="Documentation"><a href="./">Overview</a><a href="./reference.html">API reference</a><a href="./changelog.html">Changelog</a></nav><a class="docs-key" href="https://livetennisapi.com/subscribe/free">Get a free key <span aria-hidden="true">↗</span></a></header><details class="docs-topic-menu"><summary>Explore the documentation</summary><nav aria-label="Documentation topics"><a href="./">Overview</a><a href="./reference.html">API reference</a><a href="./changelog.html">Changelog</a><a href="./live-scores.html">Live tennis scores API</a><a href="./players-and-tournaments.html">Tennis players, tournaments and rankings API</a><a href="./tennis-odds.html">Tennis odds API — markets and price ticks</a><a href="./point-by-point-history.html">Point-by-point tennis data API</a><a href="./historical-results-archive.html">Historical tennis results API — 1968 onward</a><a href="./shot-level-rally-data.html">Shot-by-shot tennis rally and charting API</a><a href="./broadcast-graphics.html">Tennis scores for on-air graphics</a><a href="./push-feed-and-webhooks.html">Tennis WebSocket feed and webhooks</a><a href="./auth-quota-and-health.html" aria-current="page">Tennis API authentication, quota and status</a><a href="./ai-sdk.html">Live Tennis API tools for the Vercel AI SDK</a></nav></details>
<div class="wrap">
<header>
<p class="meta">Live Tennis API &middot; docs &middot; version 1.13.75</p>
<p class="meta">Live Tennis API &middot; docs &middot; version 1.13.76</p>
<h1>Tennis API authentication, quota and status</h1>
<p><strong>How do you authenticate, and how do you see what quota is left?</strong> Send your key as <code>X-API-Key</code> on every request. <code>GET /usage</code> returns your own consumption against your plan's quota and works on every tier including FREE, so a client can check its own headroom before a burst. <code>GET /health</code> is the unauthenticated liveness probe.</p>
<p class="meta">2 endpoints on this page. Base URL
Expand Down
2 changes: 1 addition & 1 deletion docs/broadcast-graphics.html
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@
<header class="docs-site-header"><a class="docs-brand" href="./"><img src="logo.svg" width="28" height="28" alt="">Live Tennis API <span>Docs</span></a><nav class="docs-desktop-nav" aria-label="Documentation"><a href="./">Overview</a><a href="./reference.html">API reference</a><a href="./changelog.html">Changelog</a></nav><a class="docs-key" href="https://livetennisapi.com/subscribe/free">Get a free key <span aria-hidden="true">↗</span></a></header><details class="docs-topic-menu"><summary>Explore the documentation</summary><nav aria-label="Documentation topics"><a href="./">Overview</a><a href="./reference.html">API reference</a><a href="./changelog.html">Changelog</a><a href="./live-scores.html">Live tennis scores API</a><a href="./players-and-tournaments.html">Tennis players, tournaments and rankings API</a><a href="./tennis-odds.html">Tennis odds API — markets and price ticks</a><a href="./point-by-point-history.html">Point-by-point tennis data API</a><a href="./historical-results-archive.html">Historical tennis results API — 1968 onward</a><a href="./shot-level-rally-data.html">Shot-by-shot tennis rally and charting API</a><a href="./broadcast-graphics.html" aria-current="page">Tennis scores for on-air graphics</a><a href="./push-feed-and-webhooks.html">Tennis WebSocket feed and webhooks</a><a href="./auth-quota-and-health.html">Tennis API authentication, quota and status</a><a href="./ai-sdk.html">Live Tennis API tools for the Vercel AI SDK</a></nav></details>
<div class="wrap">
<header>
<p class="meta">Live Tennis API &middot; docs &middot; version 1.13.75</p>
<p class="meta">Live Tennis API &middot; docs &middot; version 1.13.76</p>
<h1>Tennis scores for on-air graphics</h1>
<p><strong>How do you put live tennis scores into a broadcast graphics template?</strong> <code>GET /broadcast/match/{matchId}</code> returns ONE flat object for one match and <code>GET /broadcast/live</code> the same object for every live match in a single call. Both are ULTRA. A graphics template binds each field to a fixed path, so three things are contractual: the object is flat, every key is present on every read (<code>null</code>, never missing), and the score is already in display form — <code>p1_points</code> reads <code>"40"</code> or <code>"AD"</code> and <code>set_line</code> is one string. Built for 1 Hz: every response carries a strong <code>ETag</code>, so <code>If-None-Match</code> makes an unchanged state a 304 with no body. Detect a new state on <code>sequence</code>, never on <code>served_at</code>, which changes on every read.</p>
<p class="meta">2 endpoints on this page. Base URL
Expand Down
19 changes: 16 additions & 3 deletions docs/changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Live Tennis API — Changelog</title>
<meta name="description" content="Every change to the Live Tennis API specification, dated and versioned: additive within v1, newest first. Current version 1.13.75, last change 2026-10-28.">
<meta name="description" content="Every change to the Live Tennis API specification, dated and versioned: additive within v1, newest first. Current version 1.13.76, last change 2026-10-28.">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://docs.livetennisapi.com/changelog.html">
<meta property="og:type" content="article">
Expand All @@ -14,7 +14,7 @@
<meta name="twitter:card" content="summary_large_image">
<link rel="icon" href="favicon.ico" sizes="any">
<script type="application/ld+json">
{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Live Tennis API — Changelog", "description": "Every change to the Live Tennis API specification, dated and versioned: additive within v1, newest first. Current version 1.13.75, last change 2026-10-28.", "url": "https://docs.livetennisapi.com/changelog.html", "dateModified": "2026-10-28", "inLanguage": "en", "isPartOf": {"@type": "WebSite", "name": "Live Tennis API", "url": "https://livetennisapi.com"}, "publisher": {"@type": "Organization", "@id": "https://livetennisapi.com/#org", "name": "JSB Holdings LLC", "alternateName": "Live Tennis API", "url": "https://livetennisapi.com", "logo": "https://docs.livetennisapi.com/icon-256.png", "sameAs": ["https://rapidapi.com/contact-whTqTESH5/api/tennis-data-analytics-api3", "https://apify.com/livetennisapi/tennis-data-analytics", "https://api.market/store/live-tennis-api/tennis-data-analytics", "https://www.postman.com/livetennisapi", "https://github.com/livetennisapi", "https://pypi.org/project/livetennisapi/", "https://www.npmjs.com/package/livetennisapi", "https://www.npmjs.com/package/livetennisapi-mcp", "https://docs.livetennisapi.com", "https://x.com/livetennisapi"]}}
{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Live Tennis API — Changelog", "description": "Every change to the Live Tennis API specification, dated and versioned: additive within v1, newest first. Current version 1.13.76, last change 2026-10-28.", "url": "https://docs.livetennisapi.com/changelog.html", "dateModified": "2026-10-28", "inLanguage": "en", "isPartOf": {"@type": "WebSite", "name": "Live Tennis API", "url": "https://livetennisapi.com"}, "publisher": {"@type": "Organization", "@id": "https://livetennisapi.com/#org", "name": "JSB Holdings LLC", "alternateName": "Live Tennis API", "url": "https://livetennisapi.com", "logo": "https://docs.livetennisapi.com/icon-256.png", "sameAs": ["https://rapidapi.com/contact-whTqTESH5/api/tennis-data-analytics-api3", "https://apify.com/livetennisapi/tennis-data-analytics", "https://api.market/store/live-tennis-api/tennis-data-analytics", "https://www.postman.com/livetennisapi", "https://github.com/livetennisapi", "https://pypi.org/project/livetennisapi/", "https://www.npmjs.com/package/livetennisapi", "https://www.npmjs.com/package/livetennisapi-mcp", "https://docs.livetennisapi.com", "https://x.com/livetennisapi"]}}
</script>
<link rel="preload" href="fonts/inter-latin-400.woff2" as="font" type="font/woff2" crossorigin fetchpriority="high">
<link rel="preload" href="fonts/space-grotesk-latin-700.woff2" as="font" type="font/woff2" crossorigin fetchpriority="high">
Expand Down Expand Up @@ -204,8 +204,21 @@
<header>
<p class="eyebrow">Live Tennis API · docs</p>
<h1>Changelog</h1>
<p>Every change to the specification, dated and versioned. The API surface is <code>v1</code>; changes within it are additive only. Current version <strong>1.13.75</strong>, last change <time datetime="2026-10-28">2026-10-28</time>. Also as <a href="https://docs.livetennisapi.com/reference.html">the full reference</a>, <a href="https://docs.livetennisapi.com/openapi.yaml">OpenAPI YAML</a> / <a href="https://docs.livetennisapi.com/openapi.json">JSON</a>, and <a href="https://livetennisapi.com/facts.json">the dated facts file</a>.</p>
<p>Every change to the specification, dated and versioned. The API surface is <code>v1</code>; changes within it are additive only. Current version <strong>1.13.76</strong>, last change <time datetime="2026-10-28">2026-10-28</time>. Also as <a href="https://docs.livetennisapi.com/reference.html">the full reference</a>, <a href="https://docs.livetennisapi.com/openapi.yaml">OpenAPI YAML</a> / <a href="https://docs.livetennisapi.com/openapi.json">JSON</a>, and <a href="https://livetennisapi.com/facts.json">the dated facts file</a>.</p>
</header>
<article id="v1.13.76"><h2>1.13.76 <time datetime="2026-10-28">2026-10-28</time></h2>
<h3>Added</h3>
<ul>
<li><strong><code>X-LTAPI-Signature-V1</code> on every webhook delivery.</strong> The value is <code>t=&lt;unix seconds&gt;,v1=&lt;hex&gt;</code>, and the hex is HMAC-SHA256 of <code>&lt;t&gt;.&lt;raw request body&gt;</code> with your webhook secret. The timestamp is inside the signed string, so a captured delivery re-sent later under a new time no longer verifies. Each body also carries a top-level <code>delivery_id</code>, unique per delivery, to dedupe on. The <code>POST /webhooks</code> description lists the receiver checks: a 5-minute timestamp window, a constant-time compare and a dedupe on <code>delivery_id</code>. It also lists <code>score_withdrawn</code> among the <code>X-LTAPI-Event</code> values, which it had left out.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li><strong>The webhook <code>events</code> enum matches what registration accepts.</strong> <code>POST /webhooks</code> listed <code>stoppages</code>, which registration refuses with a 400, and the <code>Webhook</code> schema listed only <code>score</code> and <code>break_point</code>. Both now read <code>score</code>, <code>break_point</code>, <code>point</code>, <code>status</code>.</li>
</ul>
<h3>Deprecated</h3>
<ul>
<li><strong><code>X-LTAPI-Signature</code>, the body-only webhook signature.</strong> It does not cover the timestamp. We keep sending it unchanged until 2027-02-01, and deliveries sent from 00:00 UTC on that date do not carry it. Both headers use the same secret, so moving to the new header needs no re-registration.</li>
</ul></article>
<article id="v1.13.75"><h2>1.13.75 <time datetime="2026-10-28">2026-10-28</time></h2>
<h3>Changed</h3>
<ul>
Expand Down
2 changes: 1 addition & 1 deletion docs/historical-results-archive.html
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@
<header class="docs-site-header"><a class="docs-brand" href="./"><img src="logo.svg" width="28" height="28" alt="">Live Tennis API <span>Docs</span></a><nav class="docs-desktop-nav" aria-label="Documentation"><a href="./">Overview</a><a href="./reference.html">API reference</a><a href="./changelog.html">Changelog</a></nav><a class="docs-key" href="https://livetennisapi.com/subscribe/free">Get a free key <span aria-hidden="true">↗</span></a></header><details class="docs-topic-menu"><summary>Explore the documentation</summary><nav aria-label="Documentation topics"><a href="./">Overview</a><a href="./reference.html">API reference</a><a href="./changelog.html">Changelog</a><a href="./live-scores.html">Live tennis scores API</a><a href="./players-and-tournaments.html">Tennis players, tournaments and rankings API</a><a href="./tennis-odds.html">Tennis odds API — markets and price ticks</a><a href="./point-by-point-history.html">Point-by-point tennis data API</a><a href="./historical-results-archive.html" aria-current="page">Historical tennis results API — 1968 onward</a><a href="./shot-level-rally-data.html">Shot-by-shot tennis rally and charting API</a><a href="./broadcast-graphics.html">Tennis scores for on-air graphics</a><a href="./push-feed-and-webhooks.html">Tennis WebSocket feed and webhooks</a><a href="./auth-quota-and-health.html">Tennis API authentication, quota and status</a><a href="./ai-sdk.html">Live Tennis API tools for the Vercel AI SDK</a></nav></details>
<div class="wrap">
<header>
<p class="meta">Live Tennis API &middot; docs &middot; version 1.13.75</p>
<p class="meta">Live Tennis API &middot; docs &middot; version 1.13.76</p>
<h1>Historical tennis results API — 1968 onward</h1>
<p><strong>How far back does the historical tennis data go, and what is in it?</strong> The results archive covers 1968 to 2022: <code>GET /history/archive/matches</code> for results, <code>/archive/players</code> for bios, <code>/archive/career</code> for career aggregates and <code>GET /h2h</code> for head-to-head across both the archive and our own completed matches. All BASIC. Matches from 2013 onward additionally carry a reconstructed point-by-point tape at <code>/archive/matches/{archiveId}/tape</code> (ULTRA).</p>
<p class="meta">6 endpoints on this page. Base URL
Expand Down
2 changes: 1 addition & 1 deletion docs/live-scores.html
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@
<header class="docs-site-header"><a class="docs-brand" href="./"><img src="logo.svg" width="28" height="28" alt="">Live Tennis API <span>Docs</span></a><nav class="docs-desktop-nav" aria-label="Documentation"><a href="./">Overview</a><a href="./reference.html">API reference</a><a href="./changelog.html">Changelog</a></nav><a class="docs-key" href="https://livetennisapi.com/subscribe/free">Get a free key <span aria-hidden="true">↗</span></a></header><details class="docs-topic-menu"><summary>Explore the documentation</summary><nav aria-label="Documentation topics"><a href="./">Overview</a><a href="./reference.html">API reference</a><a href="./changelog.html">Changelog</a><a href="./live-scores.html" aria-current="page">Live tennis scores API</a><a href="./players-and-tournaments.html">Tennis players, tournaments and rankings API</a><a href="./tennis-odds.html">Tennis odds API — markets and price ticks</a><a href="./point-by-point-history.html">Point-by-point tennis data API</a><a href="./historical-results-archive.html">Historical tennis results API — 1968 onward</a><a href="./shot-level-rally-data.html">Shot-by-shot tennis rally and charting API</a><a href="./broadcast-graphics.html">Tennis scores for on-air graphics</a><a href="./push-feed-and-webhooks.html">Tennis WebSocket feed and webhooks</a><a href="./auth-quota-and-health.html">Tennis API authentication, quota and status</a><a href="./ai-sdk.html">Live Tennis API tools for the Vercel AI SDK</a></nav></details>
<div class="wrap">
<header>
<p class="meta">Live Tennis API &middot; docs &middot; version 1.13.75</p>
<p class="meta">Live Tennis API &middot; docs &middot; version 1.13.76</p>
<h1>Live tennis scores API</h1>
<p><strong>How do you read live tennis scores from the API?</strong> Poll <code>GET /matches?status=live</code> for the slate, then <code>GET /matches/{matchId}/score</code> for the lowest-latency read of one match. Both are on the FREE plan. Scores carry sets, games, points and the server; <code>/events</code> and <code>/points</code> give the same match as a stream of changes rather than a snapshot, so a client can catch up without re-reading state.</p>
<p class="meta">11 endpoints on this page. Base URL
Expand Down
Loading
Loading