Xhale Athlete API documentation
Introduction
Welcome to the API
The Xhale API is a REST web service and all responses are in JSON.
Request examples below are written for curl for experimenting on the command line, but you can of course use any language. Send your data with the Content-Type: application/x-www-form-urlencoded
header.
All requests should be made over HTTPS. Calls made with plain HTTP may be redirected to the secure protocol, but you should not rely on this.
Accessing the API
The Xhale API is a work in progress. If you would like to use it, please contact us at support@trainxhale.com so we can work with you to improve it for your requirements. Modifications to the API will occur in the future and while you can consider the API stable with a long lifetime before anything will break, it is still important that we can keep you informed and provide advise on updating your code.
To gain access to the API and receive your access credentials, please email our support@trainxhale.com address.
Two versions
The API is written for two audiences, either a single user or a coaching company. There is some crossover, but coaching companies have access to different data than a single user. This section is for a single user and requires each user to authenticate separately.
Authentication
Authentication to our API is carried out using the OAuth 2.0 protocol which will give you an access token to use when accessing the below endpoints. For more details please read the Xhale OAuth documentation.
Throttling
We currently have quite relaxed throttling so you probably won't encounter any problems, but if you encounter a limit please contact us. You will get a 429 error if you hit a limit with API requests, in which case you should ease off your requests a little.
Errors and responses
Status codes
- 200 - OK
- Standard successful response.
- 201 - Created
- The resource has been created.
- 204 - No Content
- Returned after a sucessful deletion.
- 400 - Bad request
- An error occurred to do with the request.
- 401 - Unauthorized
- A valid authentication token was not provided. Your access token may have expired, in which case you should make use of the user's refresh token.
- 403 - Forbidden
- Authenticated but you do not have access to this resource.
- 415 - Unsupported Media Type
- You've uploaded a file type we don't recognise.
- 429 - Too Many Requests
- You've reached a limit on API usage. See the body of the response for an explanation.
- 500 - Internal Server Error
- There is some kind of error on Xhale's servers.
Users
Get current user
Show details for the currently authenticated user
Example Request
curl -X GET https://trainxhale.com/api/users/current/ \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Example Response
{ "id":5, "email":"mentor@example.com", "season_dates":["2020-11-01","2021-10-31"], "seasons":[["2020-11-01","2021-10-31"]], "discipline_options": [ { "category": "swim", "id": 1, "title": "Swim Tech" }, { "category": "swim", "id": 2, "title": "Swim Intervals" }, { "category": "swim", "id": 3, "title": "Swim Endurance" }, { "category": "bike", "id": 4, "title": "Bike Intervals" }, { "category": "bike", "id": 5, "title": "Turbo Intervals" }, { "category": "bike", "id": 6, "title": "Bike Endurance" }, { "category": "run", "id": 7, "title": "Run Intervals" }, { "category": "run", "id": 8, "title": "Run Endurance" }, { "category": "run", "id": 9, "title": "Run Tempo" }, { "category": "brick", "id": 10, "title": "Brick Intervals" }, { "category": "brick", "id": 11, "title": "Brick Endurance" }, { "category": "gym", "id": 12, "title": "Gym Core/Specifics" }, { "category": "gym", "id": 13, "title": "Gym Lifting" }, { "category": "rest", "id": 14, "title": "Rest day" }, { "category": "other", "id": 15, "title": "Other" }, { "category": "diary", "id": 17, "title": "Diary" } ], "distance_unit_preference":"kilometers", "pool_unit_preference":"meters", "can_create_future_sessions":true, "first_name":"Mentor", "last_name":"User", "beta_access_list":[ "beta_feature_name" ], "diary_type":"mentor", "account_type":"coached", "zones": { "run": { "max_heart_rate":180, "zones":[ { "name": "Easy", "number":1, "heart_rate_min": 117, "heart_rate_max":134, "power_min":null, "power_max":null, "meters_per_second_fastest":3.4602076124567476, "meters_per_second_slowest":3.3557046979865772 }, { "name":"Steady", "number":2, "heart_rate_min":135, "heart_rate_max":147, "power_min":null, "power_max":null, "meters_per_second_fastest":3.7037037037037033, "meters_per_second_slowest":3.4722222222222223 }, { "name":"Moderate", "number":3, "heart_rate_min":148, "heart_rate_max":159, "power_min":null, "power_max":null, "meters_per_second_fastest":3.9682539682539684, "meters_per_second_slowest":3.717472118959108 }, { "name":"Hard", "number":4, "heart_rate_min":160, "heart_rate_max":168, "power_min":null, "power_max":null, "meters_per_second_fastest":4.291845493562231, "meters_per_second_slowest":3.9840637450199203 }, { "name":"All out", "number":5, "heart_rate_min":169, "heart_rate_max":180, "power_min":null, "power_max":null, "meters_per_second_fastest":5.649717514124294, "meters_per_second_slowest":4.310344827586206 } ]}, "bike":{ "max_heart_rate":175, "zones":[ { "name":"Easy", "number":1, "heart_rate_min":114, "heart_rate_max":130, "power_min":175, "power_max":190 }, { "name":"Steady", "number":2, "heart_rate_min":131, "heart_rate_max":143, "power_min":191, "power_max":210 }, { "name":"Moderate", "number":3, "heart_rate_min":144, "heart_rate_max":155, "power_min":211, "power_max":240 }, { "name":"Hard", "number":4, "heart_rate_min":156, "heart_rate_max":164, "power_min":241, "power_max":275 }, { "name":"All out", "number":5, "heart_rate_min":165, "heart_rate_max":175, "power_min":276, "power_max":350 } ] } } }
Training Sessions
The training session object
discipline_category can be one of 'swim', 'bike', 'run', 'brick', 'gym', 'other', 'rest', 'diary'
List sessions
List all training sessions for the current season for the authenticated user.
GET Parameters:
parameter | value type | example value |
---|---|---|
updated_since_datetime | ISO 8601 datetime string | 2015-06-17T03:00:00 |
start_date | ISO 8601 date string | 2015-06-17 |
end_date | ISO 8601 date string | 2016-06-16 |
Example Request
curl -X GET https://trainxhale.com/api/sessions/?updated_since_datetime=2015-06-17T03%3A00%3A00 \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Example Response
[ { "id":4, "athlete":5, "date":"2014-01-10", "order":"2", "datetime_added":"2015-06-18T02:03:14.513292", "datetime_updated":"2015-06-18T02:03:14.513292", "session_plan_editable": true, "brief_description":"", "deleted": false, "discipline_id":4, "discipline_title":"Bike Intervals", "discipline_category":"bike", "intensity":5, "prescribed_minutes":70, "prescribed_minutes_swim":null, "prescribed_minutes_bike":null, "prescribed_minutes_run":null, "prescribed_km":1.5, "prescribed_km_swim":null, "prescribed_km_bike":null, "prescribed_km_run":null, "completed_minutes":70, "completed_minutes_swim":null, "completed_minutes_bike":null, "completed_minutes_run":null, "completed_km":1.5, "completed_km_swim":null, "completed_km_bike":null, "completed_km_run":null, "training_plan":"Lorem ipsum dolor sit amet.", "athlete_feedback":"Lorem ipsum dolor sit amet.", "coach_comments":"Lorem ipsum dolor sit amet." "bike_average_speed_kph":null, "bike_average_power_watts":null, "bike_average_cadence_rpm":null, "bike_average_heart_rate_bpm":null, "bike_meters_climbed":null, "run_average_heart_rate_bpm":null, "run_meters_climbed":null, "missed_session":false, "key_session":false, "has_uploaded_training": false, "url":"https://trainxhale.com/session/4/", "direct_access_token":"a65249d688c78e0654a9d78726187c83" } ], [ { "id":5, "athlete":5, "date":"2014-01-10", "datetime_added":"2015-06-18T02:03:14.513292", "datetime_updated":"2015-06-18T02:03:14.513292", "session_plan_editable": true, "brief_description":"", "deleted": false, "discipline_id":4, "discipline_title":"Bike Intervals", "discipline_category":"bike", "intensity":5, "prescribed_minutes":70, "prescribed_minutes_swim":null, "prescribed_minutes_bike":null, "prescribed_minutes_run":null, "prescribed_km":1.5, "prescribed_km_swim":null, "prescribed_km_bike":null, "prescribed_km_run":null, "completed_minutes":70, "completed_minutes_swim":null, "completed_minutes_bike":null, "completed_minutes_run":null, "completed_km":1.5, "completed_km_swim":null, "completed_km_bike":null, "completed_km_run":null, "training_plan":"Lorem ipsum dolor sit amet.", "athlete_feedback":"Lorem ipsum dolor sit amet.", "coach_comments":"Lorem ipsum dolor sit amet." "bike_average_speed_kph":16.8, "bike_average_power_watts":260, "bike_average_cadence_rpm":88, "bike_average_heart_rate_bpm":162, "bike_meters_climbed": 1225, "run_average_heart_rate_bpm":166, "run_meters_climbed":null, "missed_session":false, "key_session":false, "has_uploaded_training": false, "url":"https://trainxhale.com/session/5/", "direct_access_token":"dc3656494250eed5c3644be8094f342c" } ]
Retrieve a session
Retreive a single training session
Example Request
curl -X GET https://trainxhale.com/api/sessions/63/ \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Example Response
{ "id":4, "athlete":5, "date":"2014-01-10", "datetime_added":"2015-06-18T02:03:14.513292", "datetime_updated":"2015-06-18T02:03:14.513292", "session_plan_editable": true, "deleted": false, "discipline_id":4, "discipline_title":"Bike Intervals", "discipline_category":"bike", "brief_description":"", "intensity":5, "prescribed_minutes":70, "prescribed_minutes_swim":null, "prescribed_minutes_bike":null, "prescribed_minutes_run":null, "prescribed_km":1.5, "prescribed_km_swim":null, "prescribed_km_bike":null, "prescribed_km_run":null, "completed_minutes":70, "completed_minutes_swim":null, "completed_minutes_bike":null, "completed_minutes_run":null, "completed_km":1.5, "completed_km_swim":null, "completed_km_bike":null, "completed_km_run":null, "training_plan":"Lorem ipsum dolor sit amet.", "athlete_feedback":"Lorem ipsum dolor sit amet.", "coach_comments":"Lorem ipsum dolor sit amet." "bike_average_speed_kph":16.8, "bike_average_power_watts":260, "bike_average_cadence_rpm":88, "bike_average_heart_rate_bpm":162, "bike_meters_climbed": 1225, "run_average_heart_rate_bpm":166, "run_meters_climbed": 1225, "missed_session":false, "has_uploaded_training":false, "key_session":false "url":"https://trainxhale.com/session/53/", "direct_access_token":"e2da0ec3f86f71f61a13964f698e9705" }
Create a session
Create a new training session
parameter | value type | example value | |
---|---|---|---|
date | ISO 8601 date string | 2015-06-17 | required field |
order | integer | 2 | The order value determines which order the training appears on a given day. If not set the order will automatically be set higher than any other session on this day. This means it should appear as the day's last session. |
discipline_id | integer | 24288 | required field. Session plan field. |
intensity | integer | 4 | An integer between 0 and 5 |
brief_description | string | Skiing | Relevant for diary and other training disciplines. Session plan field. |
session_plan_editable | boolean | True | Read only. Can session plan fields be edited? |
deleted | boolean | False | Read only. If true this session has been deleted and should be removed from local copies. |
key_session | boolean | False | Session plan field |
training_plan | string | Session plan field | |
prescribed_minutes | integer | Session plan field | |
prescribed_minutes_swim | integer | Session plan field | |
prescribed_minutes_bike | integer | Session plan field | |
prescribed_minutes_run | integer | Session plan field | |
prescribed_km | float | Session plan field | |
prescribed_km_swim | float | Session plan field | |
prescribed_km_bike | float | Session plan field | |
prescribed_km_run | float | Session plan field | |
training_log_files_to_add | list of integers | A list of training file IDs to add to this training session | |
direct_access_token | string | dc3656494250eed5c3644be8094f342c | A token that allows access to session charts page when logged out. E.g. https://trainxhale.com/session/5/?direct_access_token=dc3656494250eed5c3644be8094f342c |
Example Request
curl -X POST https://trainxhale.com/api/sessions/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' -d date='2015-01-14' -d intensity=3 -d discipline_id=6
Update a session
Update an existing training session
Use PATCH if you don't want to update required fields. Otherwise you can use PUT which will demand you resend the required fields.
Example Request
curl -X PATCH https://trainxhale.com/api/sessions/44/ \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' -d discipline_id=6
Delete a session
Successful deletion responds with 204 No Content
Example Request
curl -X DELETE https://trainxhale.com/api/sessions/44/ \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Races
List races
List all races for the current season for the authenticated user.
GET Parameters:
parameter | value type | example value |
---|---|---|
updated_since_datetime | ISO 8601 datetime string | 2015-06-17T03:00:00 |
start_date | ISO 8601 date string | 2015-06-17 |
end_date | ISO 8601 date string | 2016-06-16 |
Example Request
curl -X GET https://trainxhale.com/api/races/?updated_since_datetime=2015-06-17T03%3A00%3A00 \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Example Response
[ { "id":2, "athlete":5, "date":"2014-01-31", "deleted": false, "datetime_added":"2015-06-20T22:46:28.696444", "datetime_updated":"2015-06-20T22:47:18.129069", "race_name":"Triathlon", "distance":3, "taper_days":5, "attendance_probability":1, "athletes_plan": "Lorem", "coach_plan":"", "athlete_feedback":"Lorem", "coach_comments":"", "event_url":"http://example.com", "position_overall":15, "position_age_group":3, "race_priority":"b", "has_uploaded_training": false } ]
Retrieve a race
Retreive a single race
Example Request
curl -X GET https://trainxhale.com/api/races/2/ \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Example Response
{ "id":2, "athlete":5, "date":"2014-01-31", "deleted": false, "datetime_added":"2015-06-20T22:46:28.696444", "datetime_updated":"2015-06-20T22:47:18.129069", "race_name":"Triathlon", "distance":3, "taper_days":5, "attendance_probability":1, "athletes_plan": "Lorem", "coach_plan":"", "athlete_feedback":"Lorem", "coach_comments":"", "event_url":"http://example.com", "position_overall":15, "position_age_group":3, "race_priority":"b", "has_uploaded_training": false }
Create a race
Create a new race
date and race_name are required fields
Example Request
curl -X POST https://trainxhale.com/api/races/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' -d date='2015-01-14' -d race_name='Rubicon 70.3'
Update a race
Update an existing race
Use PATCH if you don't want to update required fields. Otherwise you can use PUT which will demand you resend the required fields.
Example Request
curl -X PATCH https://trainxhale.com/api/races/12/ \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' -d taper_days=5
Delete a race
Successful deletion responds with 204 No Content
Example Request
curl -X DELETE https://trainxhale.com/api/races/12/ \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Training files
Upload training files
Any file that can be uploaded manually to Xhale can also be accepted via the API. However, it is preferable to use FIT activity files and failing that TCX as these are the best supported.
To use this endpoint, you will need to authorise access with the 'upload' and 'write' scopes during the OAuth 2.0 flow.
Example Request
curl -X POST https://trainxhale.com/api/uploads/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' -F file=@/path/to/file.fit
Responses
If the file is created we will respond with status code 201. A status code of 200 means an identical file has already been uploaded. 415 is returned when we receive files we don't recognise the file type of. 403 means the user has not been authorised with the correct scopes (you need write+upload). 500 errors are a problem on our part. We should be automatically informed of these problems and work on a fix, but if you see a lot please contact us at our support@trainxhale.com email address.
Delete training file
Successful deletion responds with 204 No Content
Example Request
curl -X DELETE https://trainxhale.com/api/uploads/4332/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
List training files that need importing
Example Request
curl -X GET https://trainxhale.com/api/uploads/pending/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Add training files to training sessions or races
To add a training file to a session or a race, use the endpoints above for saving training sessions and races, and include the training_log_files_to_add field. The distance/time completed data will be updated in the training session so make sure to refresh this data after saving.
Example Request
curl -X PATCH https://trainxhale.com/api/sessions/44/ \ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' -d training_log_files_to_add=632
Planned workouts
Download planned workouts
Planned workouts are structured training plans which can be understood by devices such as a bike computer and can be used to control workout equipment such as a smart bike trainer.
List workouts
To obtain the file data for the planned workouts, first fetch a list of planned workouts to see what is available. You can then use this data to fetch the workouts themselves.
Due to limitations in what type of workouts the ZWO format supports, you should filter for that file type if that is the format you are downloading. Users need to have FTP set in their profile and it needs to be a cycling workout.
You can filter the list with the following parameters:
parameter | value type | example value |
---|---|---|
sport | string | cycling |
updated_since_datetime | ISO 8601 datetime string | 2015-06-17T03:00:00 |
scheduled_date_earliest | ISO 8601 date string | 2015-06-17 |
scheduled_date_latest | ISO 8601 date string | 2016-06-16 |
file_type | string | zwo |
Example Request
curl -X GET -G https://trainxhale.com/api/workouts/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' -d scheduled_date_earliest='2018-08-17' -d scheduled_date_latest='2018-09-30' -d sport='cycling' -d updated_since_datetime='2018-09-01T12:12:00'
Example Response
[ { "workout_id":328, "sport":"cycling", "last_updated_datetime":"2018-09-02T10:11:27.623172", "training_sessions":[ { "id":8923323, "date":"2120-07-11", "name":"Bike Endurance" } ], } ]
Download workout
Workout file data is either FIT or ZWO file formats (ask if you are interested in ERG). To obtain the file, you will need the workout_id and the training session it is attached to. Use this to construct the URL /api/sessions/{training_session_id}/workouts/{workout_id}.fit (or .zwo) and perform a GET request for the data.
Example Request
curl -X GET https://trainxhale.com/api/sessions/8923323/workouts/328.fit -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' --output workout328.fit
Messaging
Send private messages between coach and athletes
Messaging allows athletes and coaches to chat with one another.
List contacts
Get a list of people that are available to contact over the app. For coaches this will be a list of athletes and for athletes this will be their coach if they have one.
Example Request
curl -X GET -G https://trainxhale.com/api/contacts/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Example Response
{ "id": 3225, "first_name": "Jack", "last_name": "White", "unseen_messages_count": 5 }
List messages for contact
List all messages between user and contact with this ID.
Example Request
curl -X GET -G https://trainxhale.com/api/contacts/3/messages/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Example Response
{ "id": 3225, "content": "The contents of the message" "sender_user_id": 3242, "recipient_user_id": 5222, "datetime_sent":"2020-06-18T02:03:14.513292", "datetime_updated":"2020-06-19T09:04:14.523192", "datetime_seen":"2020-06-18T11:14:13.523299", }
Get message
Example Request
curl -X GET -G https://trainxhale.com/api/contacts/3/messages/17/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf'
Send a new message
Example Request
curl -X GET -G https://trainxhale.com/api/contacts/3/messages/ -H 'Authorization: Bearer db015b7280da9ebc7c0c4fc48a5d6a2f14780ecf' -d content='the content of the message'