TypeScript SDK
Zero runtime dependencies, ESM and CommonJS with types, for Node 22+, Deno, Bun, browsers and edge runtimes. Every endpoint is a typed method.
Install
One package, no setup beyond your API key.
$ npm install github:sportsapiapp/sportsapi-js # until it is published to npm $ npm install sportsapi # once it is
Authenticate
Use the API key from your dashboard. Pass it to the client, or set SPORTSAPI_API_KEY and the client reads it.
import { SportsAPI } from 'sportsapi'; const client = new SportsAPI({ apiKey: process.env.SPORTSAPI_API_KEY }); // or leave apiKey out: SPORTSAPI_API_KEY is read by default
First calls
Every method returns the API's { data, meta } envelope, typed. Path parameters come first, in path order, then the query parameters with the API's own names.
const { data: live } = await client.livescores.list({ sport: 'football' }); const { data: table, meta } = await client.leagues.standings(17, { season: 61627 }); const { data: lineups } = await client.fixtures.lineups(211521);
Errors
One error type per HTTP status, each carrying the API's code, message and Retry-After. Branch on the code, never on the message.
import { NotFoundError, PermissionDeniedError } from 'sportsapi'; try { await client.fixtures.winProbability(211521); } catch (e) { if (e instanceof PermissionDeniedError) console.error(e.code); // endpoint_not_in_plan, … if (e instanceof NotFoundError) console.error(e.code); // not_found | no_data | not_supported }
Paging
Every endpoint with a page parameter has a pages iterator that walks the pages until there are no more.
for await (const page of client.teams.fixturesPages(42, { type: 'recent' }, { maxPages: 5 })) { console.log(page.meta.page, page.data.length); }
WebSocket stream (Business)
The stream mints its own single-use ticket, subscribes, reconnects and replays what it missed, and merges every delta into the fixtures it holds.
const stream = client.stream(['livescores', 'fixture:211521']); stream.on('delta', (frame) => console.log(frame.id, frame.changes)); stream.on('error', (err) => console.error(err)); // the merged state, current at any time console.log(stream.fixtures('livescores').length, 'live'); stream.close();
Options
A 429 rate_limited or a 503 is retried after Retry-After (twice by default); a quota error never is.
new SportsAPI({ apiKey, // or SPORTSAPI_API_KEY baseUrl, // or SPORTSAPI_BASE_URL timeout: 30_000, // ms per attempt maxRetries: 2, });