WorldCups.ai API

The WorldCups.ai API gives programmatic access to the WorldCups.ai database. You can download tables as CSV files, run SQL queries directly against the database, and ask natural language questions powered by the same AI engine as he WorldCups.ai's AI assistant.
Base URL: https://worldcups.ai/api/v1
API access requires a subscription. Manage your API keys from your account page.

Authentication

All requests must include your API key as a bearer token in the Authorization header.
Authorization: Bearer YOUR_API_KEY
API keys are prefixed with wc_. You can generate and revoke keys from your account page. Keys are shown only once at creation — store them securely.

Rate limits

Each endpoint has a separate monthly request limit. Limits reset on the first day of each month at midnight UTC. Limits are per API key, not per account — if you have multiple keys, each has its own limit. You can have up to 5 API keys at a time.
EndpointMonthly limit
GET /download/:table100 requests
POST /query1,000 requests
POST /ask100 requests
Every response includes the following headers:
HeaderDescription
X-RateLimit-LimitYour monthly limit for this endpoint
X-RateLimit-RemainingRequests remaining this month
X-RateLimit-ResetUnix timestamp when the limit resets
When you exceed a limit, the API returns a 429 response.

Errors

All errors return a JSON object with error and code fields.
{
  "error": "Invalid or revoked API key.",
  "code": "unauthorized"
}
CodeStatusDescription
unauthorized401Missing, invalid, or revoked API key
bad_request400Missing or invalid request parameters
not_found404The requested table does not exist
write_not_allowed400Query contains a non-SELECT statement
query_error400The SQL query failed to execute
generation_failed500The AI failed to generate a response
usage_limit_reached429Monthly request limit reached
rate_limited429Global API rate limit reached

Endpoints

Download a table

Downloads a table from the WorldCups.ai database as a CSV file.
GET /download/:table
Path parameters
ParameterDescription
tableThe name of the table to download (e.g. matches, goals)
Query parameters
ParameterDefaultDescription
versioncuratedcurated includes pre-merged convenience columns; relational contains only the table's own columns
Example
curl -X GET "https://worldcups.ai/api/v1/download/matches?version=curated" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  --output matches.csv
Valid table names
The following tables are available for download. See the database documentation for full details on each table.
Entity tables: tournaments, confederations, teams, matches, players, managers, referees, stadiums, awards
Tournament tables: host_countries, tournament_stages, groups, group_standings, tournament_standings, award_winners
Registration tables: qualified_teams, squads, manager_appointments, referee_appointments
Appearance tables: team_appearances, player_appearances, manager_appearances, referee_appearances
Event tables: goals, bookings, substitutions, penalty_kicks
Response
Returns a CSV file with the content type text/csv. The filename is {table}_{version}.csv.

Query with SQL

Executes a SQL SELECT query against the WorldCups.ai database and returns the results.
POST /query
Request body
FieldTypeRequiredDefaultDescription
sqlstringYesA SELECT or WITH SQL statement
formatstringNojsonResponse format: json or csv
limitintegerNo100Maximum rows to return (max 10,000)
offsetintegerNo0Number of rows to skip
Only SELECT and WITH statements are permitted. All tables are in the worldcupsai schema.
Example
curl -X POST "https://worldcups.ai/api/v1/query" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sql": "SELECT p.family_name, p.given_name, COUNT(*) AS goals FROM worldcupsai.goals g JOIN worldcupsai.players p ON g.player_id = p.player_id WHERE g.own_goal = FALSE GROUP BY p.player_id, p.family_name, p.given_name ORDER BY goals DESC LIMIT 10",
    "format": "json"
  }'
Response (JSON)
{
  "data": [
    { "family_name": "Klose", "given_name": "Miroslav", "goals": 16 }
  ],
  "total_rows": 10,
  "meta": {
    "executed_at": "2024-01-15T12:00:00.000Z"
  }
}
FieldDescription
dataArray of result rows
total_rowsNumber of rows returned
meta.executed_atISO 8601 timestamp of query execution

Ask a question

Asks a natural language question about World Cup history. The API generates a SQL query, executes it, and returns a written answer along with the underlying data.
POST /ask
Request body
FieldTypeRequiredDefaultDescription
questionstringYesA natural language question about World Cup history
categorystringNomenTournament category: men or women
formatstringNojsonResponse format: json or csv
limitintegerNo100Maximum rows to return in data (max 10,000)
Example
curl -X POST "https://worldcups.ai/api/v1/ask" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "Who has scored the most World Cup goals of all time?",
    "category": "men",
    "format": "json"
  }'
Response (JSON)
{
  "answer": "Miroslav Klose holds the record with 16 goals across four tournaments.",
  "sql": "SELECT ...",
  "data": [
    { "family_name": "Klose", "given_name": "Miroslav", "goals": 16 }
  ],
  "total_rows": 1,
  "meta": {
    "executed_at": "2024-01-15T12:00:00.000Z",
    "question": "Who has scored the most World Cup goals of all time?",
    "category": "men",
    "confidence": 0.95
  }
}
FieldDescription
answerA written answer to your question
sqlThe SQL query that was generated and executed
dataArray of result rows supporting the answer
total_rowsTotal number of matching rows in the database
meta.confidenceModel confidence score between 0 and 1. Scores below 0.7 indicate the answer may be less reliable
CSV format
When format is csv, the response contains the raw data rows only — the answer and sql fields are not included. Use JSON format if you need the written answer.

Example: Python

import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://worldcups.ai/api/v1"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

# Ask a question
response = requests.post(
    f"{BASE_URL}/ask",
    headers=headers,
    json={
        "question": "Which countries have won the World Cup and how many times?",
        "category": "men",
    }
)

data = response.json()
print(data["answer"])
for row in data["data"]:
    print(row)

Example: R

library(httr2)

API_KEY <- "YOUR_API_KEY"
BASE_URL <- "https://worldcups.ai/api/v1"

# Run a SQL query and load results into a data frame
response <- request(paste0(BASE_URL, "/query")) |>
  req_headers(
    Authorization = paste("Bearer", API_KEY),
    `Content-Type` = "application/json"
  ) |>
  req_body_json(list(
    sql = "SELECT team_name, COUNT(*) AS matches FROM worldcupsai.team_appearances GROUP BY team_name ORDER BY matches DESC LIMIT 20",
    format = "json",
    limit = 20
  )) |>
  req_perform() |>
  resp_body_json()

df <- do.call(rbind, lapply(response$data, as.data.frame))

Example: Download a table

import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://worldcups.ai/api/v1"

response = requests.get(
    f"{BASE_URL}/download/goals",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"version": "curated"},
)

with open("goals.csv", "wb") as f:
    f.write(response.content)