This guide provides the full documentation of the football-data API. If you just want to get started and get a taste of the API, I recommend to have a look at the Quickstart-Information on the main page that shows all resources with a sample-request and response plus the filters they accept. If you want to understand the API in depth then this guide is for you, as I also try to point out design decisions and explain why the API ticks like it does.

Changelog

  • I decided to change wording from Soccerseason to Competition as the API now also offers tournaments, which differ in quite some way from seasonal competitions. However, as I made this decision rather late, technical support will last (→ the endpoints are still available and won’t be shut down in v1 at all).

  • The 'X-Response-Control' request-header gives you control over the represenation of resources.

  • The API returns more meta information via response headers concerning authentication and throttling.

  • You can search for teams.

  • The leagueTable resource offers more data and is able to deal with tournaments.

  • Introduction of the Event-API.

Vocabulary

Technical wording

Basically I use the terms Main Resource, Subresource and Filter to describe the API design. They are abstract "things" that can be combined in various combinations and forms to retrieve the data you need.

Main Resources are main building blocks of the API and most likely also appear as entities in clients' applications. Subresources on the other hand generally don’t make sense without the Main Resource they are based on. You can also think of that a Main Resource actually is composed of Subresources. However often there are good arguments to justify one or the other design to be right. Trying to offer a flexible API you will see some "things" appear as both. Last but not least there are Filters to narrow down result sets. A Filter always describes an attribute and it’s value must be passed in an adequate format, which is declared by a Data Type. I usually describe these Data types using a loose regex-dialect.

Domain wording

A Competition represents either a particular season of a football league (e.g. Premiere League) or a tournament (e.g. FA-Cup). A Competition belongs to a specific League, which is defined by a two or three-letter-code and consists of Matchdays, that hold a number of scheduled games named Fixtures. A certain number of Teams participate in a Competition.

I omitted to implement Matchday as a hierarchical element by purpose. It’s just an attribute of Fixture because I think this is more intuitive and separation can be achieved by using a Filter. In tournaments like the Champions League a matchday represents the round of the last 16 the semi-final as well, so be sure to adapt your frontend accordingly ;)

Resource design

URI’s, resources and subresources are all written lower case. Filters on the other hand use camelCase instead. All resources are only accessible using their plural, thus a resource by default responds with the list representation. Adding an id to the endpoint gives access to one particular resource.

Resources are represented as JSON-objects. All objects are preceded by a '_links'-node that holds linked resources, that you can use to easily traverse the API in the browser. You can omit that header by using the X-Response-Control header setting. In list representations you typically find a node 'count' that shows the number of results.

Requesting a Resource

For a first glimpse you can use your webbrowser to browse the API. To make the responses human-readable, install a browser-plugin (mentioned on the the landing page) that beautifies JSON output, or better yet use Postman. You can also use wget, curl or Powershell to easily fetch resources, depending on your platform.

To implement the API there are lots of libraries and plugins that ease implementing RESTful APIs. I personally can recommend HTTP Requests Library by Bud Bird for Groovy/Java and Guzzle for PHP. But most probably you already got your favorite REST library at hand.

Also have a look at the open-sourced football-data.org API-libraries, which offer high level functions, that directly map to API resources. These are available in PHP, Ruby, Python, Golang and Perl6.

The API follows the Query-string composition standard. So if you want to use Filters read more about query definition on wikipedia.

Please implement smart requests and always try to think about a good tradeoff between payload and the number of requests. Please don’t write loops to crawl resources from id 0 to id 1000. Don’t pull (thus: poll) resources too often, they usually do not change within a second.

Request Headers

Header-Name Possible values Description

X-Response-Control

full (default)|minified|compressed

Control the appearance of the response. 'minified' will lack some (meta) information and thus be much smaller. However, 'compressed' is currently only supported by the fixture resource.

X-Auth-Token

[a-z1-9]+

Your authentication token

Response Headers

Examine the underneath HTTP response headers to debug responses that do not look like you expected.

Header-Name Example value Description

X-API-Version

v1

indicates the version you are using

X-Response-Control

minified

Shows the representation returned.

X-Authenticated-Client

Jimbo Jones

Shows the detected API-client or 'anonymous'

X-RequestCounter-Reset

23

Defines the seconds left to reset your request counter.

X-RequestsAvailable

50

Shows the remaining requests before being blocked.

Resources

Competition

The list representation of this resource is the de-facto entry point to the API and by default returns all available competitions for the current season.

Competition.json
{
    "_links": {
        "self": {
            "href": "http://api.football-data.org/v1/competitions/424"
        }
        "teams": {
            "href": "http://api.football-data.org/v1/competitions/424/teams"
        }
        "fixtures": {
            "href": "http://api.football-data.org/v1/competitions/424/fixtures"
        }
        "leagueTable": {
            "href": "http://api.football-data.org/v1/competitions/424/leagueTable"
        }
    }
    "id": 424
    "caption": "European Championships France 2016"
    "league": "EC"
    "year": "2016"
    "currentMatchday": 3
    "numberOfMatchdays": 7
    "numberOfTeams": 24
    "numberOfGames": 38
    "lastUpdated": "2016-06-22T04:34:39Z"
}

