npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

livetennisapi

v1.0.1

Published

Official JavaScript/TypeScript client for the Live Tennis API — real-time tennis scores, players, market prices and model win-probability over REST and WebSocket.

Downloads

357

Readme

livetennisapi

Official JavaScript / TypeScript client for the Live Tennis API.

Real-time tennis scores, players, rankings, match-winner market prices and model win-probability — for ATP, WTA, Challenger and ITF, over REST and WebSocket.

npm types license

Documentation · Get an API key


Install

npm install livetennisapi

Zero runtime dependencies. Uses the platform fetch and WebSocket, so it runs unchanged on Node 18+, Deno, Bun, Cloudflare Workers and the browser.

Use

import { LiveTennisAPI } from 'livetennisapi';

const client = new LiveTennisAPI({ apiKey: 'twjp_…' });   // or $LIVETENNISAPI_KEY

const { data } = await client.listMatches({ status: 'live' });
for (const match of data) {
  console.log(match.tournament, match.players?.p1?.name, 'vs', match.players?.p2?.name);
}

Fully typed — every response, every option, every error.

Command line

No install needed:

$ npx livetennisapi live
live matches (3)
ID     Tournament       Rd   Players             Score
18953  ATP Wimbledon    R16  *Alcaraz / Sinner   6-4 3-6 2-1 (40-30)

$ npx livetennisapi match 18953
$ npx livetennisapi players djokovic
$ npx livetennisapi watch --match 18953

Live score feed (ULTRA)

import { LiveScoreStream } from 'livetennisapi';

const stream = new LiveScoreStream({ apiKey: 'twjp_…' });

for await (const update of stream) {
  console.log(update.match_id, update.sets);
}

Reconnects with exponential backoff and re-subscribes automatically. Heartbeats are consumed internally, so you only see real score changes. It deliberately does not reconnect on a bad key or insufficient tier — those throw immediately instead of retrying forever.

On Node 22+ the global WebSocket is used. On Node 18–20, npm install ws.

Tiers

| | BASIC | PRO | ULTRA | |---|:--:|:--:|:--:| | listMatches getMatch getMatchScore | ✅ | ✅ | ✅ | | searchPlayers getPlayer listFixtures listCompletedMatches | ✅ | ✅ | ✅ | | listMatchEvents listMarkets getMarketPrices | — | ✅ | ✅ | | getMatchAnalysis, win_probability_p1 / danger, WebSocket | — | — | ✅ |

Calling above your tier throws UpgradeRequired, which tells you which tier you need:

import { UpgradeRequired } from 'livetennisapi';

try {
  await client.getMatchAnalysis(18953);
} catch (err) {
  if (err instanceof UpgradeRequired) console.log(err.requiredTier); // 'ULTRA'
}

Errors

| Class | When | |---|---| | Unauthorized | 401 — key missing, unknown, or disabled | | UpgradeRequired | 403 — valid key, tier too low (has .requiredTier) | | NotFound | 404 — no such resource, or no data yet | | RateLimited | 429 — has .retryAfter in seconds | | ServerError / ServiceUnavailable | 5xx | | APIConnectionError / APITimeoutError | never reached the API |

All extend LiveTennisAPIError.

Requests retry on 429 and 5xx only, honouring Retry-After with exponential backoff and jitter. Other 4xx are never retried — a bad key or an unentitled tier cannot start working, and retrying only burns rate limit.

Pagination

limit defaults to 50; the API rejects anything above 200. To walk everything — paginate() clamps the page size for you:

for await (const player of client.paginate((p) => client.searchPlayers('nadal', p))) {
  console.log(player.name);
}

Forward compatibility

The API ships additive changes within v1, so every response type carries an index signature. A field added server-side is readable immediately, without upgrading this package and without a type error:

const match = await client.getMatch(18953);
match.some_new_field;   // readable — typed as `unknown`

The score shape (read this one)

games is player-major, not set-major:

score.games   // [[6, 3, 2], [4, 6, 1]]  ->  6-4, 3-6, 2-1
              //  ^p1 per set  ^p2 per set
score.sets    // [1, 1]
score.server  // 1 | 2

Indexing it the other way is the most common mistake made against this API, so there are helpers:

import { gamesForSet, formatScore } from 'livetennisapi';

gamesForSet(score, 0);   // [6, 4]
formatScore(score);      // '6-4 3-6 2-1 (40-30)'

Configuration

new LiveTennisAPI({
  apiKey: 'twjp_…',       // or $LIVETENNISAPI_KEY
  baseUrl: undefined,      // or $LIVETENNISAPI_BASE_URL
  timeout: 30_000,
  maxRetries: 2,
  authHeader: 'bearer',   // or 'x-api-key'
  fetch: undefined,       // inject a custom fetch
});

Contributing

Issues and pull requests welcome at livetennisapi/livetennisapi-js.

npm install
npm run test:unit                     # unit tests, offline
LIVETENNISAPI_KEY=twjp_… npm run test:contract   # verify against the live API

The contract tests assert the live API's real responses match these types. If the API and the spec disagree, that's a bug worth reporting.

Licence

MIT — see LICENSE. Use of the API service is governed by the Terms of Service.