The PHP client

No dependencies, no Composer, and a one-file version.

An official PHP client is published at github.com/FootballSoccerAPI/footballsoccerapi-php. It needs curl and json, which PHP already has, and nothing else.

There are two versions in it, and the smaller one is the better place to start.

The one-file version

Copy fsapi-simple.php next to your script. Three functions, no classes, nothing to install.

require 'fsapi-simple.php';

$matches = fsapi_get('/v1/matches', [
    'country' => 'England',
    'status'  => 'finished',
    'limit'   => 5,
]);

foreach ($matches as $m) {
    printf("%s %d-%d %s\n",
        $m['home_team_name'], $m['home_goals'],
        $m['away_goals'], $m['away_team_name']);
}

fsapi_get() hands back the data. fsapi_call() hands back the data and the meta. fsapi_walk() pages through a whole set for you. That is all of it.

Your key, and the mistake everyone makes

getenv() takes the name of an environment variable, not the key itself. Passing the key to it looks for a variable with that name, finds nothing, and you get told a key is required while holding one.

// Wrong — looks for a variable called "fsa_live_..."
$api = new Client(getenv('fsa_live_af1f2c1b...'));

// Right — the key itself
$api = new Client('fsa_live_af1f2c1b...');

// Better — the key stays out of the file
$api = new Client(getenv('FSAPI_KEY'));

For the last one, set the variable when you run it:

FSAPI_KEY=fsa_live_... php your-script.php

Worth the extra step. A key written into a file ends up in a repository, a screenshot or a support ticket eventually, and then it has to be rotated.

The full client

Same data, more handled for you: typed exceptions, cursor walking, and batching that chunks a long list rather than refusing it. Clone the repository and require the autoloader — that is the installation. Composer works if you use it, but nothing needs it.

require 'src/autoload.php';

use FootballSoccerApi\Client;

$api = new Client(getenv('FSAPI_KEY'));
$res = $api->matches(['season' => 2024]);

What the exceptions tell you

A refusal names the plan it needs rather than leaving you a bare 403, and a rate limit carries the wait from the response rather than a guessed backoff.

try {
    $api->live();
} catch (PlanRequiredException $e) {
    printf("Needs %s, you have %s\n", $e->needsPlan(), $e->yourPlan());
} catch (RateLimitException $e) {
    sleep($e->retryAfter);
}

A response that is not JSON throws a TransportException saying so. That means something between you and the API answered — a proxy, or a challenge page — and knowing which layer failed saves an hour of debugging the wrong one.

The examples

Four of them, each runnable on a free key. The last works out whether home advantage differs by country in about forty lines, which is a fair test of whether the archive is worth your time.

export FSAPI_KEY=your_key

php examples/simple.php
php examples/quickstart.php
php examples/walk-a-season.php
php examples/home-advantage.php

There is a Python client too, with the same three functions under the same names, so moving between them is not a relearn.

MIT licensed. If something is wrong or missing, an issue on the repository or a ticket both reach us.