Available filters:

  • season.

There is no way of pulling all available competitions with one call.

Fixture

The Fixture resource reflects a scheduled football game. A fixture typically belongs to a competition and is played on a certain matchday. Fixture appears as Main Resource and as Subresource of a Competition.

Fixture.json
----
{
    "fixture": {
        "_links": {
            "self": {
                "href": "http://api.football-data.org/v1/fixtures/149430"
            }
            "competition": {
                "href": "http://api.football-data.org/v1/competitions/405"
            }
            "homeTeam": {
                "href": "http://api.football-data.org/v1/teams/86"
            }
            "awayTeam": {
                "href": "http://api.football-data.org/v1/teams/78"
            }
        }
        "date": "2016-05-28T18:45:00Z"
        "status": "FINISHED"
        "matchday": 10
        "homeTeamName": "Real Madrid CF"
        "awayTeamName": "Club Atlético de Madrid"
        "result": {
            "goalsHomeTeam": 1
            "goalsAwayTeam": 1
            "halfTime": {
                "goalsHomeTeam": 1
                "goalsAwayTeam": 0
            }
            "extraTime": {
                "goalsHomeTeam": 1
                "goalsAwayTeam": 1
            }
            "penaltyShootout": {
                "goalsHomeTeam": 5
                "goalsAwayTeam": 3
            }
        }
    }
    "head2head": {
        "count": 10
        "timeFrameStart": "2013-09-28"
        "timeFrameEnd": "2016-05-28"
        "homeTeamWins": 1
        "awayTeamWins": 4
        "draws": 5
        "lastHomeWinHomeTeam": {  }
        "lastWinHomeTeam": {  }
        "lastAwayWinAwayTeam": {  }
        "lastWinAwayTeam": { }
        "fixtures": [   ]
    }
}

As you can see besides the HAL-header and the basic data, this response holds a head2head node (omitted in list representation). The empty (curly) brackets contain a fixture or a list of fixtures respectively. You can control the number of compared games for the head2head aggregation by setting the head2head Filter. However, notice that only the last 10 games are printed in detail, no matter how many games go in the aggregated data above. Results of games with no result data yet, contain null as value for the goal fields. The fields extraTime and penaltyShootout are omitted if empty.

Available filters:

  • timeFrame

  • timeFrameStart + timeFrameEnd

  • head2head

  • league (only at endpoin /fixtures)

If filtered, You can verify the date range applied by the given keys 'timeFrameStart' and 'timeFrameEnd' in the response.

Last but not least see the underneath state diagram for possible values of the STATUS field.

State-Diagram
Figure 1. Possible values of the STATUS field.

Team

Team.json
{
    "_links": {
        "self": {
            "href": "http://api.football-data.org/v1/teams/66"
        }
        "fixtures": {
            "href": "http://api.football-data.org/v1/teams/66/fixtures"
        }
        "players": {
            "href": "http://api.football-data.org/v1/teams/66/players"
        }
    }
    "name": "Manchester United FC"
    "code": "MUFC"
    "shortName": "ManU"
    "squadMarketValue": "394,550"
    "crestUrl": "http://upload.wikimedia.org/wikipedia/de/d/da/Manchester_United_FC.svg"
}

Available filters:

  • name

Set a (part of a) name to list (search) teams with the given part as substring in their name.

Player

Player.json
{
    "name": "David Silva",
    "position": "Attacking Midfield",
    "jerseyNumber": 21,
    "dateOfBirth": "1986-01-08",
    "nationality": "Spain",
    "contractUntil": "2019-06-30",
    "marketValue": "38,000,000 €"
}

Available filters: -

LeagueTable

LeagueTable.json
{
    "leagueCaption": "Premier League 2015/16",
    "matchday": 10,
    "standing":
    [
        {
            "rank": 1,
            "team": "ManCity",
            "teamId": 65,
            "playedGames": 10,
            "crestURI": "http://upload.wikimedia.org/wikipedia/de/f/fd/ManCity.svg",
            "points": 22,
            "goals": 24,
            "goalsAgainst": 8,
            "goalDifference": 16
        },
	{ ... },
        { ... }
    ]
}

Available filters:

  • matchday (defaults to the current matchday)

Filters

Filter Possible value(s) Description

id

Integer /[0-9]+/

The (unique) id of a resource.

matchday

Integer /[1-4]*[0-9]*/

For the leageTable subresource, the matchday defaults to the current matchday. For former seasons the last matchday is taken. For the fixture resource, it’s unset.

season

String /\d\d\d\d/

