World Athletics APIWorldAthletics.org ↗
Search athletes and retrieve competition results, personal bests, career history, and championship honours from World Athletics via a clean JSON API.
What is the World Athletics API?
The World Athletics API gives developers access to 4 endpoints covering athlete search, annual competition results, career championship history, and full profile data including personal bests and honours. Use search_athletes to find any athlete by name with optional filters for gender, country, and discipline, then pull detailed race-by-race results or major championship records for any athlete in the database.
curl -X GET 'https://api.parse.bot/scraper/c818b331-d34b-4d51-b08b-f72111010743/search_athletes?query=Bolt' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace worldathletics-org-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
World Athletics API Client
This module provides a Python client for interacting with the World Athletics API
through Parse. Search for athletes, retrieve their competition results, and access
their career history from major championships.
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Optional, Dict, Any
class ParseClient:
"""Client for interacting with World Athletics API through Parse."""
def __init__(self, api_key: Optional[str] = None):
"""Initialize the Parse client with API credentials."""
self.base_url = "https://api.parse.bot"
self.scraper_id = "c818b331-d34b-4d51-b08b-f72111010743"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError("API key must be provided or set in PARSE_API_KEY environment variable")
def _call(self, endpoint: str, method: str = "POST", **params) -> Dict[str, Any]:
"""Make an API call to the Parse endpoint."""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
if method == "GET":
response = requests.get(url, headers=headers, params=params)
elif method == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
def search_athletes(
self,
query: str,
gender: Optional[str] = None,
discipline_code: Optional[str] = None,
country_code: Optional[str] = None
) -> Dict[str, Any]:
"""
Search for athletes by name.
Args:
query: Athlete name or partial name to search for (e.g. 'Bolt', 'Hassan')
gender: Optional filter by gender
discipline_code: Optional filter by discipline code
country_code: Optional filter by 3-letter country code (e.g. 'JAM', 'USA')
Returns:
Dictionary containing athletes list and total count
"""
params = {"query": query}
if gender:
params["gender"] = gender
if discipline_code:
params["discipline_code"] = discipline_code
if country_code:
params["country_code"] = country_code
return self._call("search_athletes", method="GET", **params)
def get_athlete_results(
self,
athlete_id: str,
year: Optional[int] = None
) -> Dict[str, Any]:
"""
Get competition results for an athlete in a specific year.
Args:
athlete_id: Numeric athlete ID from search results
year: Optional year to retrieve results for (defaults to most recent)
Returns:
Dictionary containing active years and results by event
"""
params = {"athlete_id": athlete_id}
if year:
params["year"] = year
return self._call("get_athlete_results", method="GET", **params)
def get_athlete_career(
self,
athlete_id: str,
url_slug: str
) -> Dict[str, Any]:
"""
Get major championship results (career history) for an athlete.
Args:
athlete_id: Numeric athlete ID from search results
url_slug: Athlete URL slug from search results
Returns:
Dictionary containing career results organized by competition category
"""
return self._call(
"get_athlete_career",
method="GET",
athlete_id=athlete_id,
url_slug=url_slug
)
def get_athlete_profile(
self,
athlete_id: str,
url_slug: str
) -> Dict[str, Any]:
"""
Get an athlete's full profile including biographical data, personal bests, and achievements.
Args:
athlete_id: Numeric athlete ID from search results
url_slug: Athlete URL slug from search results
Returns:
Dictionary containing complete athlete profile with honours and world rankings
"""
return self._call(
"get_athlete_profile",
method="GET",
athlete_id=athlete_id,
url_slug=url_slug
)
if __name__ == "__main__":
# Initialize the client
client = ParseClient()
print("=" * 70)
print("World Athletics API - Practical Usage Example")
print("=" * 70)
# Step 1: Search for distance runners
print("\n📍 Step 1: Searching for elite marathon runners...")
search_results = client.search_athletes("Kipchoge")
athletes = search_results.get("athletes", [])
total = search_results.get("total", 0)
print(f" Found {total} total results (displaying {len(athletes)} results)")
if not athletes:
print(" No athletes found with that search. Trying alternative search...")
search_results = client.search_athletes("Hassan", country_code="ETH")
athletes = search_results.get("athletes", [])
# Step 2: Analyze each athlete found
for athlete_idx, athlete in enumerate(athletes[:2], 1):
athlete_id = athlete["athlete_id"]
url_slug = athlete["url_slug"]
given_name = athlete["given_name"]
family_name = athlete["family_name"]
country = athlete["country"]
disciplines = athlete["disciplines"]
birth_date = athlete["birth_date"]
print(f"\n{'=' * 70}")
print(f"Athlete {athlete_idx}: {given_name} {family_name}")
print(f"{'=' * 70}")
print(f" Country: {country}")
print(f" Birth Date: {birth_date}")
print(f" Disciplines: {disciplines}")
print(f" ID: {athlete_id}")
# Step 3: Get recent competition results (2023)
print(f"\n 📊 Fetching 2023 competition results...")
try:
results_data = client.get_athlete_results(athlete_id, year=2023)
active_years = results_data.get("active_years", [])
year_displayed = results_data.get("year")
results_by_event = results_data.get("results_by_event", [])
if active_years:
print(f" Active years: {', '.join(active_years[:8])}")
if results_by_event:
print(f" Results in {year_displayed or 'most recent year'} ({len(results_by_event)} disciplines):")
for event in results_by_event[:3]:
discipline = event.get("discipline", "Unknown")
results = event.get("results", [])
if results:
print(f"\n 🏃 {discipline}:")
for result in results[:2]:
mark = result.get("mark", "N/A")
place = result.get("place", "N/A")
venue = result.get("venue", "Unknown")
date = result.get("date", "N/A")
competition = result.get("competition", "Unknown")
print(f" • {mark} ({place}) at {competition}")
print(f" Venue: {venue} | Date: {date}")
if len(results) > 2:
print(f" ... and {len(results) - 2} more races")
else:
print(f" No results found for {year_displayed or 'the selected year'}")
except Exception as e:
print(f" ⚠️ Could not fetch recent results: {e}")
# Step 4: Get career achievements
print(f"\n 🏆 Fetching career achievements...")
try:
career_data = client.get_athlete_career(athlete_id, url_slug)
career_results = career_data.get("career_results", [])
for category in career_results:
category_name = category.get("category", "Unknown")
results = category.get("results", [])
if results:
print(f"\n {category_name} ({len(results)} results):")
for result in results[:2]:
discipline = result.get("discipline", "Unknown")
competition = result.get("competition", "Unknown")
place = result.get("place", "N/A")
result_mark = result.get("result", "N/A")
date = result.get("date", "N/A")
venue = result.get("venue", "Unknown")
print(f" • {discipline}: {result_mark}")
print(f" {competition} ({place})")
print(f" {venue} | {date}")
if len(results) > 2:
print(f" ... and {len(results) - 2} more achievements")
except Exception as e:
print(f" ⚠️ Could not fetch career data: {e}")
# Step 5: Get full athlete profile
print(f"\n 👤 Fetching complete athlete profile...")
try:
profile_data = client.get_athlete_profile(athlete_id, url_slug).get("data", {})
country_name = profile_data.get("country_name", "Unknown")
iaaf_id = profile_data.get("iaaf_id")
biography = profile_data.get("biography")
print(f" Country: {country_name}")
if iaaf_id:
print(f" IAAF ID: {iaaf_id}")
# Display personal bests
personal_bests = profile_data.get("personal_bests", [])
if personal_bests:
print(f"\n Personal Bests ({len(personal_bests)} disciplines):")
for pb in personal_bests[:3]:
discipline = pb.get("discipline", "Unknown")
mark = pb.get("mark", "N/A")
venue = pb.get("venue", "Unknown")
date = pb.get("date", "N/A")
print(f" • {discipline}: {mark}")
print(f" {venue} ({date})")
if len(personal_bests) > 3:
print(f" ... and {len(personal_bests) - 3} more personal bests")
# Display world rankings
world_rankings = profile_data.get("world_rankings", {})
current_rankings = world_rankings.get("current", [])
if current_rankings:
print(f"\n Current World Rankings:")
for ranking in current_rankings[:3]:
event_group = ranking.get("event_group", "Unknown")
place = ranking.get("place", "N/A")
print(f" • {event_group}: #{place}")
except Exception as e:
print(f" ⚠️ Could not fetch profile: {e}")
print(f"\n{'=' * 70}")
print("✅ Example completed successfully!")
print("=" * 70)Search for athletes by name. Returns matching athletes with basic profile information including ID, name, disciplines, country, and URL slug. Results include fuzzy matches.
| Param | Type | Description |
|---|---|---|
| queryrequired | string | Athlete name or partial name to search for (e.g. 'Bolt', 'Hassan'). |
| gender | string | Filter by gender. The GraphQL API accepts GenderType enum values. |
| country_code | string | Filter by 3-letter country code (e.g. 'JAM', 'USA', 'GBR'). |
| discipline_code | string | Filter by discipline code. |
{
"type": "object",
"fields": {
"total": "integer",
"athletes": "array of athlete objects with athlete_id, family_name, given_name, birth_date, disciplines, gender, country, url_slug"
},
"sample": {
"total": 30,
"athletes": [
{
"gender": "Men",
"country": "JAM",
"url_slug": "jamaica/usain-bolt-14201847",
"athlete_id": "14201847",
"birth_date": "21 AUG 1986",
"given_name": "Usain",
"disciplines": "100 Metres, 200 Metres, 400 Metres",
"family_name": "BOLT"
}
]
}
}About the World Athletics API
What the API Covers
The API exposes athlete data from World Athletics across four endpoints. search_athletes accepts a name or partial name and returns matching athletes with their athlete_id, url_slug, disciplines, country, gender, and birth date. Optional country_code (3-letter ISO), gender, and discipline_code parameters narrow results. The athlete_id and url_slug returned here are the keys you pass into every other endpoint.
Annual Results and Career History
get_athlete_results accepts an athlete_id and an optional year parameter. When year is omitted it defaults to the athlete's most recent active season. The response includes results_by_event — an array of event objects each containing a discipline name and a results array with marks, places, venues, and scores — plus active_years, which lists every season the athlete has recorded results. get_athlete_career takes both athlete_id and url_slug and returns career_results grouped by category (Olympic Games, World Championships, Other competitions), giving a full picture of major championship appearances across an athlete's entire career.
Full Profile Data
get_athlete_profile returns the most complete record: biographical fields (birth_date, country_code, biography), personal bests across all disciplines, an honours array organized by category with per-row fields for discipline, competition, venue, place, mark, and date, current and best world rankings, and the athlete's iaaf_id. Both athlete_id and url_slug are required inputs. Honours categories include Olympic Games, World Championships, Diamond League, and Major Marathons where applicable.
Source Coverage Notes
World Athletics does not publish a public REST developer API. The data reflects the official World Athletics database, which is the authoritative global source for track and field, road running, race walking, and cross country results at international and major national levels.
The World Athletics API is a managed, monitored endpoint for WorldAthletics.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when WorldAthletics.org changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official WorldAthletics.org API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a career timeline for an athlete using
get_athlete_careerchampionship results grouped by Olympic Games and World Championships - Power an athlete comparison tool by pulling personal bests and world rankings from
get_athlete_profilefor multiple competitors - Display a season-by-season results table using
get_athlete_resultswith theactive_yearsfield to populate a year selector - Create a country roster page by filtering
search_athleteswith acountry_codeparameter - Track Diamond League and Major Marathon honours using the
honoursarray inget_athlete_profile - Build an athlete search autocomplete using partial name queries against
search_athleteswith fuzzy match support - Aggregate discipline-specific result sets across years by iterating
get_athlete_resultsover each entry inactive_years
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does World Athletics have an official public developer API?+
What does `get_athlete_results` return and how do I get results for a specific year?+
results_by_event, an array of discipline objects each containing a results array with marks, places, venues, and scores. Pass the year integer parameter to target a specific season. If you omit year, the endpoint defaults to the athlete's most recent active year. The active_years field in the response lists every season available for that athlete.Does the profile endpoint return world ranking history over time?+
get_athlete_profile endpoint returns current and best world rankings but does not expose a full year-by-year ranking history. It covers personal bests, honours, and biographical fields. You can fork this API on Parse and revise it to add a ranking history endpoint if that data is required.Are indoor and outdoor results separated in `get_athlete_results`?+
results_by_event. Whether a result was set indoors or outdoors depends on how World Athletics records the event; there is no explicit indoor/outdoor filter parameter on the endpoint. You can fork this API on Parse and revise it to add indoor-specific filtering if your use case requires it.Is there a known limitation with athlete IDs from `search_athletes`?+
athlete_id returned by search_athletes is a numeric string (e.g. '14208194') that must be passed as-is to get_athlete_results, get_athlete_career, and get_athlete_profile. Some endpoints also require the url_slug. Using an ID from an external source that does not match the World Athletics format will return no results.