Skip to content

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"])