Road and XC results bulk upload¶
Update, replace, or append results to a simple road or cross country race.
All our competitions have a URL target ending with roadxc_upload/
which accept PUT requests from competition directors. The example below demonstrates how to modify the results of a test competition
at https://test-data.opentrack.run/en-gb/x/2026/GBR/api-test
1. Authenticate as a user with 'Director' permissions¶
import requests
import zlib
username = os.environ.get("username", "api-test@mailinator.com")
password = os.environ.get("password", "apitest")
BASE_URL = 'https://test-data.opentrack.run/'
r1 = requests.post(BASE_URL + 'api/get-auth-token/',
data=dict(username=username,
password=password))
token = r1.json()["token"]
2. Send a results dictionary¶
COMP_URL = 'https://test-data.opentrack.run/api/2026/GBR/api-test/'
sample_data = dict(
{"eventid": "R1", # must correspond to the ID given to the race in the Event Grid
"round": 1,
"heat": 1,
"eventname": "5k",
# choose between modes:
# update (modify existing results)
# append (add any new results, leave existing ones unchanged)
# replace (delete all existing results and replace with this batch)
"mode": "update",
"ignore_unknowns": "True", # bibs below not entered in the race will be ignored
"data": [
["349", "14:25.10"], # bib, finish-time
["347", "14:33.00"],
["393", "14:36.00"],
["355", "14:39.00"],
["266", "14:44.00"],
["242", "14:45.00"],
["234", "14:47.00"],
["409", "14:47.00"],
["261", "14:47.00"],
["295", "14:53.00"]]
}
)
r2 = requests.put(
comp_url + "roadxc_upload/",
headers={'Authorization': "Token " + token},
data=zlib.compress(json.dumps(data).encode('ascii'))
)
Viewing competitions¶
Competitions for which the current user has permissions can be browsed in a human-friendly form at https://test-data.opentrack.run/api/my-competitions/
This will work for both token authentication and through cookies if a user is logged in through their browser. The unique ID of the competition can be used in the example below to access the results of a unit programmatically
r3 = requests.get(
BASE_URL + "api/my-competitions/?to_date=2026-12-25T12:00:00Z",
headers={"Authorization": "Token " + token}
)
comp = r3.json()['competitions'][-1]
comp_id = comp["id"]
comp_url = comp["url"]
print(comp_id, url)
Accessing results by unit¶
r4 = requests.get(
BASE_URL + f"api/unit/{comp_id}/",
headers={"Authorization": "Token " + token}
)
unit_info = r3.json()
print("Heat name is", unit_info["heat_name"])