Skip to main content

Endpoint Selection Guide

This guide helps you choose the right endpoint for fetching game data based on your specific use case.

Quick Reference

Use CaseRecommended EndpointWhy
Live scores dashboard/games/allscores5s TTL, all live games
Today’s fixtures/games/allscoresSingle-day aggregation
Team schedule/games/fixturesTeam-centric, paginated
Historical results/games/resultsPast games only, paginated
Competition-specific data/games/fixtures or /games/resultscompetitions filter works
Historical backfill/games/fixtures + /games/resultsPagination support
Single match details/games/gameFull match data

Endpoint Comparison

/games/allscores - Daily Live Scores

Best for: Live score dashboards, today’s matches across all competitions Key characteristics:
  • ✅ 5-second TTL for live data freshness
  • ✅ Aggregates all games for a date range
  • ✅ Supports onlyLiveGames filter
  • ⚠️ competitions parameter NOT honored - returns all competitions
  • ⚠️ Wide date ranges may return empty game arrays
  • ❌ No pagination
// ✅ Good: Single day, all competitions
const response = await fetch(
  `${BASE_URL}/games/allscores?startDate=18/01/2025&endDate=18/01/2025&sports=1&showOdds=true`,
  { headers: { 'x-api-key': API_KEY } }
);

// ⚠️ Avoid: Wide date range (may return no games)
// ⚠️ Avoid: Using competitions filter (will be ignored)

/games/fixtures - Team Fixtures

Best for: Team schedules, upcoming matches, competition-specific queries Key characteristics:
  • competitions parameter works correctly
  • ✅ Pagination support for large datasets
  • ✅ Returns both upcoming and past games
  • ✅ 5-minute TTL (300 seconds)
  • ✅ Includes competitionFilters for easy grouping
// Get all fixtures for a team
const fixtures = await fetch(
  `${BASE_URL}/games/fixtures?competitors=110&showOdds=true`,
  { headers: { 'x-api-key': API_KEY } }
);

// Filter to specific competition in your code
const data = await fixtures.json();
const eplGames = data.games.filter(g => g.competitionId === 7);

/games/results - Historical Results

Best for: Past match data, form analysis, historical backfills Key characteristics:
  • ✅ Only completed games (no upcoming fixtures)
  • ✅ Pagination support
  • ✅ 5-minute TTL (300 seconds)
  • ✅ Results in reverse chronological order
// Get team's recent results
const results = await fetch(
  `${BASE_URL}/games/results?competitors=110&showOdds=true`,
  { headers: { 'x-api-key': API_KEY } }
);

Common Patterns

Pattern 1: Live Score Dashboard

Use /games/allscores with single-day range and onlyLiveGames:
const today = new Date();
const dateStr = `${today.getDate().toString().padStart(2, '0')}/${(today.getMonth() + 1).toString().padStart(2, '0')}/${today.getFullYear()}`;

const response = await fetch(
  `${BASE_URL}/games/allscores?startDate=${dateStr}&endDate=${dateStr}&sports=1&onlyLiveGames=true&showOdds=true`,
  { headers: { 'x-api-key': API_KEY } }
);

const data = await response.json();
// Poll every 5-10 seconds using lastUpdateId for efficiency

Pattern 2: Competition-Specific Schedule

Use /games/fixtures and filter client-side:
// Get EPL team's fixtures
const response = await fetch(
  `${BASE_URL}/games/fixtures?competitors=110&showOdds=true`,
  { headers: { 'x-api-key': API_KEY } }
);

const data = await response.json();
const EPL_ID = 7;
const eplFixtures = data.games.filter(g => g.competitionId === EPL_ID);

Pattern 3: Historical Data Backfill

See the complete backfill examples below for Python and JavaScript implementations.

Historical EPL Data Backfill

Understanding Game and Match IDs

Each game has a unique id field that can be used with /games/game to get detailed match data:
// From fixtures/results response
const gameId = game.id; // e.g., 4609054

// Get full match details
const matchDetails = await fetch(
  `${BASE_URL}/games/game?gameId=${gameId}&showOdds=true`,
  { headers: { 'x-api-key': API_KEY } }
);

Python Backfill Example

import requests
from typing import List, Dict, Optional
import time

BASE_URL = "https://v1.football.sportsapipro.com"
API_KEY = "YOUR_API_KEY"
EPL_COMPETITION_ID = 7

def get_epl_teams() -> List[Dict]:
    """Get all EPL teams from standings."""
    response = requests.get(
        f"{BASE_URL}/standings",
        params={"competitions": EPL_COMPETITION_ID},
        headers={"x-api-key": API_KEY}
    )
    response.raise_for_status()
    data = response.json()
    
    teams = []
    for row in data.get("standings", []):
        competitor = row.get("competitor", {})
        teams.append({
            "id": competitor.get("id"),
            "name": competitor.get("name")
        })
    return teams

