TUTORIAL

    How to Get Football Match Data with a REST API

    Step-by-step tutorial: how to fetch football match data using a REST API. Includes working code examples in Python and JavaScript. Start for free with TheStatsAPI.

    Last updated: March 22, 20267 min read

    If you are building a football app, a stats dashboard, or a prediction model, the first thing you need is reliable match data. Scores, fixtures, dates, teams, competitions - all of it, delivered in a structured format your code can actually use.

    This tutorial walks you through how to get football match data from a REST API, step by step. We will use TheStatsAPI as our data source because it covers 1,196 competitions and 84,000+ players with a clean REST JSON interface, and you can start with a 7-day free trial. By the end of this guide, you will have working code in both Python and JavaScript that fetches real match data and handles common edge cases.

    Prerequisites

    Before we start, make sure you have:

    • Python 3.8+ or Node.js 18+ installed (we will show both)
    • A code editor (VS Code, PyCharm, or anything you prefer)
    • Basic familiarity with HTTP requests and JSON
    • A TheStatsAPI account (we will set this up in the next section)

    No frameworks or complex dependencies are required. We are working directly with HTTP requests to keep things simple and transferable to any stack.

    Getting Your API Key

    Every request to TheStatsAPI requires a Bearer token in the Authorization header. Here is how to get one:

    1. Go to thestatsapi.com and click Start Free Trial.
    2. Create your account. The 7-day trial gives you full access to every endpoint and all 1,196 competitions.
    3. Once logged in, navigate to the Dashboard. Your API key is displayed on the main dashboard page.
    4. Copy the key and store it somewhere safe. You will use it in every API call.

    Your API key looks like a long alphanumeric string. Treat it like a password - do not commit it to public repositories or share it in client-side code.

    Your First API Call in Python

    Let's fetch today's football matches. Install the requests library if you do not already have it:

    pip install requests
    

    Now create a file called matches.py:

    import requests
    
    API_KEY = "your_api_key_here"
    BASE_URL = "https://api.thestatsapi.com/api"
    
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Accept": "application/json"
    }
    
    response = requests.get(f"{BASE_URL}/football/matches", headers=headers)
    
    if response.status_code == 200:
        data = response.json()
        matches = data.get("data", [])
        print(f"Found {len(matches)} matches\n")
    
        for match in matches[:10]:
            home = match["home_team"]["name"]
            away = match["away_team"]["name"]
            score_home = match.get("home_score", "-")
            score_away = match.get("away_score", "-")
            status = match.get("status", "unknown")
            print(f"{home} {score_home} - {score_away} {away} [{status}]")
    else:
        print(f"Error: {response.status_code}")
        print(response.text)
    

    Run it:

    python matches.py
    

    You should see a list of matches with team names, scores, and match status. The response includes match metadata like the competition name, round, venue, and timestamps - everything you need to build a fixture list or results page.

    Understanding the Response

    Each match object in the data array includes fields like:

    • id - unique match identifier
    • home_team and away_team - team objects with id, name, and other details
    • home_score and away_score - final or current scores
    • status - match status (e.g., finished, scheduled, postponed)
    • date - match date and time in ISO 8601 format
    • competition - the league or cup this match belongs to
    • season - the season context

    Fetching Matches by Competition

    In most real applications, you do not want every match from every league. You want matches from a specific competition. Use the competition_id query parameter to filter:

    import requests
    
    API_KEY = "your_api_key_here"
    BASE_URL = "https://api.thestatsapi.com/api"
    
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Accept": "application/json"
    }
    
    # Fetch Premier League matches
    params = {
        "competition_id": 1,  # Replace with the actual competition ID
    }
    
    response = requests.get(
        f"{BASE_URL}/football/matches",
        headers=headers,
        params=params
    )
    
    data = response.json()
    matches = data.get("data", [])
    
    print(f"Found {len(matches)} matches in this competition\n")
    
    for match in matches[:5]:
        date = match["date"][:10]
        home = match["home_team"]["name"]
        away = match["away_team"]["name"]
        score_home = match.get("home_score", "-")
        score_away = match.get("away_score", "-")
        print(f"[{date}] {home} {score_home} - {score_away} {away}")
    

    Handling Pagination

    When a competition has hundreds of matches, the API paginates results. The response includes pagination metadata:

    data = response.json()
    
    current_page = data["meta"]["current_page"]
    last_page = data["meta"]["last_page"]
    total = data["meta"]["total"]
    
    print(f"Page {current_page} of {last_page} ({total} total matches)")
    

    To fetch all pages, loop through them:

    all_matches = []
    page = 1
    
    while True:
        params = {"competition_id": 1, "page": page}
        response = requests.get(
            f"{BASE_URL}/football/matches",
            headers=headers,
            params=params
        )
        data = response.json()
        all_matches.extend(data["data"])
    
        if page >= data["meta"]["last_page"]:
            break
        page += 1
    
    print(f"Fetched {len(all_matches)} total matches")
    

    JavaScript Version with fetch()

    Here is the same workflow in JavaScript using the built-in fetch API (Node.js 18+ or any modern browser):

    const API_KEY = "your_api_key_here";
    const BASE_URL = "https://api.thestatsapi.com/api";
    
    async function getMatches(competitionId) {
      const url = new URL(`${BASE_URL}/football/matches`);
      if (competitionId) {
        url.searchParams.set("competition_id", competitionId);
      }
    
      const response = await fetch(url, {
        headers: {
          Authorization: `Bearer ${API_KEY}`,
          Accept: "application/json",
        },
      });
    
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }
    
      const data = await response.json();
      return data;
    }
    
    async function main() {
      try {
        const result = await getMatches();
        const matches = result.data;
    
        console.log(`Found ${matches.length} matches\n`);
    
        matches.slice(0, 10).forEach((match) => {
          const home = match.home_team.name;
          const away = match.away_team.name;
          const scoreHome = match.home_score ?? "-";
          const scoreAway = match.away_score ?? "-";
          console.log(`${home} ${scoreHome} - ${scoreAway} ${away}`);
        });
      } catch (error) {
        console.error("Failed to fetch matches:", error.message);
      }
    }
    
    main();
    

    To paginate in JavaScript:

    async function getAllMatches(competitionId) {
      let allMatches = [];
      let page = 1;
      let lastPage = 1;
    
      do {
        const url = new URL(`${BASE_URL}/football/matches`);
        url.searchParams.set("competition_id", competitionId);
        url.searchParams.set("page", page);
    
        const response = await fetch(url, {
          headers: {
            Authorization: `Bearer ${API_KEY}`,
            Accept: "application/json",
          },
        });
    
        const data = await response.json();
        allMatches = allMatches.concat(data.data);
        lastPage = data.meta.last_page;
        page++;
      } while (page <= lastPage);
    
      return allMatches;
    }
    

    Common Errors and How to Fix Them

    When working with any REST API, you will encounter HTTP errors. Here are the three most common ones and how to handle them.

    401 Unauthorized

    Your API key is missing, invalid, or expired.

    HTTP 401: Unauthorized
    

    Fix: Double-check your API key. Make sure the Authorization header uses the format Bearer your_api_key_here - with the word "Bearer" followed by a space. If your trial has expired, you will need to subscribe to a plan.

    429 Too Many Requests

    You have exceeded the rate limit for your plan.

    HTTP 429: Too Many Requests
    

    Fix: TheStatsAPI rate limits are 30 requests per minute on the Starter plan, 60/min on Growth, and 300/min on Scale. Add a delay between requests when fetching in bulk:

    import time
    
    for page in range(1, total_pages + 1):
        response = requests.get(url, headers=headers, params={"page": page})
        if response.status_code == 429:
            print("Rate limited. Waiting 60 seconds...")
            time.sleep(60)
            response = requests.get(url, headers=headers, params={"page": page})
        # process response...
        time.sleep(2)  # 2-second delay between requests
    

    404 Not Found

    The endpoint or resource ID does not exist.

    HTTP 404: Not Found
    

    Fix: Verify the URL path and any IDs you are passing. A competition_id of 99999 will return a 404 if that competition does not exist. Use the competitions endpoint first to get valid IDs.

    Next Steps

    You now know how to fetch football match data from a REST API, filter by competition, handle pagination, and deal with common errors. Here are some directions to take this further:

    • Add player statistics. Use the /football/players/{id}/stats endpoint to pull goals, assists, and appearances for any player. See our player stats tutorial for a complete walkthrough.
    • Build a dashboard. Combine match data with a frontend framework like Next.js to create a live stats dashboard. Our Next.js tutorial covers this end to end.
    • Fetch historical data. TheStatsAPI includes 20+ years of match history - perfect for building prediction models or analyzing trends. Check the historical data guide.
    • Explore all 1,196 competitions. Start with the /football/competitions endpoint to browse all available leagues and cups, then filter matches by any competition you need.

    TheStatsAPI offers a 7-day free trial on all plans, giving full access to all 1,196 competitions and 84,000+ players - making it the best way to evaluate a premium football API before committing. Sign up at thestatsapi.com and start building.

    Start building today

    Ready to Power Your Sports App?

    Start your 7-day free trial. All endpoints included on every plan.

    Cancel anytime
    7-day free trial
    Setup in 5 minutes