Competitions API¶
This API endpoint provides access to competitions on OpenTrack. Each record represents a single competition (e.g., a track meet, road race, or cross country event), including its name, dates, venue, type, and metadata.
Specifically, this refers to our SQL Competitions table, which is basically the main calendar entry. There are parallel records in MongoDB, which store a lot of settings for the competition setup; this Mongo record is created when a SQL competition is saved, and they share the same id. You cannot manipulate the latter through this API
Common Tasks with this API
- find upcoming competitions
- embed a calendar in your site for a specific region or club, using OpenTrack as the storage engine
- find a competition containing a specific event
- create a new competition
Endpoint URL: https://{domain}/api/competitions/
For example: https://test-data.opentrack.run/api/competitions/
Federation sites also have access to their own competitions API filtered by their country by default:
https://saaf.opentrack.run/api/competitions/
Saudi Athletics Upcoming Competitions
Quick Start Examples¶
Authentication and Query a Competition by Natural Key¶
Every competition has a natural key URL built from its year, country and slug — far easier to read and remember than a UUID. Get a token first, then use the natural key to fetch the competition and list its events:
Pass the token via the Authorization: Token ... header:
TOKEN=$(curl -s -X POST "https://test-data.opentrack.run/api/get-auth-token/" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'username=api-test@mailinator.com&password=apitest' | python3 -c "import sys,json;print(json.load(sys.stdin)['token'])")
# Fetch a competition by natural key: /api/x/{year}/{country}/{slug}/
curl "https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/" \
-H "Authorization: Token $TOKEN"
# List the events in that competition
curl "https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/event/" \
-H "Authorization: Token $TOKEN"
import requests
# Obtain a token first
resp = requests.post("https://test-data.opentrack.run/api/get-auth-token/",
data={"username": "api-test@mailinator.com",
"password": "apitest"})
token = resp.json()["token"]
headers = {"Authorization": f"Token {token}"}
# Fetch a competition by natural key: /api/x/{year}/{country}/{slug}/
r = requests.get("https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/",
headers=headers)
comp = r.json()
print(f'{comp["date"]} - {comp["full_name"]} ({comp["country"]})')
# List the events in that competition
r = requests.get("https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/event/",
headers=headers)
for ev in r.json()["results"]:
print(f'{ev["event_id"]} - {ev["name"]}')
Example output:
2026-06-19 - Livingston Open Meeting (GBR)
F01 - Long Jump | U16-SEN
F02 - Long Jump | U12
F03 - Long Jump | U14
T01 - 150m | U12
...
API Playground¶
The API uses Django REST Framework's browsable API interface, which provides an interactive playground when accessed via a web browser. The playground allows you to:
- Filter competitions using interactive form controls
- Search across competition names
- Order results by various fields
- Test different pagination limits
- View results in JSON or HTML format
- Try different HTTP methods (GET, POST, etc.)
To access the playground, simply navigate to the API URL while logged in with the appropriate credentials.
HTTP Methods¶
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/competitions/ |
List all competitions (paginated) |
POST |
/api/competitions/ |
Create a new competition |
GET |
/api/competitions/{uuid}/ |
Retrieve a specific competition |
PUT |
/api/competitions/{uuid}/ |
Fully update a specific competition |
PATCH |
/api/competitions/{uuid}/ |
Partially update a specific competition |
DELETE |
/api/competitions/{uuid}/ |
Delete a specific competition |
GET |
/api/x/{year}/{country}/{slug}/ |
Retrieve a competition by natural key |
Natural Key URL Pattern¶
Competitions can be referenced by their UUID, but there is also a much more readable natural key URL pattern based on the competition's year, country and slug:
/api/x/{year}/{country}/{slug}/
For example:
https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/
Example URLs use the test server
The example URLs in this section deliberately point at the test server (test-data.opentrack.run) so you can experiment with write operations (PATCH, PUT, DELETE) without risking live data. Use the live server domain or federation domain when you are ready to make real changes.
The three components are:
| Component | Example | Description |
|---|---|---|
year |
2026 |
The year of the competition (4 digits) |
country |
GBR |
The ISO 3-letter country code |
slug |
lac-open-2 |
The competition's URL slug |
The natural key is unique for every competition, and is also the basis for the events and units API URLs, which are nested under it:
/api/x/{year}/{country}/{slug}/event/
/api/x/{year}/{country}/{slug}/event/{event_id}/
/api/x/{year}/{country}/{slug}/event/{event_id}/rounds/
The natural key is especially useful when you know the competition you want to work with (e.g. you can read it straight from the competition's public URL) and want to avoid looking up its UUID first.
Demo competitions
Competitions set up as demos (the is_demo flag) are excluded from list
endpoints — they do not appear in /api/competitions/ or any filtered list, so
they never clutter browsing or search for real users. They are still retrievable
directly by their exact natural key (/api/x/{year}/{country}/{slug}/), because a
natural-key fetch is an explicit lookup for a known competition, not a discovery
query. So a demo competition's data (and its events/units) is reachable if you know
its URL, but it will not show up in lists.
Response Fields¶
Each competition record in the response contains the following fields:
Basic Information¶
| Field | Type | Description |
|---|---|---|
url |
URL | Link to this specific competition record |
full_name |
String | Full name of the competition |
short_name |
String | Short/abbreviated name |
name_local |
String | Localised name in the native language |
name_local_short |
String | Short localised name |
slug |
String | URL slug identifier |
year |
Integer | Year of the competition |
Dates¶
| Field | Type | Description |
|---|---|---|
date |
Date | Start date of the competition (e.g., "2025-01-17") |
finish_date |
Date | End/finish date of the competition |
created |
Datetime | Timestamp when the competition was created |
Location & Venue¶
| Field | Type | Description |
|---|---|---|
venue |
URL | Link to the venue detail endpoint (nullable) |
address |
String | Street address of the venue |
city |
String | City where the competition is held |
country |
String | ISO country code (e.g., "GBR", "SAU", "USA") |
latitude |
Decimal | Latitude coordinate (nullable) |
longitude |
Decimal | Longitude coordinate (nullable) |
altitude |
Integer | Altitude in metres (nullable) |
Type & Classification¶
| Field | Type | Description |
|---|---|---|
type |
String | Competition type: TRACK, ROAD, CROSSCOUNTRY, INDOOR, WALK, VIRTUAL, or empty |
wa_rankings_category |
URL | Link to the World Athletics rankings category/level (nullable) |
wa_id |
String | World Athletics identifier (nullable) |
Organiser & Contact¶
| Field | Type | Description |
|---|---|---|
organiser |
URL | Link to the organising club/org detail endpoint (nullable) |
contact_name |
String | Name of the contact person |
contact_details |
String | Contact details (email, phone, etc.) |
Description¶
| Field | Type | Description |
|---|---|---|
basic_description |
String | Short description of the competition |
summary_text |
String | HTML summary text with full details |
Statistics (Read-Only)¶
| Field | Type | Description |
|---|---|---|
num_competitors |
Integer | Number of competitors entered (read-only) |
num_results |
Integer | Number of results recorded (read-only) |
Links¶
| Field | Type | Description |
|---|---|---|
home_page_url |
URL | Link to the competition's public home page |
Fetching Competitions¶
List All Competitions¶
GET /api/competitions/
Returns a paginated list of competitions.
Retrieve a Specific Competition¶
By natural key (recommended):
GET /api/x/{year}/{country}/{slug}/
Example: GET /api/x/2026/GBR/lac-open-2/
Returns a single competition record by its natural key (year, country, slug).
By UUID:
GET /api/competitions/{uuid}/
Example: GET /api/competitions/00042340-ea29-41f4-9e26-05732e20b6c9/
Returns a single competition record by its UUID. Both patterns return the same competition record.
Creating Competitions¶
Create a New Competition¶
POST /api/competitions/
Requires authentication. The request body should be a JSON object with the relevant fields.
Permission required
Your account must have explicit permission to create competitions for the competition's country (granted by OpenTrack or your federation), or have federation admin rights. Contact OpenTrack if you are not sure your account has the necessary permissions.
Example:
{
"full_name": "My Track Meet 2026",
"short_name": "MTM 2026",
"date": "2026-06-15",
"finish_date": "2026-06-15",
"type": "TRACK",
"country": "GBR",
"city": "London",
"address": "London Stadium, Queen Elizabeth Olympic Park",
"basic_description": "An open track meet for all ages"
}
Updating Competitions¶
Full Update (PUT)¶
PUT /api/competitions/{uuid}/
Replaces the entire competition record. All required fields must be provided.
Partial Update (PATCH)¶
PATCH /api/competitions/{uuid}/
Only updates the fields provided in the request body.
Example - Update competition name and date:
{
"full_name": "My Track Meet 2026 - Rescheduled",
"date": "2026-07-01",
"finish_date": "2026-07-01"
}
Deleting Competitions¶
Delete a Competition¶
DELETE /api/competitions/{uuid}/
Deletes the competition and all associated data (events, entries, results). This action is irreversible.
Filtering¶
You can filter the competitions list using the following query parameters:
| Parameter | Type | Description | Example |
|---|---|---|---|
country |
String | Filter by ISO country code | ?country=GBR |
type |
String | Filter by competition type | ?type=TRACK |
year |
Integer | Filter by competition year | ?year=2025 |
date |
Date | Filter by exact start date | ?date=2025-01-17 |
when |
String | Filter by timeframe (future, past) |
?when=future |
my_competitions |
Flag | Scope to competitions you administer | ?my_competitions=1 |
Filter Examples¶
Get all competitions in the UK:
/api/competitions/?country=GBR
Get all track competitions in 2025:
/api/competitions/?type=TRACK&year=2025
Get upcoming competitions (future dates):
/api/competitions/?when=future
Get past road races:
/api/competitions/?type=ROAD&when=past
Searching¶
The API supports text search across competition names using the search parameter:
| Parameter | Description | Example |
|---|---|---|
search |
Search in full name, short name, and local name fields | ?search=championships |
Search Example¶
Find all competitions with "marathon" in the name:
/api/competitions/?search=marathon
Ordering¶
You can order the results using the ordering parameter. Prefix with - for descending order.
| Field | Description |
|---|---|
date |
Order by start date |
-date |
Order by start date (descending, most recent first) |
full_name |
Order by full name (A to Z) |
-full_name |
Order by full name (Z to A) |
year |
Order by year |
-year |
Order by year (descending) |
created |
Order by creation date |
-created |
Order by creation date (most recently created first) |
Default ordering: -date (most recent first)
Ordering Examples¶
Order by date (oldest first):
/api/competitions/?ordering=date
Order by date (most recent first):
/api/competitions/?ordering=-date
Order by name:
/api/competitions/?ordering=full_name
Order by most recently created:
/api/competitions/?ordering=-created
Pagination¶
The API uses limit/offset pagination to control the number of results returned.
| Parameter | Type | Description | Default |
|---|---|---|---|
limit |
Integer | Number of records to return | 50 |
offset |
Integer | Starting position in the result set | 0 |
Pagination Examples¶
Get the first 10 competitions:
/api/competitions/?limit=10
Get competitions 21-30 (second page of 10):
/api/competitions/?limit=10&offset=20
Get 100 competitions in the UK:
/api/competitions/?limit=100&country=GBR
Response Structure¶
Paginated responses include:
{
"count": 14677,
"next": "https://test-data.opentrack.run/api/competitions/?limit=50&offset=50",
"previous": null,
"results": [
{
"url": "https://test-data.opentrack.run/api/competitions/00042340-ea29-41f4-9e26-05732e20b6c9/",
"venue": null,
"created": "2021-06-16T18:26:08+01:00",
"full_name": "Jeugdmedaillemeeting - Kan/Ben - AFGELAST !!!",
"short_name": "Jeugdmedaillemeeting - Kan/Ben - AFGELAST !!!",
"name_local": "",
"name_local_short": "",
"slug": "21329",
"address": "Atletiekweg, 9400 Ninove",
"city": "",
"date": "2021-05-24",
"finish_date": "2021-05-24",
"type": "",
"latitude": 50.82768,
"longitude": 4.01302,
"altitude": null,
"wa_id": null,
"year": 2021,
"basic_description": "",
"summary_text": "",
"contact_name": "",
"contact_details": "",
"num_competitors": 0,
"num_results": 0,
"country": "BEL",
"wa_rankings_category": null,
"organiser": null,
"home_page_url": "https://test-data.opentrack.run/en-gb/x/2021/BEL/21329/"
}
]
}
count: Total number of results availablenext: URL for the next page (null if on last page)previous: URL for the previous page (null if on first page)results: Array of competition records for the current page
Combined Query Example¶
Get the first 20 upcoming track competitions in Great Britain:
/api/competitions/?country=GBR&type=TRACK&when=future&limit=20
Get all cross country competitions from 2024 onwards, ordered by date:
/api/competitions/?type=CROSSCOUNTRY&year__gte=2024&ordering=date
Get past road races in the USA with athlete results:
/api/competitions/?country=USA&type=ROAD&when=past&num_results__gt=0
Permissions¶
All API endpoints require authentication — there are no public endpoints. Log in with a valid API token or session cookie to access them.
| Access Level | Permission |
|---|---|
| Authenticated user | Read access — list all competitions and view any competition's details |
| Competition Director/Admin | Full CRUD access to competitions they manage, but write operations (POST/PUT/PATCH/DELETE) are only permitted until 7 days after the competition finishes |
| Federation Admin | Access to all competitions within their federation |
Permissions by Method¶
| Method | Permission Required |
|---|---|
GET (list) |
Any authenticated user |
GET (detail) |
Any authenticated user |
POST |
Director/Admin of the competition (or federation admin for their federation), within 7 days after the competition finishes |
PUT / PATCH |
Director/Admin of the competition (or federation admin for their federation), within 7 days after the competition finishes |
DELETE |
Director/Admin of the competition (or federation admin for their federation), within 7 days after the competition finishes |
Notes¶
- Competitions are identified by UUID (e.g.,
00042340-ea29-41f4-9e26-05732e20b6c9/) in the standard API, or by their natural key (/api/x/{year}/{country}/{slug}/), which is more readable and is recommended when you know the competition you want - The
typefield uses OpenTrack's internal competition type constants (TRACK,ROAD,CROSSCOUNTRY,INDOOR,WALK,VIRTUAL) - Federation-specific API URLs (e.g.,
https://saaf.opentrack.run/api/competitions/) will automatically filter results to competitions within that federation's country - The playground interface is only available when accessing via a web browser with proper authentication