Defaults to the current year, given as 4 digit like '2016'

head2head

Integer /[0-9]+/

Define the the number of former games to be analyzed in the head2head node. Defaults to 10.

venue

home|away

Define the venue of the fixtures to be returned.

league

(comma separated) String /[\w\d]{2,4}(,[\w\d]{2,4})*/

A (list of, comma separated) league-code(s). Default is unset and means all available. See the soccerseason list resource for currently available leagues or the appendix of the full documentation for a table of all league codes

timeFrame

p|n[1-9]{1,2}

The value of the timeFrame argument must start with either p(ast) or n(ext), representing a timeframe either in the past or future. It is followed by a number in the range 1..99. It defaults to n7 in the fixture resource and is unset for fixture as a subresource. For instance: p6 would return all fixtures in the last 6 days, whereas n23 would result in returning all fixtures in the next 23 days.

timeFrameStart

\d\d\d\d-\d\d\-\d\d

The start date of the resources to be returned, e.g. 2016-08-01

timeFrameEnd

\d\d\d\d-\d\d\-\d\d

The end date of the resources to be returned, e.g. 2016-08-08

API behaviour

Request-Throttling

To protect the API from unnecessary load it is throttled. Non-authenticated clients are allowed for 100 requests per 24 hours, which is enough to see if it’s worth registering. Registered clients are allowed for 50 requests per minute by default. However, only rarely there is need for such high rates, so if one of my guarding-algorithms detects abnormal or foolish requests, I will first try to contact you via mail to try to find out the reasons for your load. Mostly some sort of caching resolves the issue, sometimes I loosen rate limits. However, depending on the load and your response time I may suspend your account and/or ban your IP.

Default values

The API in general always defaults to current dates, which is the current season and matchday. Season is usually switched somewhen in June. The current matchday is defined by the following algorithm: from now (as of the time it is run every 5 minutes) take the last and the next match of the season. If their matchday is equal set the matchday to that matchday. If the gap between now and the next match is less that 36 hours or the gap between the last game and now is more than 60 hours, set the matchday to the matchday of the next game.

CORS handling

CORS (Cross-Origin-Resource-Sharing) describes a security mechanism of browsers to prevent malicious code from different servers than the original page was served from to execute. There is an excellent article on SpringSource explaining CORS,^ so there’s no need to describe that further at this point. However, if you implement requests directly from Javascript, you need to add your X-Auth-Token correctly so the API gives you permission to do that. The basic workflow is like so:

Before your implemented Ajax-Request takes place your browser will automatically fire somethink like that:

OPTIONS http://api.football-data.org/v1/competitions/355/leagueTable

So that is your intentionally implemented request but not fired with GET but with the OPTIONS method. The API will respond with

204 No Content

response indicating there is no message body but also return the headers that are allowed. It reads as follows:

Access-Control-Allow-Methods "GET";
Access-Control-Allow-Origin "*";
Access-Control-Allow-Headers "x-auth-token, x-response-control";
Content-Length 0;
Content-Type text/plain;

Your browser now interprets this as I am allowed to make that intended request and fires the same request again with the GET method and you will receive your desired response.

Event-API

documentation will follow as soon as it’s getting way more stable.

Verifying your host system

Setting up a listener

Event format

Errors

If something goes wrong you will likely face one of the following HTTP error codes. If the error is caused by the client the API will try to give you a hint with a small JSON encoded error message that could look like this:

{
  "error": "Parameter 'id' is expected to be an integer in a specific range."
}

HTTP error codes returned

400 Bad Request

Your request was malformed most likely the value of a Filter was not set according to the Data Type that is expected.

403 Restricted Resource

You tried to access a resource that exists, but is not available for you. This can be out of the following reasons:

  • the resource is only available to authenticated clients.

  • the resource is only available to donating clients.

  • the resource is not available in the API version you are using.

404 Not Found

You tried to access a resource that doesn’t exist.

429 Too Many Requests

You exceeded your allowed requests per minute/day depending on API version and your user status. Look at Request-Throttling for more information.

Appendix

Table of League-Codes

Table 1. League-Codes used in the Competition resource

League-Code

Country

League

BL1

Germany

1. Bundesliga

BL2

Germany

2. Bundesliga

BL3

Germany

3. Bundesliga

DFB

Germany

Dfb-Cup

PL

England

Premiere League

EL1

England

League One

ELC

England

Championship

FAC

England

FA-Cup

SA

Italy

Serie A

SB

Italy

Serie B

PD

Spain

Primera Division

SD

Spain

Segunda Division

CDR

Spain

Copa del Rey

FL1

France

Ligue 1

FL2

France

Ligue 2

DED

Netherlands

Eredivisie

PPL

Portugal

Primeira Liga

GSL

Greece

Super League

CL

Europe

Champions-League

EL

Europe

UEFA-Cup

EC

Europe

European-Cup of Nations

WC

World

World-Cup