SportMonks TypeScript SDK

A comprehensive, production-ready TypeScript SDK for the SportMonks Football API v3. Built with modern TypeScript, featuring complete type safety, intuitive method chaining, automatic retries, real-time polling, and extensive test coverage.

Features

  • ๐Ÿš€ Full TypeScript Support - Complete type definitions for all 50+ entities and responses
  • ๐Ÿ”— Intuitive Method Chaining - Fluent API design for building complex queries naturally
  • ๐Ÿ“ฆ Comprehensive Coverage - 10 resources with 56 endpoints covering all major football data
  • ๐Ÿ”„ Smart Retry Logic - Automatic retry with exponential backoff and rate limit awareness
  • ๐Ÿ“Š Real-time Updates - Built-in polling utilities for livescores and transfer monitoring
  • โœ… Input Validation - Automatic validation of dates, IDs, and search queries with helpful errors
  • ๐ŸŽฏ Type-safe Includes - Full TypeScript support for relationship includes
  • ๐Ÿ“ˆ Performance Optimized - Efficient pagination, response caching, and minimal dependencies
  • ๐Ÿงช Battle-tested - 330+ tests with 97.7% coverage and real API validation
  • ๐Ÿ“ Extensive Documentation - Comprehensive JSDoc comments, examples, and guides

Quick Example

import { SportMonksClient } from '@withqwerty/sportmonks-typescript-sdk';

const client = new SportMonksClient('YOUR_API_KEY');

// Get fixtures for today with team and venue information
const fixtures = await client.fixtures
  .byDate('2024-01-15')
  .include(['participants', 'scores', 'venue'])
  .get();

// Search for teams with pagination
const teams = await client.teams.search('Manchester').page(1).perPage(10).get();

Why Use This SDK?

Type Safety

Every API response is fully typed, giving you IntelliSense support and compile-time error checking.

Intuitive API

The method chaining approach makes building complex queries feel natural and readable.

Production Ready

With automatic retries, rate limit handling, and comprehensive error messages, this SDK is built for production use.

Well Tested

Over 330 tests ensure reliability, with both unit tests and integration tests against the real API.

Next Steps

Installation

npm install @withqwerty/sportmonks-typescript-sdk

Or with yarn:

yarn add @withqwerty/sportmonks-typescript-sdk

Requirements

  • Node.js 14.0 or higher
  • TypeScript 4.0 or higher (if using TypeScript)

API Key

Youโ€™ll need a SportMonks API key. Get one at SportMonks

Quick Start

Configuration

Client Setup

Method Chaining

Include Separator

Error Handling

Rate Limiting

Leagues Resource

Teams Resource

Players Resource

Fixtures Resource

Standings Resource

Livescores Resource

Transfers Resource

Coaches Resource

Referees Resource

Venues Resource

Type Helpers Guide

The SportMonks TypeScript SDK includes utility types and functions to make working with API responses even more type-safe.

Type Guards

hasInclude()

Check if an optional include is present and get proper type inference:

import { hasInclude } from '@withqwerty/sportmonks-typescript-sdk';

const team = await client.teams.byId(1).include(['country', 'venue']).get();

if (hasInclude(team.data, 'country')) {
  // TypeScript now knows team.data.country is defined
  console.log(team.data.country.name); // โœ… No type errors
}

hasData()

Type guard for responses with data:

import { hasData } from '@withqwerty/sportmonks-typescript-sdk';

const response = await client.teams.byId(1).get();

if (hasData(response)) {
  // TypeScript knows response.data exists
  console.log(response.data.name);
}

isPaginatedResponse() / isSingleResponse()

Distinguish between response types:

import { isPaginatedResponse, isSingleResponse } from '@withqwerty/sportmonks-typescript-sdk';

const response = await client.teams.all().get();

if (isPaginatedResponse(response)) {
  // response.data is Team[]
  response.data.forEach(team => console.log(team.name));
} else if (isSingleResponse(response)) {
  // response.data is Team
  console.log(response.data.name);
}

Type Helpers

ExtractData<T>

Extract the data type from any response:

import {
  ExtractData,
  SingleResponse,
  PaginatedResponse
} from '@withqwerty/sportmonks-typescript-sdk';

type TeamData = ExtractData<SingleResponse<Team>>; // Team
type TeamsData = ExtractData<PaginatedResponse<Team>>; // Team[]

WithRequired<T, K>

Make optional properties required when you know theyโ€™re included:

import { WithRequired, Team } from '@withqwerty/sportmonks-typescript-sdk';

// Make country required on Team type
type TeamWithCountry = WithRequired<Team, 'country'>;

