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.
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_availableandlive_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.
Ready to Power Your Sports App?
Start your 7-day free trial. All endpoints included on every plan.