This is a read me and FAQ for our API. Please note, using the API requires addition fees that vary based on your project. Please contact commercial@liveheats.com with some basic information about the project you're looking to use our API for and we can assist with a quote.
Full API docs can be found at https://docs.liveheats.com/.
Our API can be used by your software developers for projects using Liveheats data. Example projects may include:
- custom graphics for integration into live streaming or broadcasts (if our standard graphics are not sufficient). Example from X Games:
- custom integration of live scores, results, and rankings into your website (if our standard website embed is not sufficient). Example from Freeride World Tour:
How to access and explore the LiveHeats API & documentation
LiveHeats uses a GraphQL API to display data on the public website (https://liveheats.com). All screens that you see when navigating through organisations and events in the Liveheats website fetch their data using the LiveHeats API, so anything that you can see on the website without being logged in, you can get through the API to display where and how you need.
GraphQL is a very powerful query language for APIs which allows developers to predictable extract the exact data they need by traversing the schema available. It does, however, require a bit of knowledge on how it works in order to get properly started, so if you are unfamiliar with GraphQL and it's main concepts, we suggest reading about it in https://graphql.org/learn/
The rest of this guide assumes familiarity with GraphQL Queries and their Variables, and Types
- The API url is https://liveheats.com/api/graphql
-
GraphQL provides it's own online API documentation, which can be accessed on the same URL you will use for querying the API: https://liveheats.com/api/
graphql -
You can use a desktop client like GraphiQL to explore the API, where can view the available GraphiQL queries and types
- You'll need to find the specific event, eventDivision or heat ids that you'll need to query to fetch the relevant data. These IDs can only be accessed after being created by the event organiser. The IDs can be found in the public event page urls (e.g.: when the public event page url is https://liveheats.com/events/28328 the eventId is "28328", and for the JACKALOPE_STREET SKATE_WOMENS divisions https://liveheats.com/events/28328/divisions/107658 the eventDivisionId is "107658")
- Full API docs can be found at https://docs.liveheats.com/.
How to fetch private data with an access token
Some data accessible via our GraphQL API is private and requires appropriate permissions. To access this data, you'll need an access token, which will be generated using the OAuth 2.0 client credentials grant flow.
The necessary client_id and client_secret need to be requested by contacting us at commercial@liveheats.com.
Example request to obtain a token:
One way to obtain a token is by attaching the encoded client_id (username) and client_secret (credential) to the HTTP Basic auth header in your request, like so:
curl -X POST https://liveheats.com/oauth/token -H 'Authorization: Basic xxxxxxxxxx' -H 'content-type: application/x-www-form-urlencoded' -d 'grant_type=client_credentials&scope=public events/director organisations/manage'
Note: tokens have a short lifespan, you should generate a new token for each interaction with the service.
Example response:
{
"access_token": "VNzy5VGa9qP8bb7rQf1jUWf5QGP2aAn_OV_B_DozACA",
"token_type": "Bearer"
"expires_in": 7200,
"scope": "public events/director organisations/manage"
"created_at": 1662094017
}
Example request using the token:
curl -X POST https://liveheats.com/api/graphql -H 'Content-Type: application/json' -H 'Authorization: Bearer VNzy5VGa9qP8bb7rQf1jUWf5QGP2aAn_OV_B_DoZACA' -d '{"query": "query {event (id: 1){name}}"}'
A Brief Introduction to LiveHeats data structure
Although the heat will usually be the source of the most valuable data (e.g. the athletes in the heat, the heat results and all score data associated, priority places for each athlete (for sports that use a priority system, like surfing, bodyboarding, skimboarding, etc)), there are a couple other important models:
- the Event is where all competition data is aggregated, including all draws, heats and the scheduled running order
- the EventDivision is where a specific draw lives, which will include all rounds and heats for that division (e.g. the draw for Open Womens Shortboard). If you are looking at displaying draw information (how many rounds, how many heats in which round, which ones are finished which ones are upcoming), or scores for heats that have finished, or leaderboards for rounds, you'll be looking in here.
- the Schedule is the running order of heats in an event. If you are looking at displaying scores and results for Heats while they are live, or if you want to display athlete information for upcoming heats, you'll be looking in here to figure out which heat is Live and which are coming next during the competition.
- the Heat. Just to emphasize that all the score and result data lives in a heat. You can get heat data through the event, through the eventDivision or through the schedule, but you can also query a heat directly to get or update the data on it.
Some example queries
On the below examples, we'll have a block with a human readable query that can actually be copy/pasted into a browser like Chrome, where the address bar will encode the query for you, and display the result. Once pasted into a browser, you can copy the encoded value to plug in and use in any software which you will use to retrieve data. You can use the examples to further expand your query with whatever other bits of data you need, and once built paste it on the browser to get the full encoded URL.
How to get data about an event including all its divisions
https://liveheats.com/api/graphql?query=
query event($id: ID!) {
event(id: $id) {
id
name
date
daysWindow
status
eventDivisions {
division {
id
name
}
}
}
}&operationName=event&variables={"id":"28328"}
This fetches some data for the event (event id: 28328 - https://liveheats.com/events/28328) and it's event divisions, including their ids and name. The full event window can be calculated adding the event.daysWindow to the event.date.
How to get the event schedule which includes the running order of the heats
https://liveheats.com/api/graphql?query=
query event($id: ID!) {
event(id: $id) {
id
name
currentScheduleIndex
fullSchedule {
breaks {
date
position
}
podiums {
name
heats {
id
round
roundPosition
position
eventDivision {
division {
name
}
}
}
}
heatsIntervalSeconds
}
}
}&operationName=event&variables={"id":"28328"}
There's a bit to unpack here, so bear with us.
- The event.fullSchedule will contain 2 podiums -> this mirrors how the schedule is configured by the event organisers, they can put heats into the "Main bank" or "Secondary bank" (only 2 podiums are supported at the moment, and they cannot have custom names unfortunately).
- Each podium.heats will contain an array of heats in the running order from start to finish. If a podium contains "null" in an index, this means there is no heat running in that podium at that time. If both podiums contain heats in the same index, it means that both those heats will start at the exact same time, so both will be live when the event reaches that point in the schedule.
- The event.currentScheduleIndex is used to determine where the event is in the schedule.
How to get a full draw for an event division, including all athletes in all heats in all rounds
https://liveheats.com/api/graphql?query=
query eventDivision($id: ID!) {
eventDivision(id: $id) {
id
division {
name
}
heats {
id
round
roundPosition
position
competitors {
teamName
position
athlete {
name
image
nationality
}
}
}
}
}&operationName=eventDivision&variables={"id":"107656"}
This fetches the athletes in each heat of each round for the JACKALOPE_STREET SKATE MEN division (https://liveheats.com/events/28328/divisions/107656).
Couple of things to note:
- The heat.round will be the actual name of the round (e.g. Quarterfinal, Final, Round 1, etc)
- The heat.roundPosition will be the index of the round in that draw, starting from 0
- The heat.position will be the index of the position of a heat in a round. So in a draw that has 4 rounds (Round 1, Quarterfinal, Semifinal, Final), Quarterfinal Heat 3 will have the following properties: heat.round = "Quarterfinal"; heat.roundPosition = 1; heat.position = 2
- The competitor.position determines the athlete's start position or order (or in cases that use jerseys, their jersey color) in the heat
How to get results and scores for a heat
https://liveheats.com/api/graphql?query=
query heat($id: ID!) {
heat(id: $id) {
id
round
roundPosition
position
startTime
endTime
eventDivision {
division {
name
}
}
competitors {
athleteId
position
teamName
athlete {
name
image
nationality
}
}
result {
athleteId
place
total
winBy
needs
rides
}
}
}&operationName=heat&variables={"id":"1337810"}
This retrieves the scores and results data for the final in the JACKALOPE_STREET SKATE MEN division (https://liveheats.com/events/28328/divisions/107656).
The most relevant bit is the result array. This will always be the most up to date result list (at the time of retrieving the information) in order of highest placed to lowest placed (winner to loser). Each entry in result will look something like this:
"result": [
{
"athleteId": 22,
"place": 1,
"total": 14.0,
"winBy": 1.16,
"needs": null,
"rides": {
"22": [
{
"scores": {
"108": 5.2,
"106": 5.5,
"107": 4.5
},
"total": 5.07,
"modified_total": 5.07,
"modifier": null
},
{
"scores": {
"106": 6.0,
"108": 6.5,
"107": 5.5
},
"total": 6.0,
"modified_total": 6.0,
"modifier": null,
"scoring_ride": true
},
(...)
{
"scores": {
"108": 4.5,
"106": 4.7,
"107": 4.5
},
"total": 4.57,
"modified_total": 4.57,
"modifier": null
}
]
}
},
(...)
]
The result.total will be the final score for that athlete including all of their scoring rides. result.rides will have an athleteId keyed list of rides. Each ride will contain its total and modified_total (the modified_total will actually be the value used in the final score calculation, taking into account any modifiers that need to be applied to that ride, such as Interferences. In a surfing example, if an athlete receives an Interference and their second highest ride had an 8.33 score, on that ride total will be 8.33 and modified_total will be 0), and all the judge scores under scores, which are keyed by judge_id. If a specific ride counts towards the athlete's main total, it will have the attribute scoring_ride as true.
How do I get a round leaderboard result with scores
In events where results for a round are determined by the entire round leaderboard, as opposed to individual heat results, it might be required to get the full round result data to display the leaderboard.
https://liveheats.com/api/graphql?query=
query getEventDivisionLeaderboard($id: ID!, $round: Int) {
eventDivision(id: $id) {
id
leaderboards(round: $round) {
round
startTime
endTime
result {
athleteId
total
rides
}
competitors {
athleteId
athlete {
name
image
}
}
}
}
}&operationName=getEventDivisionLeaderboard&variables={"id":"107656","round":1}
This retrieves the Semifinal leaderboard for the JACKALOPE_STREET SKATE MEN division (https://liveheats.com/events/28328/divisions/107656).
The result data is exactly the same as the heat result data, the only difference is that it will include the result for the entire round. Note the round variable at the end of the query. This needs to be the index of the round in that particular draw.
API Common Questions
What is the URL or address for the API (or data feed)?
The address you will use is our GraphQL API address which is https://liveheats.com/api/graphql. You’ll want to use a desktop application like Graphiql to explore the types and queries available.
If you are unfamiliar with GraphQL have a read through this: https://graphql.org/learn/
Where can we find the actual API Documentation?
Full API docs can be found at https://docs.liveheats.com/.
What is the data format in the API?
JSON
Can I access an API Sandbox?
We don't have a Sandbox environment, but you can explore & test the API using production data - either by accessing any public event available on www.liveheats.com or by running a test event. You can use the free trial credit upon account sign up to do any testing.
How do I find the event ID, heat ID, and other items?
You can use the public event page url and url paths of each page to determine the IDs. To find an event ID, go to www.liveheats.com/organisations find the organisation running your event (or your test), and click on the event. The event page URL will look something like https://liveheats.com/events/5009 and therefore the event ID is "5009".
How do I get the athlete's name when looking at the heat result
Each heat result item will contain an athleteId. You can use that athlete id to find the competitor (inside heat.competitors) with the same athleteId and inside that competitor you'll be able to access athlete.name.
How do we access the heat countdown timer?
The heat has 2 properties which are used to calculate the timer: startTime and heatDurationMinutes. Using those, you can calculate how much time is left on the heat and render a timer.