Events API (EventSpec)¶
This API endpoint provides access to event specifications (EventSpec) within competitions on OpenTrack. Each record represents a single event (e.g., "100m Men", "Long Jump Women") within a competition, including its configuration, rounds, timings, and status.
Endpoint URL: https://{domain}/api/events/
For example: https://test-data.opentrack.run/api/events/
Quick Start Examples¶
# Obtain a token and list all events in a competition via its natural key URL
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'])")
curl "https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/event/" \
-H "Authorization: Token $TOKEN"
import requests
# Obtain a token
resp = requests.post("https://test-data.opentrack.run/api/get-auth-token/",
data={"username": "api-test@mailinator.com",
"password": "apitest"})
token = resp.json()["token"]
# List all events in a competition via its natural key URL
headers = {"Authorization": f"Token {token}"}
r = requests.get("https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/event/",
headers=headers)
data = r.json()
for event in data["results"]:
print(f'{event["event_id"]}: {event["name"]} ({event["genders"]}) - {event["category"]}')
Example output:
T01: 150m (M) - U12
T02: 200m (M)
T03: 600m (M) - U12
T04: 800m (M)
F01: Long Jump (F) - U16-SEN
...
Filtering across all competitions
The natural key URL above queries the events of one specific competition. If you want to search across competitions (for example, every 100m event on the whole site), use the standard list endpoint with the competition UUID and filter parameters instead:
/api/events/?competition={competition_uuid}&event_code=100&ordering=name&limit=5
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:
- View and filter event specifications
- Create new events using interactive forms
- Update and delete individual events
- Test different pagination limits
- View results in JSON or HTML format
- Try different HTTP methods (GET, POST, PUT, PATCH, DELETE)
To access the playground, simply navigate to the API URL while logged in with the appropriate credentials.
HTTP Methods¶
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/events/ |
List all event specs (paginated) |
POST |
/api/events/ |
Create a new event spec |
GET |
/api/events/{id}/ |
Retrieve a specific event spec |
PUT |
/api/events/{id}/ |
Fully update a specific event spec |
PATCH |
/api/events/{id}/ |
Partially update a specific event spec |
DELETE |
/api/events/{id}/ |
Delete a specific event spec |
GET |
/api/x/{year}/{country}/{slug}/event/ |
List all events for a competition (natural key) |
GET |
/api/x/{year}/{country}/{slug}/event/{event_id}/ |
Retrieve an event by natural key |
PATCH |
/api/x/{year}/{country}/{slug}/event/{event_id}/ |
Partially update an event by natural key |
PUT |
/api/x/{year}/{country}/{slug}/event/{event_id}/ |
Fully update an event by natural key |
DELETE |
/api/x/{year}/{country}/{slug}/event/{event_id}/ |
Delete an event by natural key |
Natural Key URL Pattern¶
As with competitions, events can be addressed using the natural key URL pattern instead of the numeric event spec id. Events are nested under their competition's natural key:
/api/x/{year}/{country}/{slug}/event/
/api/x/{year}/{country}/{slug}/event/{event_id}/
The {event_id} is the competition-specific event identifier string (e.g. T01, F1), not the database primary key. For example:
https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/event/
https://test-data.opentrack.run/api/x/2026/GBR/lac-open-2/event/T01/
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.
This pattern supports the full range of operations on a single event: GET, PATCH, PUT and DELETE — so once you know the competition (year/country/slug) and the event identifier, you do not need to look up any database IDs.
Response Fields¶
Each event spec record in the response contains the following fields:
Basic Information¶
| Field | Type | Description |
|---|---|---|
url |
URL | Link to this specific event spec record |
competition |
UUID | UUID of the competition this event belongs to |
event_id |
String | competition-specific event identifier (e.g., "F1", "T01") |
event_code |
String | Standard athletics event code (e.g., "100", "HJ", "LJ", "SP", "DT") |
name |
String | Display name of the event (e.g., "100 metres MEN") |
name_local |
String | Localised name of the event (nullable) |
age_groups |
String | Comma-separated age groups (e.g., "SEN,U13,U15,U17,U20", "ALL") |
genders |
String | Eligible genders (M, F, MF, X) |
category |
String | Category within the competition (e.g., "OPEN", "M", "U11", "BMC2") |
parent |
String | Parent event reference for combined events (empty string if none) |
question |
String | Entry question text associated with this event |
Scheduling¶
| Field | Type | Description |
|---|---|---|
day |
Integer | Competition day this event is scheduled on |
rounds |
String | Round structure as comma-separated values (e.g., "1" = straight final, "8,3,1" = 8 heats, 3 semis, 1 final) |
r1_time |
Time | Round 1 scheduled time (e.g., "19:15") |
r2_day |
Integer | Day for round 2 |
r2_time |
Time | Round 2 scheduled time (nullable) |
r3_day |
Integer | Day for round 3 |
r3_time |
Time | Round 3 scheduled time (nullable) |
r4_day |
Integer | Day for round 4 |
r4_time |
Time | Round 4 scheduled time (nullable) |
r1_status |
String | Status of round 1: none, partial, complete |
r2_status |
String | Status of round 2 |
r3_status |
String | Status of round 3 |
r4_status |
String | Status of round 4 |
status |
String | Overall event status: none, partial, complete |
hide_in_timetable |
Boolean | Whether this event is hidden from the public timetable |
heat_time_calculation |
String | Method for calculating heat times: AUTO or manual |
heat_time_override |
Time | Override time for heat calculation (nullable) |
Lanes & Seeding¶
| Field | Type | Description |
|---|---|---|
lanes |
Integer | Number of lanes available for round 1 |
lanes_r2 |
Integer | Number of lanes for round 2 |
lanes_r3 |
Integer | Number of lanes for round 3 |
lane_prefs |
String | Lane preference configuration (nullable) |
seeding |
String | Seeding method (e.g., open_meet) |
seeding_method |
String | Seeding algorithm for round 1 (e.g., fastest_last) |
seeding_method_r3 |
String | Seeding algorithm for round 3 |
pool_order |
String | Pool ordering method (e.g., random) |
reorder_last_round |
Boolean | Whether to reorder athletes in the last round |
rank_by |
String | Ranking method: DEFAULT or custom |
Entry Limits¶
| Field | Type | Description |
|---|---|---|
limit |
Integer | Maximum number of entries allowed (nullable) |
entry_limit_per_event |
Integer | Per-club entry limit (nullable) |
relay_entry_limit_per_event |
Integer | Per-club relay entry limit (nullable) |
entry_limit_per_ns_event |
Integer | Per-club non-scorer entry limit (nullable) |
non_scorers_per_scoring_event |
Integer | Number of non-scorers allowed per scoring event (nullable) |
Qualification¶
| Field | Type | Description |
|---|---|---|
qual_by_place |
Integer | Number of athletes qualifying by place from round 1 (nullable) |
qual_fastest_losers |
Integer | Number of fastest losers qualifying from round 1 (nullable) |
qual_by_place_r3 |
Integer | Number qualifying by place from round 2 (nullable) |
qual_fastest_losers_r3 |
Integer | Number of fastest losers qualifying from round 2 (nullable) |
qual_criteria |
String | Qualification criteria description (nullable) |
qualifying_performance |
String | Automatic qualifying performance standard (nullable) |
cut_after_round |
Integer | Round after which to apply cut (0 = no cut) |
cut_survivors |
Integer | Number of survivors after cut |
min_perf |
String | Minimum performance standard for entry (nullable) |
max_perf |
String | Maximum performance standard for entry (nullable) |
Display & Appearance¶
| Field | Type | Description |
|---|---|---|
primary_colour |
String | Primary colour for display (nullable) |
text_colour |
String | Text colour for display (nullable) |
show_form_guide |
Boolean | Whether to show form guide for this event |
record_text |
String | Record text to display (nullable) |
record_perf |
String | Record performance value (nullable) |
world_athletics_event_id |
String | World Athletics event identifier (nullable) |
remote_results_url |
URL | External URL for remote results (nullable) |
Scoring & Combined Events¶
| Field | Type | Description |
|---|---|---|
ce_score_formula |
String | Combined events scoring formula (e.g., x for none, or a specific formula) |
combined_event_tables |
String | Combined events scoring tables used (nullable) |
exclude_from_scoring_system |
Boolean | Whether excluded from team/league scoring |
max_field_attempts |
Integer | Maximum field event attempts (default: 6) |
Flags & Behaviour¶
| Field | Type | Description |
|---|---|---|
team_types |
String | Team type configuration: INHERIT or custom |
require_callroom_override |
Boolean | Whether call room is required for this event |
callroom_time_override |
Time | Override for call room time (nullable) |
exclude_from_per_event_checkins |
Boolean | Whether excluded from per-event check-in |
include_dns_athletes |
Boolean | Whether DNS (Did Not Start) athletes are included in results |
include_dnf_athletes |
Boolean | Whether DNF (Did Not Finish) athletes are included in results |
include_dq_athletes |
Boolean | Whether DQ (Disqualified) athletes are included in results |
Fetching Events¶
List All Events¶
GET /api/events/
Returns a paginated list of event specs. By default the list returns all events you have permission to see. Add ?my_competitions=1 to scope it to competitions you administer.
Retrieve a Specific Event¶
By natural key (recommended):
GET /api/x/{year}/{country}/{slug}/event/{event_id}/
Example: GET /api/x/2026/GBR/lac-open-2/event/T01/
Returns a single event spec record by its competition natural key and event identifier.
By primary key:
GET /api/events/{id}/
Example: GET /api/events/1/
Returns a single event spec record by its primary key ID. Both patterns return the same event spec record.
List Events for a Specific Competition¶
By natural key (recommended):
GET /api/x/{year}/{country}/{slug}/event/
Example:
GET /api/x/2026/GBR/lac-open-2/event/
Returns all events for the competition identified by its natural key.
By competition UUID:
GET /api/events/?competition={competition_uuid}
Example:
GET /api/events/?competition=7cd7f7a8-67a4-4cb7-93b9-21e91f4b8934
Creating Events¶
Create a New Event¶
POST /api/events/
Requires authentication with appropriate permissions. The request body should be a JSON object with the relevant fields. At minimum, competition, event_id, event_code, name, genders, and rounds are required.
Example - Create a running event:
{
"competition": "7cd7f7a8-67a4-4cb7-93b9-21e91f4b8934",
"event_id": "T01",
"event_code": "100",
"name": "100 metres Men",
"genders": "M",
"category": "OPEN",
"age_groups": "SEN,U20,U17",
"rounds": "1",
"lanes": 8,
"r1_time": "10:00",
"day": 1,
"limit": 32
}
Example - Create a field event:
{
"competition": "7cd7f7a8-67a4-4cb7-93b9-21e91f4b8934",
"event_id": "F01",
"event_code": "LJ",
"name": "Long Jump Women",
"genders": "F",
"category": "OPEN",
"age_groups": "SEN,U20,U17",
"rounds": "1",
"r1_time": "14:00",
"day": 1,
"max_field_attempts": 6
}
Updating Events¶
Full Update (PUT)¶
PUT /api/events/{id}/
Replaces the entire event spec record. All required fields must be provided.
Partial Update (PATCH)¶
PATCH /api/events/{id}/
Only updates the fields provided in the request body.
Example - Update event name and time:
{
"name": "100 metres Men - Updated",
"r1_time": "11:00"
}
Example - Update event status:
{
"status": "complete"
}
Deleting Events¶
Delete an Event¶
DELETE /api/events/{id}/
Deletes the event spec and all associated data (units, results, entries). This action is irreversible.
Filtering¶
You can filter the events list using the following query parameters:
| Parameter | Type | Description | Example |
|---|---|---|---|
competition |
UUID | Filter by competition UUID | ?competition=7cd7f7a8-67a4-4cb7-93b9-21e91f4b8934 |
event_id |
String | Filter by custom event identifier | ?event_id=F1 |
event_code |
String | Filter by athletics event code | ?event_code=100 |
age_groups |
String | Filter by age group(s) | ?age_groups=SEN |
genders |
Choice | Filter by gender (M, F, MF, X) |
?genders=M |
category |
String | Filter by category | ?category=OPEN |
competition_year |
Number | Filter by competition year | ?competition_year=2025 |
my_competitions |
Flag | Scope to competitions you administer | ?my_competitions=1 |
Filter Examples¶
The natural key URL is deliberately simple: it returns all events for a competition and does not take filter parameters.
List all events for a competition via its natural key URL:
/api/x/2026/GBR/lac-open-2/event/
To filter events (e.g. running events, event code "100"), use the standard list endpoint with the competition UUID:
/api/events/?competition=7cd7f7a8-67a4-4cb7-93b9-21e91f4b8934&event_code=100
Get all field events (event code "HJ" = High Jump):
/api/events/?event_code=HJ
Get events for a specific year:
/api/events/?competition_year=2025
Get events for male athletes only:
/api/events/?genders=M
Searching¶
The API supports text search across event names using the search parameter:
| Parameter | Description | Example |
|---|---|---|
search |
Search in event name field | ?search=100 |
Search Example¶
Find all events matching "800":
/api/events/?search=800
Ordering¶
You can order the results using the ordering parameter. Prefix with - for descending order.
| Field | Description |
|---|---|
id |
Order by event spec ID |
name |
Order by event name |
event_code |
Order by event code |
competition |
Order by competition UUID |
day |
Order by competition day |
r1_time |
Order by round 1 scheduled time |
status |
Order by overall status |
age_groups |
Order by age groups |
Ordering Examples¶
Order by name (A to Z):
/api/events/?ordering=name
Order by name (Z to A):
/api/events/?ordering=-name
Order by day, then by time:
/api/events/?ordering=day,r1_time
Order by most recently created (highest ID first):
/api/events/?ordering=-id
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 events:
/api/events/?limit=10
Get events 21-30 (second page of 10):
/api/events/?limit=10&offset=20
Get 100 events ordered by name:
/api/events/?limit=100&ordering=name
Response Structure¶
Paginated responses include:
{
"count": 123762,
"next": "https://test-data.opentrack.run/api/events/?limit=50&offset=50",
"previous": null,
"results": [
{
"url": "https://test-data.opentrack.run/api/events/1/",
"competition": "7cd7f7a8-67a4-4cb7-93b9-21e91f4b8934",
"event_id": "F1",
"event_code": "HJ",
"name": "High Jump",
"age_groups": "SEN,U13,U15,U17,U20",
"genders": "MF",
"category": "OPEN",
"limit": 12,
"rounds": "1",
"day": 1,
"r1_time": "19:15",
"lanes": 8,
"status": "none",
...
}
]
}
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 event spec records for the current page
Combined Query Example¶
Get the first 20 running events (event_code "100") for a specific competition, ordered by round 1 time:
/api/events/?competition=7cd7f7a8-67a4-4cb7-93b9-21e91f4b8934&event_code=100&ordering=r1_time&limit=20
Get all completed field events on day 1:
/api/events/?event_code=LJ&status=complete&day=1
Permissions¶
All API endpoints require authentication — there are no public endpoints. Log in with a valid API token or session cookie to access them.
- Authenticated users can list all events and view any event's details
- Competition directors and admins have full CRUD access to their competition's events
- Federation admins have access to all competitions within their federation
- Write operations (POST, PUT, PATCH, DELETE) are only permitted until 7 days after the competition finishes
- The standard list endpoints return events from all competitions; use
?my_competitions=1to restrict to competitions you administer
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¶
- The event
id(primary key) in the standard URL is the auto-incrementing database ID, not theevent_idstring field - The natural key pattern (
/api/x/{year}/{country}/{slug}/event/{event_id}/) addresses events by their competition plusevent_idstring (e.g.T01,F1) and is the recommended way to reference a single event - The
event_codefield uses standard athletics codes (e.g., "100", "200", "400", "800", "1500", "HJ", "LJ", "SP", "DT", "JT", "PV") - Events with
rounds="1"are straight finals; multi-round events use comma-separated values (e.g.,"8,3,1"for 8 heats, 3 semi-finals, 1 final) - The playground interface is only available when accessing via a web browser with proper authentication