Skip to content
Developer docsREST · JSON and PNG · /v1

Code examples

Football API code examples for server-side integrations

Every example reads the key from FOOTBALLAPI_KEY on your server. Feed IDs shown here are illustrative; confirm the real IDs in /api/football/catalogue. Sample IDs: league 1204, team 9260, player 194646.

List feeds (public, no key)

curl --fail-with-body "https://footballapi.net/api/football/catalogue"

League table

curl --fail-with-body "https://footballapi.net/api/v1/football/standings?leagueId=1204" \
  -H "X-API-Key: $FOOTBALLAPI_KEY"

Season fixtures

curl --fail-with-body "https://footballapi.net/api/v1/football/fixtures?leagueId=1204" \
  -H "X-API-Key: $FOOTBALLAPI_KEY"

Team profile

curl --fail-with-body "https://footballapi.net/api/v1/football/team?teamId=9260" \
  -H "X-API-Key: $FOOTBALLAPI_KEY"

Player profile

curl --fail-with-body "https://footballapi.net/api/v1/football/player?playerId=194646" \
  -H "X-API-Key: $FOOTBALLAPI_KEY"

Download a crest

Media routes return image bytes. Venue images take the team ID. League logos are not offered.

curl --fail "https://footballapi.net/api/football/media/teams/9260" --output crest.png

Errors and retries

At most three attempts with a 15-second timeout. Retries 429 and transient upstream errors, and stops rather than waiting more than 30 seconds.

const key = process.env.FOOTBALLAPI_KEY;
if (!key) throw new Error("Set FOOTBALLAPI_KEY on your server");
const base = process.env.API_BASE_URL || "https://footballapi.net";
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function footballGet(path, params = {}) {
  const url = new URL(path, base);
  for (const [name, value] of Object.entries(params)) {
    url.searchParams.set(name, String(value));
  }
  for (let attempt = 0; attempt < 3; attempt++) {
    const res = await fetch(url, {
      headers: { "X-API-Key": key },
      signal: AbortSignal.timeout(15000),
    });
    const body = await res.json(); // JSON endpoints only; not media images
    if (res.ok) return body;

    const retryAfter = Number(res.headers.get("Retry-After") || 0);
    const transientSource = res.status === 503 &&
      ["provider_unavailable", "image_source_unavailable"].includes(body.code);
    const retryable = res.status === 429 || transientSource;
    const delay = Math.max(
      Number.isFinite(retryAfter) ? retryAfter * 1000 : 0,
      1000 * (2 ** attempt),
    );
    if (!retryable || attempt === 2 || delay > 30000) {
      throw Object.assign(new Error(body.error || `HTTP ${res.status}`), {
        status: res.status, code: body.code,
        requestId: body.requestId, retryAfter,
      });
    }
    await sleep(delay + Math.random() * 200);
  }
}

const { meta, data } = await footballGet("/api/v1/football/standings", { leagueId: "1204" });
console.log(meta, data);