def fetch_team_results(team_id: int, max_pages: int = 5) -> List[Dict]:
    """Fetch paginated results for a team, filtered to EPL."""
    all_games = []
    next_page = f"/games/results?competitors={team_id}&showOdds=true"
    pages_fetched = 0
    
    while next_page and pages_fetched < max_pages:
        # Handle relative vs absolute URLs
        if next_page.startswith("/"):
            url = f"{BASE_URL}{next_page}"
        else:
            url = next_page
            
        response = requests.get(
            url,
            headers={"x-api-key": API_KEY}
        )
        response.raise_for_status()
        data = response.json()
        
        # Filter to EPL games only
        epl_games = [
            game for game in data.get("games", [])
            if game.get("competitionId") == EPL_COMPETITION_ID
        ]
        all_games.extend(epl_games)
        
        # Get next page
        paging = data.get("paging", {})
        next_page = paging.get("nextPage")
        pages_fetched += 1
        
        # Rate limiting
        time.sleep(0.5)
    
    return all_games

def fetch_team_fixtures(team_id: int, max_pages: int = 3) -> List[Dict]:
    """Fetch paginated fixtures for a team, filtered to EPL."""
    all_games = []
    next_page = f"/games/fixtures?competitors={team_id}&showOdds=true"
    pages_fetched = 0
    
    while next_page and pages_fetched < max_pages:
        if next_page.startswith("/"):
            url = f"{BASE_URL}{next_page}"
        else:
            url = next_page
            
        response = requests.get(
            url,
            headers={"x-api-key": API_KEY}
        )
        response.raise_for_status()
        data = response.json()
        
        # Filter to EPL upcoming games (statusGroup = 1)
        epl_fixtures = [
            game for game in data.get("games", [])
            if game.get("competitionId") == EPL_COMPETITION_ID
            and game.get("statusGroup") == 1
        ]
        all_games.extend(epl_fixtures)
        
        paging = data.get("paging", {})
        next_page = paging.get("nextPage")
        pages_fetched += 1
        
        time.sleep(0.5)
    
    return all_games

def backfill_epl_data():
    """Main backfill function."""
    teams = get_epl_teams()
    print(f"Found {len(teams)} EPL teams")
    
    all_results = {}
    all_fixtures = {}
    
    for team in teams:
        team_id = team["id"]
        team_name = team["name"]
        print(f"Fetching data for {team_name} (ID: {team_id})")
        
        # Get historical results
        results = fetch_team_results(team_id)
        all_results[team_id] = results
        print(f"  - {len(results)} EPL results")
        
        # Get upcoming fixtures
        fixtures = fetch_team_fixtures(team_id)
        all_fixtures[team_id] = fixtures
        print(f"  - {len(fixtures)} EPL fixtures")
        
        # Rate limiting between teams
        time.sleep(1)
    
    # Deduplicate games (same match appears for both teams)
    unique_results = {}
    for team_games in all_results.values():
        for game in team_games:
            unique_results[game["id"]] = game
    
    unique_fixtures = {}
    for team_games in all_fixtures.values():
        for game in team_games:
            unique_fixtures[game["id"]] = game
    
    print(f"\nTotal unique EPL results: {len(unique_results)}")
    print(f"Total unique EPL fixtures: {len(unique_fixtures)}")
    
    return {
        "results": list(unique_results.values()),
        "fixtures": list(unique_fixtures.values())
    }

if __name__ == "__main__":
    data = backfill_epl_data()
    
    # Example: Print last 5 results
    print("\nLast 5 EPL Results:")
    for game in sorted(data["results"], key=lambda x: x["startTime"], reverse=True)[:5]:
        home = game["homeCompetitor"]
        away = game["awayCompetitor"]
        print(f"  {home['name']} {home['score']:.0f} - {away['score']:.0f} {away['name']}")

JavaScript Backfill Example

const BASE_URL = "https://v1.football.sportsapipro.com";
const API_KEY = "YOUR_API_KEY";
const EPL_COMPETITION_ID = 7;

async function fetchWithRetry(url, options, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url, options);
      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      return await response.json();
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(r => setTimeout(r, 1000 * (i + 1)));
    }
  }
}

async function getEplTeams() {
  const data = await fetchWithRetry(
    `${BASE_URL}/standings?competitions=${EPL_COMPETITION_ID}`,
    { headers: { "x-api-key": API_KEY } }
  );
  
  return data.standings?.map(row => ({
    id: row.competitor?.id,
    name: row.competitor?.name
  })) || [];
}

