TUTORIAL

How to Get Football Data with PHP - Complete API Tutorial

Step-by-step PHP tutorial for fetching football fixtures, match stats, player stats and odds via API. Includes working cURL code examples you can copy.

5 min read

PHP still powers a huge share of the web, from Laravel apps to WordPress plugins. If you are adding football data to a PHP project, TheStatsAPI is a plain REST JSON API, so you only need cURL and json_decode.

This tutorial shows how to fetch football data with PHP: competitions, fixtures, match stats, player season stats, and pre-match odds. Every example reuses one small helper function.

Prerequisites

You need:

  • PHP 8.0+ with the cURL extension (enabled by default on most installs)
  • A TheStatsAPI API key

Set your API key as an environment variable:

export THESTATSAPI_KEY="your_api_key"

If you do not have a key yet, sign up at thestatsapi.com for a 7-day free trial.

Create a Small API Client

Create football_api.php:

<?php

function tsapi_get(string $endpoint, array $params = []): array
{
    $apiKey = getenv('THESTATSAPI_KEY');
    $baseUrl = 'https://api.thestatsapi.com/api';

    $url = $baseUrl . $endpoint;
    if (!empty($params)) {
        $url .= '?' . http_build_query($params);
    }

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $apiKey,
            'Accept: application/json',
        ],
        CURLOPT_TIMEOUT => 20,
    ]);

    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($body === false || $status >= 400) {
        throw new RuntimeException("API request failed: HTTP {$status}");
    }

    return json_decode($body, true);
}

http_build_query handles URL-encoding of query parameters for you. Every example below reuses tsapi_get().

Fetch Competitions

Find the competition ID you need by searching competitions.

<?php
require 'football_api.php';

$result = tsapi_get('/football/competitions', ['search' => 'Premier League']);

foreach ($result['data'] as $competition) {
    echo $competition['id'] . ' ' . $competition['name'] . ' ' . $competition['country'] . PHP_EOL;
}

Typical output:

comp_3039 Premier League England

Save the competition ID. You will use it in match and season queries.

Get Fixtures for a League

<?php
require 'football_api.php';

$result = tsapi_get('/football/matches', [
    'competition_id' => 'comp_3039',
    'per_page' => 10,
]);

foreach ($result['data'] as $match) {
    printf(
        "%s - %s vs %s (%s)\n",
        $match['utc_date'],
        $match['home_team']['name'],
        $match['away_team']['name'],
        $match['status']
    );
}

Add date_from, date_to, season_id, team_id, and status to narrow the results. See the fixtures API for all parameters.

Handle Pagination

List endpoints return a meta block with total_pages. Loop through every page for backfills.

<?php
require 'football_api.php';

function tsapi_get_all(string $endpoint, array $params = []): array
{
    $page = 1;
    $rows = [];

    do {
        $params['page'] = $page;
        $result = tsapi_get($endpoint, $params);
        $rows = array_merge($rows, $result['data']);

        $totalPages = $result['meta']['total_pages'] ?? 1;
        $page++;
    } while ($page <= $totalPages);

    return $rows;
}

$matches = tsapi_get_all('/football/matches', ['competition_id' => 'comp_3039']);
echo 'Fetched ' . count($matches) . ' matches' . PHP_EOL;

For user-facing apps, run this in a background job and cache the rows in your database.

Get Match Stats

Match stats include shots, possession, corners, and xG where available.

<?php
require 'football_api.php';

$stats = tsapi_get('/football/matches/mt_010249745/stats')['data'];
$overview = $stats['overview'];

$shots = $overview['total_shots']['all'];
$possession = $overview['ball_possession']['all'];
$xg = $overview['expected_goals']['all'];

echo "Shots: {$shots['home']} - {$shots['away']}" . PHP_EOL;
echo "Possession: {$possession['home']} - {$possession['away']}" . PHP_EOL;
echo "xG: {$xg['home']} - {$xg['away']}" . PHP_EOL;

This powers match centres and team form features. See the match stats API and xG API.

Get Player Season Stats

Useful for fantasy apps, player cards, and leaderboards.

<?php
require 'football_api.php';

$stats = tsapi_get('/football/players/pl_61928103/stats', [
    'season_id' => 'sn_6125938',
])['data'];

echo 'Appearances: ' . $stats['appearances'] . PHP_EOL;
echo 'Minutes: ' . $stats['minutes_played'] . PHP_EOL;
echo 'Goals: ' . $stats['scoring']['goals'] . PHP_EOL;
echo 'Assists: ' . $stats['scoring']['assists'] . PHP_EOL;

For match-by-match data, use /football/matches/{match_id}/player-stats instead.

Get Pre-Match Odds

Odds are grouped by bookmaker. See the Football Odds API for markets and bookmakers.

<?php
require 'football_api.php';

$odds = tsapi_get('/football/matches/mt_010249745/odds')['data'];

foreach ($odds['bookmakers'] as $book) {
    if (!isset($book['markets']['match_odds'])) {
        continue;
    }
    echo $book['bookmaker'] . ': ' . json_encode($book['markets']['match_odds']) . PHP_EOL;
}

Use /football/matches/{match_id}/odds/live for in-play odds on supported fixtures.

Use It Inside Laravel

Inside a Laravel controller you can wrap the same call with the HTTP client:

use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'Authorization' => 'Bearer ' . config('services.thestatsapi.key'),
    'Accept' => 'application/json',
])->get('https://api.thestatsapi.com/api/football/matches', [
    'competition_id' => 'comp_3039',
    'per_page' => 10,
]);

$matches = $response->json('data');

Store the key in config/services.php and your .env, never in source control.

Production Tips

  • Keep your API key in environment variables, not in code.
  • Cache responses (file cache, Redis, or your database) to stay within plan limits.
  • Run backfills with pagination in CLI scripts or queued jobs, not web requests.
  • Check availability flags such as xg_available and live_odds_available.
  • Log the endpoint, params, and HTTP status on failed requests.

FAQ

Can I use PHP with TheStatsAPI?

Yes. TheStatsAPI is a REST JSON API, so PHP works with cURL or any HTTP client. The examples above use cURL and json_decode, and there is a Laravel HTTP client example too.

Do I need a PHP SDK?

No. Plain HTTP requests keep your integration simple and portable across frameworks like Laravel, Symfony, and WordPress.

How do I fetch football odds in PHP?

Use /football/matches/{match_id}/odds for pre-match odds and /football/matches/{match_id}/odds/live for live odds where available.

How do I get xG data in PHP?

Use /football/matches/{match_id}/stats and read overview.expected_goals.all for team xG. Player and shot-level xG are available on the player-stats and shotmap endpoints.

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