Endpoint Selection Guide
This guide helps you choose the right endpoint for fetching game data based on your specific use case.
Quick Reference
| Use Case | Recommended Endpoint | Why |
|---|
| Live scores dashboard | /games/allscores | 5s TTL, all live games |
| Today’s fixtures | /games/allscores | Single-day aggregation |
| Team schedule | /games/fixtures | Team-centric, paginated |
| Historical results | /games/results | Past games only, paginated |
| Competition-specific data | /games/fixtures or /games/results | competitions filter works |
| Historical backfill | /games/fixtures + /games/results | Pagination support |
| Single match details | /games/game | Full 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
| Scenario | Endpoint | Key Parameters |
|---|
| Live dashboard | /games/allscores | onlyLiveGames=true, single day |
| Team profile | /games/fixtures | competitors={teamId} |
| Historical analysis | /games/results | competitors={teamId} |
| Competition schedule | /games/fixtures | Filter by competitionId in response |
| Backfill data | /games/results + /games/fixtures | Use pagination |
Always filter by competitionId client-side when using /games/fixtures or /games/results, as these endpoints return all competitions a team participates in.