The RTRT.me API allows developers to query event data via a public JSON+REST interface.
When accessing the API, use HTTPS and provide your Application ID in the query-string of the URL.
https://api.rtrt.me/?appid=[YOUR APP ID] |
Example: https://api.rtrt.me/?appid=4c5d9d5ef469f69057f7766a
In addition to the Application ID, any client using the API must have for a unique client ID. This is called the token.
To acquire a token, the client must make a register call to the following URL:
https://api.rtrt.me/register?appid=[YOUR APP ID] |
Example: https://api.rtrt.me/register?appid=4c5d9d5ef469f69057f7766a
The response will be a newly assigned token. For example:
{ "token":"89ad3f6700e2e68e6431315bdab00f54" } |
Use the token and appid in all future requests.
Example: https://api.rtrt.me/?appid=4c5d9d5ef469f69057f7766a&token=89ad3f6700e2e68e6431315bdab00f54
Tokens may expire after 30 days. Please contact us if you require a longer-living token.
NOTE: Throughout this document, example hyperlink's do not have appid or token visible in the query-string for the sake of readability. However, they are included in the href.
You can select event data by requesting a URL and parsing the JSON response.
NOTE: When doing queries in a standard web browser, we recommend installing a JSON formatting extension to help make the response readable. Optionally, you can force the format to 'pretty' JSON by passing in the querystring "&browser=1".
Below is a list of available queries. Follow the links for example responses.
Get list of all events (that I have access to).
/events |
Example: https://api.rtrt.me/events
Get details on a specific event.
/events/[EVENT NAME] |
Example: https://api.rtrt.me/events/EVENTDEMO
You can further control which fields you want to return by using the fields querystring option and a comma separated list fields to return.
/events/[EVENT NAME]?fields=name,shortName,desc |
Example: https://api.rtrt.me/events/EVENTDEMO?fields=name,shortName,desc
NOTE: When using the fields querystring parameter, every field requested will be returned even if there is no value for the field. Fields without values will be returned as empty strings.
Get list of pre-defined locations (or "points") associated with a specific event.
/events/[EVENT NAME]/points |
Example: https://api.rtrt.me/events/EVENTDEMO/points
Get info about a specific point.
/events/[EVENT NAME]/points/[POINT NAME] |
Example: https://api.rtrt.me/events/EVENTDEMO/points/5K
Get all splits that have been reported for a specific point.
/events/[EVENT NAME]/points/[POINT NAME]/splits |
Example: https://api.rtrt.me/events/EVENTDEMO/points/5K/splits
NOTE: For simplicity, all field values in the API are returned as strings. Type casting should be handled by your application when needed. For an explanation of fields, see field definitions.
You can specify more than one point name in a comma separated list to acquire a combined result.
/events/[EVENT NAME]/points/[POINT NAME,POINT NAME,POINT NAME]/splits |
Example: https://api.rtrt.me/events/EVENTDEMO/points/5K,10K,13.1M/splits
You can use a special keyword of 'ALL_POINTS' to get splits for all points.
/events/[EVENT NAME]/points/ALL_POINTS/splits |
Get list of profiles and search for profiles (participant names, bibs, and other profile information).
/events/[EVENT NAME]/profiles |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles
You can also search for participants by name. [QUERY] matches part of name based on a set of keywords. Search can be done on any combination and in any order such as 'first last' or 'last first', 'first middle', etc. Searching can also be enabled for 'city','charity' or 'team' if enabled for the event.
NOTE: Make sure to url encode spaces or other characters in your search request.
/events/[EVENT NAME]/profiles?search=[QUERY] |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles?search=jam
If [QUERY] is a number, a lookup on that bib number will be performed. Normally, only a single participant will be returned when a numeric bib or tag number matches. However, it is possible for more than one result on a number search if tag numbers are not the same as bib numbers, or if there are duplicate numbers in the event.
/events/[EVENT NAME]/profiles?search=103 |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles?search=103
NOTE: After numbers are assigned, each profile should have both a 'tag' and a 'bib'. A searches will match 'bib' instead of 'tag'. Tags are internal IDs, often zero padded such as "0000212", and are not to be used for public display. See profile fields for more info.
Sometimes, when searching profiles, it makes sense to limit results instead of dealing with pagination of result sets. You can set a limit using the max option along with the special failonmax option.
/events/[EVENT NAME]/profiles?search=[QUERY]&max=50&failonmax=1 |
When failonmax is enabled, and the number of matched profiles is equal to or greater than the max, you will receive an error object instead of the result set.
"error":{ "type":"too_many_results", "msg":"Max results reached and 'failonmax' is true. Not returning results" } |
This error should prompt the user to be more specific in the search. You might have a dialog which says something like
"Sorry, too many participants matched your search.
Try entering more of the name, or try entering the bib number only."
While, generally, it is recommended that sorting of small result be performed client-side, as a convenience, we have added the option of namesort. Setting this parameter to 1 will order names in result by last name, then first name when doing profiles search queries only.
NOTE: You may not use 'namesort' when "polling", and you should only use 'namesort' in combination with the 'failonmax' parameter.
Example: https://api.rtrt.me/events/EVENTDEMO/profiles?search=j&max=50&failonmax=1&namesort=1
You can control which fields you want to return by using the fields querystring option and a comma separated list fields to return.
/events/[EVENT NAME]/profiles?fields=tag,name,age,sex |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles?fields=tag,name,age,sex
Get roster profile by 'pid' (participant identifier) or by 'tag' number.
/events/[EVENT NAME]/profiles/[PID or TAG #] |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/RBXW4TA5
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/103
NOTE: A 'pid' is an 8 character alpha-numeric unique identifier beginning with the letter 'R' that is assigned to a participant. Example "RBXW4TA5". This is designed not to change for this participant even when tag number assignments change. Therefore, it is usually best to query the API using 'pid' instead of tag #.
NOTE: Internally, a 'tag' will be zero padded such as "00103". However, when referencing a profile tag in the API here, you do not need the zeros, i.e. "/103" will work.
Get roster profiles for a list of 'pids' or 'tags'.
/events/[EVENT NAME]/profiles/[LIST of PIDs or TAG #'s] |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/R2KRY3TV,RBXW4TA5
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/102,103
Get all splits (points) that have been reported for a specific profile or list of profiles.
/events/[EVENT NAME]/profiles/[LIST of PIDs or TAG #'s]/splits |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/103/splits
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/R2KRY3TV,RBXW4TA5/splits
Get split info on a single specific point, list of points, or latest point for a profile.
/events/[EVENT NAME]/profiles/[LIST of PIDs or TAG #'s]/splits/[POINT NAME] or /events/[EVENT NAME]/profiles/[LIST of PIDs or TAG #'s]/splits/[LIST of POINT NAMES] |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/RBXW4TA5/splits/5K
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/R2KRY3TV,RBXW4TA5/splits/5K,10K,13.1M
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/R2KRY3TV,RBXW4TA5/splits/LATEST_POINT
It is possible to retreive current estimated location information for participants by adding loc=1 to your querystring while requesting profiles/XXX or profiles/XXX/splits. This can be done with or without polling.
During the race or during a simulation, the info section will return a 'loc' object for each participant queried if they have started the race.
{ "list":[{ ... }], "info":{ "first":"1", "last":"1", "loc":{ "R2KRY3TV": { "multiplier": "1", "epc": "26.9", "emiles": "7.058", "mph": "6.52", "sslp": "466", "sss": "3918", "lpn": "10K", "npn": "10M", "etimes":{ "10M": { "label": "10M", "time": "01:19:01", "timeOfDay": "8:21:19 am", "coords": { "lat": "40.620478", "lng": "-74.029275" } }, "13.1M": { "label": "HALF", "time": "01:43:31", "timeOfDay": "8:45:49 am", "coords": { "lat": "40.624718", "lng": "-74.027538" } }, "20M": { "label": "20M", "time": "02:38:02", "timeOfDay": "9:40:20 am", "coords": { "lat": "40.648120", "lng": "-74.010817" } }, "FINISH": { "label": "FINISH", "time": "03:27:10", "timeOfDay": "10:29:28 am", "coords": { "lat": "40.650961", "lng": "-74.007864" } } } "ecoords": { "lat": "41.603477", "lng": "-87.930223" } } } } |
Meaning of 'loc' fields:
Field | Description |
---|---|
multiplier | Speed multiplier for simulation. Only changes when simulations are running. Normally, multipler is 1 (realtime). |
epc | Estimated Percentage of Completion. Gives a percentage of the participant's progress based on the course rounded to 1 decimal place. For example, a value of "50.1" would be slightly past the half-way point. |
emiles | Estimated Miles. Gives an estimated distance in miles traveled by the participant as measured from the start of the course. Multiply by 1.60934 for est. kilometers. |
mph | Miles Per Hour. Estimated current speed of participant. Multiply by 1.60934 for kilometers per hour. |
sslp | Seconds Since Last Point. Duration since seen at most recent point ('lpn'). |
sss | Seconds Since Start. Duration since starting. |
lpn | Last Point Name. Name of most recent published timing point. |
npn | Next Point Name. Name of next upcoming published timing point. |
overdue | Overdue Seconds. Seconds since participant was expected to have arrived at the next point. Only available if participant is overdue. |
ecoords | Estimated Coordinates. The estimated latitude and longitude of the particpant based upon projected movement along course. Only returned if coordinates can be determined, otherwise, 'ecoords' field will not be included in the response. Must pass additional querystring parameter of ecoords=1 on each request where this feature is needed. |
etimes | Estimated Times. The estimates for each upcoming point. Etimes for each pid can only be returned if the current estimated location can be determined. If not, some pids may excluded or, of no pids have esimates, the 'etimes' field will not be included at all in the response even if requested. The coords field is only availabe when map tracking is enabled and map is plotted in RTRT.me. Must pass additional querystring parameter of etimes=1 on each request where this feature is needed. |
NOTE: Not all fields defined are always present. For example, 'npn' would not be available after finished.
ALWAYS CHECK FOR EXISTENCE OF FIELDS BEFORE USING.
Missing Participants: If a participant's data is not arriving as expected within a reasonable leeway, or if we can no longer estimate a location for any reason, 'emiles' and 'epc' will return with a value of "-1". Also, ecoords and etimes will not be available.
Categories are predefined as needed for a specific event.
Get a list of available categories.
/events/[EVENT NAME]/categories |
Example: https://api.rtrt.me/events/EVENTDEMO/categories
Get list of participants in a category. The "fields=[field name, field name]" option is available as shown for the "/profiles" query above.
/events/[EVENT NAME]/categories/[CATEGORY NAME] |
Example: https://api.rtrt.me/events/EVENTDEMO/categories/top-women
Get splits for a category.
/events/[EVENT NAME]/categories/[CATEGORY NAME]/splits |
Example: https://api.rtrt.me/EVENTDEMO/categories/top-women/splits
Get splits for a single point, or list of points for a category.
/events/[EVENT NAME]/categories/[CATEGORY NAME]/splits/[POINT NAME] or /events/[EVENT NAME]/categories/[CATEGORY NAME]/splits/[LIST of POINT NAMES] or /events/[EVENT NAME]/categories/[CATEGORY NAME]/splits/LATEST_POINT |
Example: https://api.rtrt.me/events/EVENTDEMO/categories/top-women/splits/5K
Example: https://api.rtrt.me/events/EVENTDEMO/categories/top-women/splits/5K,10K,13.1M
Example: https://api.rtrt.me/events/EVENTDEMO/categories/top-women/splits/LATEST_POINT
As a convenience, there is an option of timesort. Setting this parameter to 1 will ensure order of splits returned is by time. May only be used in 'categories' queries and not while 'Polling'.
Example: https://api.rtrt.me/events/EVENTDEMO/categories/top-women/splits/5K?timesort=1
Get splits and places for a single participant (or list) in the context of the category.
/events/[EVENT NAME]/categories/[CATEGORY NAME]/splits/[POINT NAME (OR CSV)]/[PID or TAG # (OR CSV)] or /events/[EVENT NAME]/categories/[CATEGORY NAME]/splits/ALL_POINTS/[PID or TAG # (OR CSV)] |
Example: https://api.rtrt.me/events/EVENTDEMO/categories/top-women/splits/5K/RLB6XW9J
Example: https://api.rtrt.me/events/EVENTDEMO/categories/top-women/splits/ALL_POINTS/RLB6XW9J?timesort=1
NOTE: The 'place' field is not availabe on start points and will not be returned. If you require empty key/value, use fields=[LIST OF FIELDS] to mandate items for response.
Whenever you make a request that may have more than one result, the API will return an array called "list" that contains each of your results.
The default maximum number of results returned is 20. You may specify a different max in the query-string like so:
/events/[EVENT NAME]/points?max=5 |
NOTE: Highest max for anonymous requests is 1000. There is no limit when using authenticated tokens. Max set to 0 yields unlimited results for authenticated tokens. See Admin APIfor info about authenticated requests.
With any list, the API will also return an object called "info". Info will include stats on the query.
"info": { "first":1, "last":5, } |
With the exception queries on 'splits' and 'profiles', you can skip to a different set of results by adding start=### to your querystring.
/events/[EVENT NAME]/points?start=5&max=5 |
To skip through 'splits' or 'profiles', see 'Polling' below.
PLEASE NOTE: It is possible to get a count of the total objects in the list by adding 'total=1' to your querystring. However, it is best to develop without relying on 'total'. Totals are not guaranteed to be exactly precise at any given moment, and there is a slight performance cost from calculating them.
"Polling" can be done for splits or profiles. Polling in our case just means going back to see what is new since the last time you received any results. There are 2 polling methods:
• agt - to fetch all newly inserted or updated records matching your query. (most common)
• igt - to fetch only newly inserted records. (appropriate for live notification feeds)
Use one of these option in querystring to initiate polling. For example:
/events/[EVENT NAME]/categories/top-women/splits/5K?agt=0 |
Starting with agt=0 will bring in splits starting from the earliest insertion or update.
In the response, the "info" section will return the 'lasta', which is the insert or update stamp of the last record in the current set of results.
Now, to poll for the next set of results, you can use agt=[LASTA] in your querystring parameter. This will pull any results where insertion or update is greater than the value specified.
For example, let's say you have been polling, and in your last set of results, you had a 'lasta' of "1296493798_000281". Your next request should look like this:
/events/[EVENT NAME]/categories/top-women/splits/5K?agt=1296493798_000281 |
NOTE: If there are no results returned, you will receive an error object with a type of "no_results" on each request.
Depending on how much data you expect to receive, and how large of a response you want to be able to handle, you will likely want to increase the max parameter. NOTE: The default max is 20 records per request.
/events/[EVENT NAME]/categories/top-women/splits/5K?agt=1296493798_000281&max=100 |
If you are only interested in new inserts, and do not want any updated record info (appropriate for something like sending notifications), you would use the 'igt' polling method instead. For Example:
/events/[EVENT NAME]/categories/top-women/splits/5K?igt=1296493798_000281 |
In the response, the "info" section will return the 'lasti', which is the insert 'i' stamp of the last record in the current set of results.
NOTE: Split or profile records includes an 'i' or 'a' field. These fields are a stamp indictating the order of insertion or update, and consist of a combination of an insertion timestamp and a unique increment. For example:
"i":"1318783929_000007" - is the 7th insert which occurred within the unix timestamp 1318783929. |
On splits, you can also request the list to be in reverse order by adding reverse=1 to your querystring.
This would give the 3 most recent top women spits at the 5K.
/events/[EVENT NAME]/categories/top-women/splits/5K?max=3&reverse=1 |
During an event, splits usually become available to the system in logical order. However, order is not always guaranteed due to a number of factors.
For example, it is possible that the 5K point becomes available AFTER the 10K if the device transmitting the data at the 5K was temporarily disconnected from the network.
Another example, if two participants cross the same point at very close to the same time, order of appearance in the API can sometimes be reversed. A participant with the better time by hundreds of a second may appear in the API after a participant with a slower time.
Since sorting splits by time in the API is not compatible with polling, sorting should be done by your application client-side. We recommend sort by the 'time' or 'timestamp' fields when displaying lists of splits for a participant or in a leaderboard. The 'time' field is independent of when the point was inserted or updated.
You may be considering caching the results locally on your client or in your system somewhere. Caching data locally adds complexity since changes can occur in the RTRT platform after it has been received by your application. For this reason, we usually recommend an on demand approach to retrieving data for most use cases.
However, some applications need to cache or store data. Polling for updates and inserts (the agt model) takes care of many caching concerns, but polling alone will not inform you of 'deleted' split or profiles.
To aid with caching, we provide the following:
Profile Versions
The version of a profile is stored as the '_ver' field. This field will advance whenever 1) profile information has changed such as name, bib, city, etc. or 2) the participants 'split' data has been modified or updated or after first insertion.
Passing querystring parameter of 'pidversion=1' to a query for profile splits will yield a breakdown of the requested profiles version info as demonstrated below.
Get all splits for specific profile or list of profiles along with profile version info.
/events/[EVENT NAME]/profiles/[PID or LIST of PIDs]/splits?pidversion=1 |
Example: https://api.rtrt.me/events/EVENTDEMO/profiles/R2KRY3TV,RBXW4TA5,RZ9ZWPFS/splits?pidversion=1
This yields a regular list or error object, but with an added section to 'info'. For example:
{ "list":[{ ... }], "info":{ "first":"1", "last":"2", "lasti":"1324666245_000008", "pidversion": { "R2KRY3TV": "11", "RBXW4TA5": "13", "RZ9ZWPFS": "-1" } } } |
The info section now provides a 'pidversion' which is an object with keys of pids requested and values of each profile's current version.
If no record is found for a requested pid, the pid version will be equal to -1, e.g. RZ9ZWPFS: "-1". In this case, the profile has been removed from the system and you will likely want to remove the profile and all split data from your system.
A good strategy is to keep track of the '_ver' as returned in 'profiles' queries, and also pass 'pidversion=1' on every request to get splits. Then, check the 'pidversions' on each response. If you find that they do not match (or are flagged for deletion), you should uncache & reload or delete all data for that particular participant.
If for some reason your request either returns no results, or is invalid for any reason, the API will respond with an "error" object.
{ "error":{ "type":"[ERROR_TYPE]", "msg":"[ERROR MESSAGE]" } } |
Example: https://api.rtrt.me/oops
Example: https://api.rtrt.me/events/NOTHINGHERE
NOTE: For a list of possible errors, see error types.