// Make multiple properties required
type TeamWithAll = WithRequired<Team, 'country' | 'venue' | 'coach'>;

Pre-defined Include Types

Common include combinations are pre-defined for convenience:

import {
  TeamWithCountry,
  TeamWithVenue,
  TeamWithAll,
  FixtureWithTeams,
  FixtureWithEvents,
  PlayerWithTeam
} from '@withqwerty/sportmonks-typescript-sdk';

// Use in your functions
function processTeamWithCountry(team: TeamWithCountry) {
  // country is guaranteed to exist
  console.log(`${team.name} from ${team.country.name}`);
}

Utility Functions

getNestedInclude()

Safely access nested include properties:

import { getNestedInclude } from '@withqwerty/sportmonks-typescript-sdk';

const team = await client.teams.byId(1).include(['country']).get();

// Safe access - returns undefined if not present
const countryName = getNestedInclude(team.data, 'country', 'name');
const countryCode = getNestedInclude(team.data, 'country', 'code');

Filter Helpers

Type-safe filter functions:

import { isNationalTeam } from '@withqwerty/sportmonks-typescript-sdk';

const teams = await client.teams.all().get();
const nationalTeams = teams.data.filter(isNationalTeam);

Sort Helpers

Type-safe sorting functions:

import { sortByName, sortByCapacity } from '@withqwerty/sportmonks-typescript-sdk';

// Sort teams by name
const sortedTeams = teams.data.sort(sortByName);

// Sort venues by capacity (descending)
const sortedVenues = venues.data.sort(sortByCapacity);

Response Transformers

Create typed transformers for responses:

import { createTransformer, PaginatedResponse, Team } from '@withqwerty/sportmonks-typescript-sdk';

// Create a transformer that extracts team names
const toTeamNames = createTransformer<PaginatedResponse<Team>, string[]>(response =>
  response.data.map(team => team.name)
);

// Use it
const response = await client.teams.all().get();
const names = toTeamNames(response); // string[]

Complete Example

Hereโ€™s how to use multiple type helpers together:

import {
  SportMonksClient,
  hasInclude,
  isPaginatedResponse,
  TeamWithCountry,
  sortByName
} from '@withqwerty/sportmonks-typescript-sdk';

const client = new SportMonksClient(API_KEY);

async function getTeamsByCountry(countryName: string) {
  const response = await client.teams.all().include(['country']).perPage(100).get();

  if (!isPaginatedResponse(response)) {
    throw new Error('Unexpected response type');
  }

  // Filter teams with type safety
  const teamsFromCountry = response.data.filter((team): team is TeamWithCountry => {
    return hasInclude(team, 'country') && team.country.name === countryName;
  });

  // Sort and return
  return teamsFromCountry.sort(sortByName);
}

// Usage
const englishTeams = await getTeamsByCountry('England');
englishTeams.forEach(team => {
  console.log(`${team.name} - ${team.country.name}`); // โœ… Type safe!
});

Benefits

  1. Type Safety: Eliminate runtime errors from accessing undefined includes
  2. Better IntelliSense: Get proper autocomplete for included properties
  3. Cleaner Code: Use type guards instead of manual checks
  4. Reusability: Pre-defined types for common include patterns

Polling Utilities

Custom Includes

Validation

SportMonks SDK REPL (Interactive Console)

The SportMonks TypeScript SDK includes an interactive REPL (Read-Eval-Print Loop) for testing and exploring the API.

Installation & Usage

When installed via npm

After installing the SDK, you can use the REPL directly:

# Install the SDK
npm install @withqwerty/sportmonks-typescript-sdk

# Run the REPL
npx sportmonks-repl

# Run the advanced REPL
npx sportmonks-repl --advanced

When developing locally

If youโ€™re working with the SDK source code:

# Simple REPL
npm run repl

# Advanced REPL
npm run repl:advanced

Features

  • ๐Ÿš€ Interactive console with full SDK access
  • ๐Ÿ” Autocomplete support for resources and methods
  • ๐Ÿ“ Command history (persisted between sessions)
  • ๐ŸŽจ Syntax highlighting and colored output
  • ๐Ÿ“š Built-in examples and documentation
  • ๐Ÿ› ๏ธ Helper functions for data exploration

Getting Started

1. Set up your API key

Create a .env file in the project root:

SPORTMONKS_API_KEY=your_api_key_here

Or set it as an environment variable:

export SPORTMONKS_API_KEY=your_api_key_here

2. Start the REPL

npm run repl

Basic Usage

Simple Queries

// Get all leagues (limited to 5)
await client.leagues.all().limit(5).get();

// Get a specific team with includes
await client.teams.byId(1).include(['country', 'venue']).get();

