Live Timing Standard v2 (not used)
Proposal currently in draft form waiting for timer feedback
This document covers a draft proposal for Version 2 of the Triathlon.org Live Timing Standard. The current version 1 may be found here.
Overview
The aim of Version 2 of the Triathlon.org Live Timing Standard is to produce a higher quality of real-time timing data directly from races which may be delivered via the Triathlon.org API platform to subscribers. The improvements proposed in the standard reduce timing latency and greatly increase the potential for displaying timing data and developing feature-rich timing applications when used in conjunction with other available APIs. The proposal also removes the requirement for timers to host any web-facing hosts as timing will be pushed to the Triathlon.org API platform which will handle the delivery of timing messages to all connected clients. Significantly, the standard is designed to support all ITU sanctioned events including Paratriathlon by incorporating custom data fields. Whilst greatly simplified, this timing standard is much more similar in scope to the Olympic Data Feed.
Delivery
Timing should be delivered by a series of timing messages that each contain full information as to the current state of the race. Each message, which contains valid JSON as the body of a POST request with a corresponding Content-type: application/json header, should be delivered to the /live/timing API endpoint.
Authentication
Timers will use the standard API authentication method adding authentication parameters to the header of all requests sent. Each timer will be provided a unique API key to use specific to their timing application.
Response Codes
The Triathlon.org API will respond with a 2xx response on successful receipt of the message. All other response codes should be considered a failure. Badly formatted or unauthenticated messages will result in a 4xx code. For reference, our general response codes are available here.
Retry Policy
Timers should implement a sensible (needs more clarification) retry policy to primarily cover the case of a loss of internet connectivity at the venue. As each message contains entire timing information if a later message is available (defined as a later timing message id) there is no need to retry an earlier message. For reference you may also consult the retries policy of the Subscription API.
Validation
All timing messages should validate against current JSON standards. Any messages that do not contain valid JSON or are missing required data fields will be rejected by the Triathlon API validation mechanism and a 400 response code returned.
Push Frequency
Timing messages should be pushed immediately on receipt of new timing information i.e. an athlete crossing a timing point. For times when there would be an overwhelming number of updates e.g. a large bike pack crossing a timing point, messages should be combined into a single message such that push frequency does not exceed one push every 500ms (limit subject to discussion). Messages should only be pushed when there is a change of information in the message and messages should not be sent according to a fixed time schedule.
Message Persistence
Timers do not need to persist timing messages as this will be handled via the Triathlon API platform with specific messages available for historical analysis / replay via the Live API.
Concurrent Races
Often there will be more than one race occurring at the same time (defined by race_code or prog_id which are both unique). Each race should be considered a single entity and formatted according to the specification. Logic should be present to handle instances when multiple athletes from different races cross a timing point at the same time.
Testing
For development purposes you may use the sandbox boolean to indicate that you wish to send to the sandbox environment, which will perform exactly as the production environment with the exception that messages will not be published.
Timing Message Format
Each timing message should contain complete timing information such that a user may be able to retrieve all information by receiving the latest timing push message. All message characters should be UTF-8 formatted.
A curtailed sample format of timing messages is as follows:
{
"id":1234,
"date":"2017-01-01 13:34:59.123Z",
"race_code":"EM",
"event":"2017 ITU World Triathlon Abu Dhabi",
"sandbox": true,
"event_id":35645,
"prog_id":23567,
"start_time":"2017-01-01 13:26:59.123Z",
"num_athletes":2,
"latest":{
"segment_id":3,
"segment_name":"Bike Lap 4",
"num_athletes":1
},
"athletes":[
{
"athlete_id":12345,
"start_num":23,
"athlete_name":"Test Athlete",
"athlete_nat":"GBR",
"latest_segment":3,
"position":1,
"time":"01:23:23",
"splits":[
{
"segment_id":1,
"segment_name":"Swim Lap 1",
"segment_time":"00:08:12",
"segment_distance":0.75,
"cumulative":"00:08:12",
"position":12,
"difference":"00:00:15"
},
{
"segment_id":2,
"segment_name":"Swim Exit",
"segment_time":"00:08:15",
"segment_distance":0.75,
"cumulative":"00:16:27",
"position":9,
"difference":"00:00:12"
},
{
"segment_id":3,
"segment_name":"T1",
"segment_time":"00:00:54",
"segment_distance":null,
"cumulative":"00:17:21",
"position":9,
"difference":"00:00:11"
}
]
},
{
"athlete_id":54321,
"start_num":22,
"athlete_name":"Another Test Athlete",
"athlete_nat":"CAN",
"latest_segment":2,
"position":12,
"time":"01:23:23",
"splits":[
{
"segment_id":1,
"segment_name":"Swim Lap 1",
"segment_time":"00:08:12",
"segment_distance":0.75,
"cumulative":"00:18:12",
"position":15,
"difference":"00:00:15"
},
{
"segment_id":2,
"segment_name":"Swim Exit",
"segment_time":"00:08:17",
"segment_distance":0.75,
"cumulative":"00:16:29",
"position":12,
"difference":"00:00:12"
}
]
}
]
}A breakdown of each parameter is listed below:
Parameter | Example | Description | Format |
|---|---|---|---|
id | 1 | The id of the message which should be sequential and start from 1 for each race (defined by the prog_id) | number |
date | 2017-01-01 13:34:59.123Z | An ISO 8601 formatted date of the time of the message | string |
race_code | EM | A descriptive name for the race | string |
event | 2016 ITU World Triathlon Abu Dhabi | A descriptive name for the event | string |
sandbox | true | Boolean to indicate whether to use the sandbox environment for development (defaults to false) | boolean |
event_id | 12345 | The unique event_id corresponding to the event_id in the Events API | number |
prog_id | 54321 | The unique prog_id corresponding to the prog_id in the Events API | number |
start_time | 2017-01-01 13:34:59.123Z | An ISO 8601 formatted date corresponding to the start time of the race | string |
num_athletes | 12 | The number of athletes in the race (which must correspond to the number of items in the athletes array) | number |
latest | The latest object contains information regarding the latest timing point data (may be null if no timing data) | object | |
latest.segment_id | 1 | The segment_id containing the latest result | number |
latest.segment_name | Swim Exit | The segment name containing the latest results | string |
latest.num_athletes | 12 | The number of athletes that have passed through the timing point | number |
athletes | An object containing an array of all athletes in the race | object | |
athletes.id | 123456 | The unique athlete_id corresponding to the athlete_id in the Athletes API | number |
athletes.start_num | 12 | The start number of the athlete | number |
athletes.name | Alistair Brownlee | The name of the athlete | string |
athletes.nat | GBR | The three letter IOC country code | string |
athletes.latest_segment_id | 3 | The latest segment_id that contains data for the athlete (may be nullif no data) | number |
athletes.position | 12 | The latest position of the athlete (may be null if no data) | number |
athletes.time | 00:17:16.145 | string | |
athletes.splits | An array of split objects containing data for each segment completed by the athlete (may be nullif no data) | object | |
athletes.splits.segment_id | 3 | The segment_id of the split | number |
athletes.splits.segment_name | Swim Exit | The name of the timing segment | string |
athletes.splits.segment_time | 00:08:16.345 | The time to complete this segment | string |
athletes.splits.segment_distance | 750 | The distance of the segment specified in m (may be nullif not defined) | number |
athletes.splits.cumulative_time | 00:14:12.345 | The cumulative time of all segments to this point | string |
athletes.splits.position | 12 | The position of the athlete at this timing point | number |
athletes.splits.difference | 00:01:07.123 | The difference of the athlete to the leader at this timing point | string |
Notes
- All athletes must be present in the athlete array regardless of their status in the race.
- Millisecond data may be provided where available.
- Athletes should be ordered in the athletes array according to the latest timing point information, naturally athletes crossing the latest timing point will be ordered first and DNF athletes will be at the end of this list with the remainder of the athletes ordered in relation to their position at the previous timing point.
- A list of segment_ids & names will need to be provided by the timers prior to the start of an event as these are subject to course conditions.
- The segment_distance parameter is optional and may be included if such data is available and relevant.
Paratriathlon
A para object is provided within the athlete object (athletes.para) for Paratriathlon events indicating additional Paratriathlon specific information for the athlete. These fields are optional depending on the Paratriathlon class.
Parameter | Example | Description | Format |
|---|---|---|---|
athlete.para | A Paratriathlon specific object | object | |
athlete.para.guide_name | David Barnett | The name of the Paratriathlon guide | string |
athlete.para.guide_id | 1234 | The athlete_id of the Paratriathlon guide according to the Athletes API | number |
athlete.para.start_delay | 15 | The number of seconds delay in a staggered start format event | number |
Optional Data Objects
The format allows in the future for additional data objects to be provided if such data becomes available such as real-time weather data or GPS positioning of athletes. The schema of such objects will be devised when delivering this data becomes feasible.
Distribution
Timing will be distributed by the Triathlon API platform to applications through the Live REST API, Subscriptions API and Streaming APIs to all connected applications.