async function fetchTeamResults(teamId, maxPages = 5) {
  const allGames = [];
  let nextPage = `/games/results?competitors=${teamId}&showOdds=true`;
  let pagesFetched = 0;
  
  while (nextPage && pagesFetched < maxPages) {
    const url = nextPage.startsWith("/") 
      ? `${BASE_URL}${nextPage}` 
      : nextPage;
    
    const data = await fetchWithRetry(url, {
      headers: { "x-api-key": API_KEY }
    });
    
    // Filter to EPL games
    const eplGames = (data.games || []).filter(
      game => game.competitionId === EPL_COMPETITION_ID
    );
    allGames.push(...eplGames);
    
    nextPage = data.paging?.nextPage;
    pagesFetched++;
    
    // Rate limiting
    await new Promise(r => setTimeout(r, 500));
  }
  
  return allGames;
}

async function fetchTeamFixtures(teamId, maxPages = 3) {
  const allGames = [];
  let nextPage = `/games/fixtures?competitors=${teamId}&showOdds=true`;
  let pagesFetched = 0;
  
  while (nextPage && pagesFetched < maxPages) {
    const url = nextPage.startsWith("/") 
      ? `${BASE_URL}${nextPage}` 
      : nextPage;
    
    const data = await fetchWithRetry(url, {
      headers: { "x-api-key": API_KEY }
    });
    
    // Filter to EPL upcoming games
    const eplFixtures = (data.games || []).filter(
      game => game.competitionId === EPL_COMPETITION_ID && game.statusGroup === 1
    );
    allGames.push(...eplFixtures);
    
    nextPage = data.paging?.nextPage;
    pagesFetched++;
    
    await new Promise(r => setTimeout(r, 500));
  }
  
  return allGames;
}

async function backfillEplData() {
  console.log("Fetching EPL teams...");
  const teams = await getEplTeams();
  console.log(`Found ${teams.length} EPL teams`);
  
  const allResults = new Map();
  const allFixtures = new Map();
  
  for (const team of teams) {
    console.log(`Fetching data for ${team.name} (ID: ${team.id})`);
    
    const results = await fetchTeamResults(team.id);
    results.forEach(game => allResults.set(game.id, game));
    console.log(`  - ${results.length} EPL results`);
    
    const fixtures = await fetchTeamFixtures(team.id);
    fixtures.forEach(game => allFixtures.set(game.id, game));
    console.log(`  - ${fixtures.length} EPL fixtures`);
    
    // Rate limiting between teams
    await new Promise(r => setTimeout(r, 1000));
  }
  
  const uniqueResults = Array.from(allResults.values());
  const uniqueFixtures = Array.from(allFixtures.values());
  
  console.log(`\nTotal unique EPL results: ${uniqueResults.length}`);
  console.log(`Total unique EPL fixtures: ${uniqueFixtures.length}`);
  
  return { results: uniqueResults, fixtures: uniqueFixtures };
}

// Run backfill
backfillEplData()
  .then(data => {
    console.log("\nLast 5 EPL Results:");
    const sorted = data.results.sort((a, b) => 
      new Date(b.startTime) - new Date(a.startTime)
    );
    sorted.slice(0, 5).forEach(game => {
      const home = game.homeCompetitor;
      const away = game.awayCompetitor;
      console.log(`  ${home.name} ${home.score} - ${away.score} ${away.name}`);
    });
  })
  .catch(console.error);

Efficient Polling with lastUpdateId

For live score applications, use lastUpdateId to fetch only changes:
let lastUpdateId = -1;

async function pollLiveScores() {
  const today = new Date();
  const dateStr = `${today.getDate().toString().padStart(2, '0')}/${(today.getMonth() + 1).toString().padStart(2, '0')}/${today.getFullYear()}`;
  
  const params = new URLSearchParams({
    startDate: dateStr,
    endDate: dateStr,
    sports: "1",
    showOdds: "true",
    onlyLiveGames: "true"
  });
  
  // Only add lastUpdateId after first request
  if (lastUpdateId > 0) {
    params.append("lastUpdateId", lastUpdateId.toString());
  }
  
  const response = await fetch(
    `${BASE_URL}/games/allscores?${params}`,
    { headers: { "x-api-key": API_KEY } }
  );
  
  const data = await response.json();
  
  // Store for next request
  lastUpdateId = data.lastUpdateId;
  
  // Process only changed data
  if (data.games?.length > 0) {
    console.log(`Received ${data.games.length} updated games`);
    updateUI(data.games);
  }
}

// Poll every 5-10 seconds
setInterval(pollLiveScores, 5000);

Summary

ScenarioEndpointKey Parameters
Live dashboard/games/allscoresonlyLiveGames=true, single day
Team profile/games/fixturescompetitors={teamId}
Historical analysis/games/resultscompetitors={teamId}
Competition schedule/games/fixturesFilter by competitionId in response
Backfill data/games/results + /games/fixturesUse pagination
Always filter by competitionId client-side when using /games/fixtures or /games/results, as these endpoints return all competitions a team participates in.