// Search for players
await client.players.search('Ronaldo').limit(10).get();

Using Includes

// Get fixtures with team information
await client.fixtures.byDate('2024-01-15').include(['localteam', 'visitorteam']).get();

// Get league with nested includes
await client.leagues.byId(8).include(['country', 'seasons.stages']).get();

Complex Queries

// Filter national teams in a season
await client.teams.bySeason(19735).include(['country']).filter('national_team', 'true').get();

// Get head-to-head with full match details
await client.fixtures.headToHead(1, 14).include(['events', 'lineups']).limit(5).get();

// Get transfers between dates
await client.transfers
  .between('2024-01-01', '2024-01-31')
  .include(['player', 'fromteam', 'toteam'])
  .get();

Helper Functions

pp(response) - Pretty Print

Pretty prints the entire response object with proper formatting:

const response = await client.leagues.all().limit(3).get();
pp(response);

data(response) - Extract Data

Prints only the data array from the response:

const response = await client.teams.search('Manchester').get();
data(response);

examples() - Show Examples

Displays example queries you can run:

sportmonks > examples();

resources() - List Resources

Shows all available resources and their methods:

sportmonks > resources();

Available Resources

  • leagues - Football leagues and competitions
  • teams - Football teams
  • players - Player information
  • fixtures - Matches and game data
  • seasons - Season information
  • squads - Team squads by season
  • standings - League tables and standings
  • transfers - Player transfers
  • venues - Stadium information
  • coaches - Coach/manager data
  • referees - Referee information
  • livescores - Live match data

Protected Resources

The REPL automatically protects built-in resources and functions from being overwritten. If you try to use a protected name as a variable, youโ€™ll get a helpful error:

// This will trigger a protective error:
const players = await players.search('Salah').get();

// Error message will suggest alternatives:
// Cannot use 'players' as a variable name!
// 'players' is a SportMonks resource and cannot be overwritten.
// Try using a different name like:
//   const playersResult = await players.search(...).get()
//   const myPlayers = await players.all().get()

Protected names include:

  • All resources: leagues, teams, players, fixtures, etc.
  • Helper functions: pp, data, type, browse, save
  • System variables: client, _

Tips and Tricks

1. Use Tab Completion

Press Tab to autocomplete resource names and methods:

sportmonks> client.lea[TAB]
sportmonks> client.leagues

2. Store Results in Variables

const leagues = await client.leagues.all().limit(10).get();
const premierLeague = leagues.data.find(l => l.name.includes('Premier'));

3. Explore Response Structure

const response = await client.teams.byId(1).get();
Object.keys(response); // See available fields

4. Use Async/Await

All API calls return promises, so use await:

// Good
const data = await client.players.byId(580).get();

// Without await (returns Promise)
const promise = client.players.byId(580).get();

5. Chain Multiple Operations

const teams = await client.teams
  .bySeason(19735)
  .include(['country', 'venue'])
  .filter('national_team', 'false')
  .page(1)
  .perPage(30)
  .get();

Keyboard Shortcuts

  • Tab - Autocomplete
  • โ†‘/โ†“ - Navigate command history
  • Ctrl+C - Cancel current input
  • Ctrl+D or .exit - Exit REPL
  • Ctrl+L - Clear screen

Error Handling

The REPL will show detailed error messages:

// API errors show full details
await client.teams.byId(999999).get();
// Error: Request failed with status code 404

// Validation errors
await client.fixtures.byDate('invalid-date').get();
// Error: Invalid date format: invalid-date. Expected YYYY-MM-DD

Environment Variables

  • SPORTMONKS_API_KEY - Your SportMonks API key
  • SPORTMONKS_TEST_API_KEY - Alternative key for testing

Notes

  • The REPL maintains a history file (.sportmonks_repl_history) for command persistence
  • All SDK features are available in the REPL
  • The client is pre-initialized and available as client
  • Use require() to load additional modules if needed

Examples

API Documentation

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[1.1.0] - 2024-12-01

Changed

  • IMPORTANT: Changed default include separator from comma (,) to semicolon (;) to match SportMonks API requirements for multiple includes
  • Updated all unit tests to use semicolon separator for multiple includes
  • Improved TypeScript types by replacing any with proper types in type helpers and validators

Added

  • Input validation for PlayersResource:
    • ID validation in byId() and byCountry() methods
    • Search query validation with minimum length check
  • Type helper utilities in src/utils/type-helpers.ts:
    • hasInclude() - Type guard to check if an include exists
    • hasData() - Type guard for responses with data
    • isPaginatedResponse() - Type guard for paginated responses
    • isSingleResponse() - Type guard for single responses
    • WithRequired<T, K> - Type helper to make optional properties required
    • Pre-defined types like TeamWithCountry, FixtureWithTeams, etc.
  • Documentation for type helpers (docs/TYPE_HELPERS.md)
  • ESLint configuration for test files (tsconfig.eslint.json)
  • Global REPL command accessible via npx sportmonks-repl when installed via npm

Fixed

  • Integration test failures:
    • Updated players test to use Denmark (ID: 320) instead of Brazil for European Plan compatibility
    • Updated fixtures pagination test to use dates with more fixtures (2025-03-30)
    • Skipped latest fixtures test due to subscription limitations
  • ESLint configuration to properly lint test files
  • Prettier formatting in type helpers and test files
  • Test coverage improved to 97.7%

Developer Notes

  • The include separator change maintains backwards compatibility for single includes
  • Multiple includes now require semicolon separation (e.g., include: 'country;venue')
  • Field selectors within includes still use commas (e.g., include: 'team:name,short_code')

[1.0.2] - 2025-05-31

Added

  • Interactive REPL (Read-Eval-Print Loop) for testing and exploring the API
    • Simple REPL with direct resource access (npm run repl)
    • Advanced REPL with additional features (npm run repl:advanced)
    • Helper functions: pp(), data(), examples(), resources()
    • Command history persistence
    • No need to type client. prefix - direct access to resources

Fixed

  • Fixed fixtures resource documentation (removed non-existent live() method)
  • Clarified that live matches are accessed via livescores.inplay()

Changed

  • Moved REPL tools from scripts/ to tools/ directory for better organization

[1.0.1] - 2025-05-31

Changed

  • Updated all dev dependencies to latest stable versions
  • Migrated from ESLint v8 to v9 with new flat config format
  • Updated husky to v9 simplified format
  • Fixed CI/CD workflow issues (updated upload-artifact to v4)

Fixed

  • Removed all deprecation warnings
  • Fixed unused variable ESLint errors

Removed

  • Deprecated @types/dotenv package (dotenv now includes its own types)

[1.0.0] - 2025-05-31

Added

  • Initial release of SportMonks TypeScript SDK
  • Full TypeScript support with comprehensive type definitions
  • Support for 10 resources with 56 endpoints:
    • Leagues (8 endpoints): all, byId, byCountry, search, live, byDate, byTeam, currentByTeam
    • Teams (5 endpoints): all, byId, byCountry, bySeason, search
    • Players (5 endpoints): all, byId, byCountry, search, latest
    • Fixtures (13 endpoints): all, byId, byIds, byDate, byDateRange, byTeamAndDateRange, byTeamAndSeason, headToHead, search, byLivescores, byFixtureMulti, latest, byTvStation
    • Standings (5 endpoints): all, bySeasonId, byRoundId, bySeasonIdCorrected, liveByLeagueId
    • Livescores (3 endpoints): all, inplay, latest
    • Transfers (6 endpoints): all, byId, latest, byDateRange, byPlayerId, byTeamId
    • Coaches (5 endpoints): all, byId, byCountryId, byTeamId, search
    • Referees (5 endpoints): all, byId, byCountryId, bySeasonId, search
    • Venues (4 endpoints): all, byId, bySeasonId, search
  • Method chaining for intuitive query building
  • Automatic retry logic with exponential backoff
  • Real-time polling utilities for livescores and transfers
  • Input validation for dates, IDs, and search queries
  • Rate limit information in responses
  • Comprehensive error handling with detailed messages
  • Support for includes, filters, pagination, and sorting
  • Custom include separator support (for transfers endpoint)
  • Enhanced support for SportMonksโ€™ advanced query syntax
    • includeFields() method for field selection on includes
    • withIncludes() method for complex include configurations
    • Support for multiple filter values using arrays
    • SportMonksSyntaxBuilder utility for programmatic query building
    • Full TypeScript types for SportMonks syntax patterns
  • Comprehensive test coverage improvements (97.62% coverage)

Features

  • Type Safety: Strong TypeScript types for all entities and API responses
  • Method Chaining: Fluent API design for building complex queries
  • Error Handling: Detailed error messages with context
  • Retry Logic: Automatic retries with exponential backoff for failed requests
  • Polling Utilities: Built-in support for real-time data updates
  • Validation: Input validation for common parameters
  • Flexible Configuration: Customizable timeout, base URL, and include separator

Testing

  • Comprehensive test suite with 330+ tests
  • Unit tests for all resources and utilities
  • Integration tests with real API (when API key provided)
  • 97.62% code coverage

Documentation

  • Complete README with installation and usage instructions
  • JSDoc comments on all public methods
  • Examples for all major use cases
  • Migration guide for future versions

Migration Guide

Contributing