Introduction
Welcome to the Wahoo Fitness OAuth2 API! You can use our API to access Wahoo Fitness OAuth2 API endpoints, which can get information on your user profile and workout history stored in our cloud.
We have language bindings in Shell! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
Data Model
This diagram shows how the data records are related within the API
Registration
Create a user account and register your app in our developer portal (https://developers.wahooligan.com). Your app can be set to 'Sandbox' or 'Production'. With 'Sandbox' apps you will be able to test and see your changes immediately but with very limited throughput. Production apps will have to go through a review process with Wahoo Fitness, and when approved your app can be released with a higher rate limit.
Rate Limiting
Rate limits and usage are included within each HTTP response header
X-RateLimit-Limit: <limit_day>, <limit_hour>, <limit_5min>
X-RateLimit-Remaining: <remaining_day>, <remaining_hour>, <remaining_5min>
X-RateLimit-Reset: <seconds_until_reset>
Sample header values for a successful response:
X-RateLimit-Limit: 5000, 1000, 200
X-RateLimit-Remaining: 4999, 999, 199
X-RateLimit-Reset: 0
Sample header values for a rate limited response:
X-RateLimit-Limit: 5000, 1000, 200
X-RateLimit-Remaining: 4800, 800, 0
X-RateLimit-Reset: 300
The following chart shows how your app will be rate limited. If you require a higher throughput, please contact support to request an increase.
Interval | Sandbox Apps | Production Apps |
---|---|---|
Requests every 5 Min: | 25 | 200 |
Requests per Hour: | 100 | 1000 |
Requests per Day: | 250 | 5000 |
Authentication
Workflow
OAuth2 Uses the following authentication workflow. The goal is to obtain an access_token for a user that can be used for accessing Wahoo's API on the user's behalf.
The Wahoo API does allow users to use the PKCE flow for authorization. If you would like to use the PKCE flow for your application please go to My Developer Apps -> select edit on your app and then select 'Yes' under the question asking if you would like to use PKCE for your application. If you would like to learn more about the PKCE flow please visit their documentation https://www.oauth.com/oauth2-servers/pkce/
Prior to starting the OAuth2 workflow please make sure the application has been created here(https://developers.wahooligan.com/applications) in order to obtain the client id and client secret.
Step 1. Send the user to Wahoo in order to login and grant access to your app using the following url:
https://<base_url>/oauth/authorize?client_id=<client_id>&redirect_uri=<redirect_uri>&scope=<scopes>&response_type=code
Step 2. After successful authorization the user will be redirected back to your redirect_uri with a code.
<redirect_uri>?code=<code>
Step 3. Send an HTTP POST to Wahoo with the code and your app's OAuth2 credentials and receive the access_token and refresh_token
https://<base_url>/oauth/token?client_secret=<client_secret>&code=<code>&redirect_uri=<redirect_uri>&grant_type=authorization_code&client_id=<client_id>
Step 4. When the access_token expires after 2 hours you can use the refresh_token to get a new access_token and a new refresh_token
https://<base_url>/oauth/token?client_secret=<client_secret>&client_id=<client_id>&grant_type=refresh_token&refresh_token=<refresh_token>
Step 5. You are now ready to send requests to our API by putting the new access_token within the following HTTP Header:
"Authorization": "Bearer <access_token>"
Attribute | Notes |
---|---|
base_url: | api.wahooligan.com |
client_id: | You can get your app's client_id from the developer portal. |
client_secret: | You can get your app's client_secret from the developer portal. |
redirect_uri: | You can set the redirect_uri for your app in the developer portal. |
scopes: | See Authorization Scopes |
access_token: | Returned in Step 3; Used for API calls to view/manage user data. |
refresh_token: | Returned in Step 3; Used to refresh the access_token. |
expires_in: | Returned in Step 3; Indicates when the access_token will expire. |
code_challenge: | Required for PKCE in Step 1; A SHA256 hash value for the code verifier, must be Base64 encoded |
code_verifier: | Required for PKCE in Step 3; The original code verifier for the PKCE request |
Our API returns strings for decimal data types in our responses. This is because our API uses JSON for responses and requests. Please be sure to use headers for Content-Type as application/JSON:
Content-Type: application/json
Authorization
# With shell, you can append the requested scopes as a space separated list of values
curl "<base_url>/oauth/authorize?scope=user_read%20user_write"
-H "Authorization: Bearer <Token>"
Applications must only request permission for resources they intend to access or modify. You can choose which permission scopes your app will request either by setting the scopes for your app in the developer portal or by sending a space separated list of scopes as a parameter in the oauth/authorize
request.
We support the following OAuth 2.0 permission scopes:
Scope | Description |
---|---|
Access your email address | |
user_read | Access your user data |
user_write | Update your user data |
workouts_read | Access your workout history |
workouts_write | Update your workout history |
offline_data | Receive data even when the app is closed |
Please note: If the user_read
scope is not included the API will return a 403 response.
Deauthorize
# With shell, you can revoke access to an application
curl -X "DELETE" "<base_url>/v1/permissions"
-H "Authorization: Bearer <Token>"
Application access can be revoked by sending a request to delete all permissions.
HTTP Request
DELETE https://api.wahooligan.com/v1/permissions
Plans
Plan records hold information pertaining to the structure of a workout that can be played on Wahoo devices and applications. A plan record includes a file which holds details about the intervals and targets to be performed during a workout.
For Information regarding how to build your plan file see Plan Files.
Wahoo uses a library data model approach for planned workouts. A user should only have a single copy of a plan that can then be referenced by multiple workout instances. As a result creating a planned workout is a two-step process:
- Create a plan record to place the plan in the user's library and receive a plan id.
- Create (or update) a workout record with a reference to the plan id.
It is best practice to use the external_id and provider_updated_at fields to prevent duplicate records and ensure only a single copy of a plan is uploaded to a user's library.
Plan Files
The plan file contains a single JSON object with the following sections:
- Header
- Intervals
Detailed information regarding the structure of the plan file can be found in the link below.
Instructions for creating a plan file
Create a Plan
curl --header "Authorization: Bearer users-token-goes-here" -X POST
-d 'plan[file]=data:application/json;base64,<base64-encoded-plan-file>&
plan[filename]=plan.json&
plan[external_id]=P0001&
plan[provider_updated_at]=2023-01-01T12:00:00.000Z' https://api.wahooligan.com/v1/plans
Sample Response:
{
"id": 5,
"user_id": 4,
"name": "Special Plan",
"description": "Warmup for 10 minutes, FTP ladder up, cool down for 5 minutes",
"file": {
"url": "https://cdn.wahooligan.com/wahoo-cloud/production/uploads/plan/file/RGpT2JYKbmHzqRu2WFHHvg/plan.json"
},
"workout_type_family_id": 0,
"workout_type_location_id": 255,
"external_id": "P0001",
"provider_updated_at": "2023-01-01T12:00:00.000Z",
"deleted": false,
"updated_at": "2023-12-19T22:26:36.000Z",
"created_at": "2023-12-19T22:26:36.000Z"
}
Requires the plans_write
scope
Creates a plan for the authenticated user.
HTTP Request
POST https://api.wahooligan.com/v1/plans
Parameters
Parameter | Type | Required | Description |
---|---|---|---|
plan[file] | File | yes | Base64 encoded JSON file |
plan[filename] | String | no | The name of the plan file |
plan[external_id] | String | yes | Unique external Id of the plan |
plan[provider_updated_at] | Date | yes | External date/time the file was updated externally |
Get a Plan
curl --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/plans/5
Sample Response:
{
"id": 5,
"user_id": 4,
"name": "Special Plan",
"description": "Warmup for 10 minutes, FTP ladder up, cool down for 5 minutes",
"file": {
"url": "https://cdn.wahooligan.com/wahoo-cloud/production/uploads/plan/file/RGpT2JYKbmHzqRu2WFHHvg/plan.json"
},
"workout_type_family_id": 0,
"workout_type_location_id": 255,
"external_id": "P0001",
"provider_updated_at": "2023-01-01T12:00:00.000Z",
"deleted": false,
"updated_at": "2023-12-19T22:26:36.000Z",
"created_at": "2023-12-19T22:26:36.000Z"
}
Requires the plans_read
scope
Returns a plan from the library of the authenticated user.
HTTP Request
GET https://api.wahooligan.com/v1/plans/:id
Update a Plan
curl --header "Authorization: Bearer users-token-goes-here" -X PUT
-d 'plan[file]=data:application/json;base64,<base64-encoded-plan-file>&
plan[filename]=plan.json&
plan[provider_updated_at]=2023-01-04T12:00:00.000Z' https://api.wahooligan.com/v1/plans/5
Sample Response:
{
"id": 5,
"user_id": 4,
"name": "Special Plan",
"description": "Warmup for 10 minutes, FTP ladder up, cool down for 5 minutes",
"file": {
"url": "https://cdn.wahooligan.com/wahoo-cloud/production/uploads/plan/file/RGpT2JYKbmHzqRu2WFHHvg/plan.json"
},
"workout_type_family_id": 0,
"workout_type_location_id": 255,
"external_id": "P0001",
"provider_updated_at": "2023-01-04T12:00:00.000Z",
"deleted": false,
"updated_at": "2023-12-19T22:26:36.000Z",
"created_at": "2024-01-05T05:18:21.000Z"
}
Requires the plans_write
scope
Updates a plan that is in the library of the authenticated user.
HTTP Request
PUT https://api.wahooligan.com/v1/plans/:id
Query Parameters
Parameter | Type | Required | Description |
---|---|---|---|
plan[file] | File | yes | Base64 encoded JSON file |
plan[filename] | String | no | The name of the plan file |
plan[provider_updated_at] | Date | yes | External date/time the file was updated externally |
Delete a Plan
curl -X DELETE --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/plans/5
Requires the plans_write
scope
Deletes a plan that is in the library of the authenticated user.
HTTP Request
DELETE https://api.wahooligan.com/v1/plans/:id
Power Zones
Create a Power Zone
curl --header "Authorization: Bearer users-token-goes-here" -X POST
-d 'power_zone[zone_1]=100
power_zone[zone_2]=120&
power_zone[zone_3]=120&
power_zone[zone_4]=120&
power_zone[zone_5]=120&
power_zone[zone_6]=120&
power_zone[zone_7]=120&
power_zone[ftp]=400&
power_zone[zone_count]=8&
power_zone[workout_type_id]=10&
power_zone[workout_type_family_id]=6&
power_zone[workout_type_location_id]=8&
power_zone[critical_power]=324' https://api.wahooligan.com/v1/power_zones
Sample Response:
{
"id": 1,
"user_id": 1,
"zone_1": 100,
"zone_2": 120,
"zone_3": 140,
"zone_4": 150,
"zone_5": 200,
"zone_6": 300,
"zone_7": 400,
"ftp": 400,
"zone_count": 8,
"workout_type_id": 10,
"workout_type_family_id": 6,
"workout_type_location_id": 8,
"critical_power": 324,
"originator_type": 0,
"fitness_app_id": 6,
"created_at": "2016-01-27T16:18:53.927Z",
"updated_at": "2016-01-27T16:18:53.927Z"
}
Requires the power_zones_write
scope
Creates a power zone for the authenticated user.
HTTP Request
POST https://api.wahooligan.com/v1/power_zones
Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
power_zone[zone_1] | Number | no | Power Zone Value | |
power_zone[zone_2] | Number | no | Power Zone Value | |
power_zone[zone_3] | Number | no | Power Zone Value | |
power_zone[zone_4] | Number | no | Power Zone Value | |
power_zone[zone_5] | Number | no | Power Zone Value | |
power_zone[zone_6] | Number | no | Power Zone Value | |
power_zone[zone_7] | Number | no | Power Zone Value | |
power_zone[zone_count] | Number | no | Power Zone Total Count | |
power_zone[ftp] | Number | no | Functional Threshold Power | |
power_zone[critical_power] | Number | no | MMP/Best average power | |
power_zone[workout_type_id] | Number | no | ID of the Workout Type | |
power_zone[workout_type_family_id] | Number | no | ID of the Workout Type | |
power_zone[workout_type_location_id] | Number | no | ID of the Workout Type |
Get a Power Zone
curl --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/power_zones/56519
Sample Response:
{
"id": 56519,
"user_id": 1,
"zone_1": 100,
"zone_2": 120,
"zone_3": 140,
"zone_4": 150,
"zone_5": 200,
"zone_6": 300,
"zone_7": 400,
"ftp": 400,
"zone_count": 8,
"workout_type_id": 10,
"workout_type_family_id": 6,
"workout_type_location_id": 8,
"critical_power": 324,
"originator_type": 0,
"fitness_app_id": 6,
"created_at": "2016-01-27T16:18:53.927Z",
"updated_at": "2016-01-27T16:18:53.927Z"
}
Requires the power_zones_read
scope
Returns a power zone for the current authenticated user.
HTTP Request
GET https://api.wahooligan.com/v1/power_zones/:id
Update a Power Zone
curl --header "Authorization: Bearer users-token-goes-here" -X PUT
-d power_zone[ftp]=300 https://api.wahooligan.com/v1/power_zones/56519
Sample Response:
{
"id": 56519,
"user_id": 1,
"zone_1": 100,
"zone_2": 120,
"zone_3": 140,
"zone_4": 150,
"zone_5": 200,
"zone_6": 300,
"zone_7": 400,
"ftp": 300,
"zone_count": 8,
"workout_type_id": 10,
"workout_type_family_id": 6,
"workout_type_location_id": 8,
"critical_power": 324,
"originator_type": 0,
"fitness_app_id": 6,
"created_at": "2016-01-27T16:18:53.927Z",
"updated_at": "2016-01-27T16:18:53.927Z"
}
Requires the power_zones_write
scope
Updates a power zone for the authenticated user.
HTTP Request
POST https://api.wahooligan.com/v1/power_zones
Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
power_zone[zone_1] | Number | no | Power Zone Value | |
power_zone[zone_2] | Number | no | Power Zone Value | |
power_zone[zone_3] | Number | no | Power Zone Value | |
power_zone[zone_4] | Number | no | Power Zone Value | |
power_zone[zone_5] | Number | no | Power Zone Value | |
power_zone[zone_6] | Number | no | Power Zone Value | |
power_zone[zone_7] | Number | no | Power Zone Value | |
power_zone[zone_count] | Number | no | Power Zone Total Count | |
power_zone[ftp] | Number | no | Functional Threshold Power | |
power_zone[critical_power] | Number | no | Critical Power | |
power_zone[workout_type_id] | Number | no | ID of the Workout Type | |
power_zone[workout_type_location_id] | Number | no | ID of the Workout Type Location | |
power_zone[workout_type_family_id] | Number | no | ID of the Workout Type Family |
Get Power Zones
curl --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/power_zones
Sample Response:
{
"power_zones":
[
{
"id": 1,
"user_id": 1,
"zone_1": 100,
"zone_2": 120,
"zone_3": 140,
"zone_4": 150,
"zone_5": 200,
"zone_6": 300,
"zone_7": 400,
"ftp": 400,
"zone_count": 8,
"workout_type_id": 10,
"workout_type_family_id": 6,
"workout_type_location_id": 8,
"critical_power": 324,
"originator_type": 0,
"fitness_app_id": 6,
"created_at": "2016-01-27T16:18:53.927Z",
"updated_at": "2016-01-27T16:18:53.927Z"
}
]
}
Requires the power_zones_read
scope
Returns the power zones for the authenticated user.
HTTP Request
GET https://api.wahooligan.com/v1/power_zones
Delete a Power Zone
curl -X DELETE --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/power_zones/:id
Requires the power_zones_write
scope
Deletes a power zone that is owned by the authenticated user.
HTTP Request
DELETE https://api.wahooligan.com/v1/power_zones/:id
Users
Applications can get and update the attributes of the authenticated user.
Get Authenticated User
curl --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/user
Sample Response:
{
"id": 60462,
"height": "2.0",
"weight": "80.0",
"first": "Bob",
"last": "Smith",
"email": "sample@test-domain.com",
"birth": "1980-10-02",
"gender": 1,
"created_at": "2018-10-23T15:38:23.000Z",
"updated_at": "2018-10-24T20:46:40.000Z"
}
Requires user_read
scope
Returns the authenticated user along with email if email scope is included.
HTTP Request
GET https://api.wahooligan.com/v1/user
Update User
curl --header "Authorization: Bearer users-token-goes-here"
-X PUT -d user[gender]=1 https://api.wahooligan.com/v1/user
Sample Response:
{
"id": 60462,
"height": "2.0",
"weight": "80.0",
"first": "Bob",
"last": "Smith",
"email": "bob.s@wahoofitness.com",
"birth": "1980-10-02",
"gender": 1,
"created_at": "2018-10-23T15:38:23.000Z",
"updated_at": "2018-10-24T20:46:40.000Z"
}
Requires the user_write
scope
Updates the current authenticated user.
HTTP Request
PUT https://api.wahooligan.com/v1/user
Parameters
Parameter | Type | Required | Description |
---|---|---|---|
user[email] | String | no | Well formed email address, must be unique in the system |
user[first] | String | no | First name |
user[last] | String | no | Last name |
user[height] | Decimal | no | Height in meters |
user[weight] | Decimal | no | Weight in kilograms |
user[birth ] | Date | no | Date of birth formatted as YYYY-MM-DD |
user[gender] | 0,1,2,3 | no | Use 0 for male, 1 for female, 2 for other, and 3 for prefer not to say |
Workouts
A workout record holds information about a single workout event. A workout becomes a structured workout when it includes an association to a plan.
What is a daycode?
Daycodes can be used to specify a specific date a user would like a workout on without having to also tie the workout to a start time. A daycode is an integer that is calculated based on how many days it has been since January 1st 2020 (daycode of 1), for example 1/1/2021 would have a daycode of 366 becuase 2020 was a leap year, and 09/12/2024 would have a daycode of 1716.
Create a Workout
curl --header "Authorization: Bearer users-token-goes-here" -X POST
-d 'workout[name]="Friday fun"&
workout[workout_token]=123&
workout[workout_type_id]=40&
workout[starts]=2015-08-12T09:00:00.000Z&
workout[minutes]=12' https://api.wahooligan.com/v1/workouts
Sample Response:
{
"id": 56519,
"starts": "2015-08-12T09:00:00.000Z",
"minutes": 12,
"name": "Friday Fun",
"created_at": "2018-10-23T20:41:55.000Z",
"updated_at": "2018-10-23T20:41:55.000Z",
"plan_id": null,
"workout_token": "123",
"workout_type_id": 40
}
Requires the workouts_write
scope
Creates a workout for the authenticated user.
If you would like to create a planned structured workout please make sure to create a plan file that can be attached to the workout. Documentation for creating a plan file can be found under the Plans tab.
HTTP Request
POST https://api.wahooligan.com/v1/workouts
Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
workout[name] | String | yes | The name of the workout | |
workout[workout_type_id] | Number | yes | The type of the workout - Workout Types | |
workout[starts] | Time | yes | Start time | |
workout[minutes] | Number | yes | Duration of the workout in minutes | |
workout[workout_token] | String | no | Can be used by the application to identify the workout | |
workout[plan_id] | Number | no | null | Id of the plan used in this workout |
workout[day_code] | Number | no | null | The number of days since 1/1/2020 |
workout[workout_summary] | Object | no | Include summary results - Workout Summary |
Get a Workout
curl --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/workouts/56519
Sample Response:
{
"id": 56519,
"starts": "2015-08-12T09:00:00.000Z",
"minutes": 12,
"name": "Friday Fun",
"plan_id": null,
"workout_token": "123",
"workout_type_id": 40,
"workout_summary": null,
"created_at": "2018-10-23T20:41:55.000Z",
"updated_at": "2018-10-23T20:41:55.000Z"
}
Requires the workouts_read
scope
Returns a workout for the current authenticated user.
HTTP Request
GET https://api.wahooligan.com/v1/workouts/:id
Update a Workout
curl --header "Authorization: Bearer users-token-goes-here" -X PUT
-d workout[name]="Friday afternoon" https://api.wahooligan.com/v1/workouts/56519
Sample Response:
{
"id": 56519,
"starts": "2015-08-12T09:00:00.000Z",
"minutes": 12,
"name": "Friday afternoon",
"plan_id": null,
"workout_token": "123",
"workout_type_id": 40,
"workout_summary": null,
"created_at": "2018-10-23T20:41:55.000Z",
"updated_at": "2018-10-23T20:41:55.000Z"
}
Requires the workouts_write
scope
Updates a workout for the authenticated user.
HTTP Request
PUT https://api.wahooligan.com/v1/workouts/:id
Query Parameters
Parameter | Type | Required | Description |
---|---|---|---|
workout[name] | String | no | The name of the workout |
workout[workout_token] | String | no | Can be used by the application to identify the workout |
workout[starts] | Time | no | Start time |
workout[minutes] | Number | no | Duration of the workout in minutes |
workout[plan_id] | Number | no | Id of the plan used in this workout |
workout[workout_type_id] | Number | no | The type of the workout - Workout Types |
workout[day_code ] | Number | no | The number of days since 1/1/2020 |
workout[workout_summary] | Object | no | Include summary results - Workout Summary |
Get all Workouts
curl --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/workouts
Sample Response:
{
"workouts": [
{
"id": 56519,
"starts": "2015-08-12T09:00:00.000Z",
"minutes": 12,
"name": "Friday afternoon",
"plan_id": null,
"workout_token": "123",
"workout_type_id": 40,
"workout_summary": null,
"created_at": "2018-10-23T20:41:55.000Z",
"updated_at": "2018-10-23T20:41:55.000Z"
}
],
"total": 1,
"page": 1,
"per_page": 30,
"order": "descending",
"sort": "starts"
}
Requires the workouts_read
scope
Returns all workouts for the authenticated user. The workout are always sorted by the starts field in descending order. By default the most recent 30 workouts are returned. The per_page parameter can be used to adjust the number of workouts returned.
In the response the total attribute is the total number of workouts for the current user.
HTTP Request
GET https://api.wahooligan.com/v1/workouts
Query Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
page | integer | no | 1 | Used for pagination. |
per_page | integer | no | 30 | Limits the number of workouts returned. |
Delete a Workout
curl -X DELETE --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/workouts/:id
Requires the workouts_write
scope
Deletes a workout that is owned by the authenticated user.
HTTP Request
DELETE https://api.wahooligan.com/v1/workouts/:id
Workout File Uploads
Create a Workout File Upload
curl --header "Authorization: Bearer users-token-goes-here" -X POST
-d 'workout_file_upload[file]="data:application/vnd.fit;base64,RmFrZSBmaXQgZmlsZQ=="&
workout_file_upload[filename]="workout_results.fit"&
workout_file_upload[time_zone]="America/New_York"' https://api.wahooligan.com/v1/workout_file_uploads
Sample Response:
{
"id": 56519,
"starts": "2015-08-12T09:00:00.000Z",
"minutes": 12,
"name": "Friday Fun",
"created_at": "2018-10-23T20:41:55.000Z",
"updated_at": "2018-10-23T20:41:55.000Z",
"plan_id": null,
"workout_type_id": 40
}
Requires the workouts_write
scope
Send the results of a workout to Wahoo for processing. This endpoint will attempt to process the uploaded FIT file and generate the correct workout and workout summary objects. If a workout object has already been created it is recommended to specify the target_workout_id
within the request to ensure that the workout summary is associated with the correct workout.
This endpoint will return a workout_file_upload
object that will contain the current status of the upload.
HTTP Request
POST https://api.wahooligan.com/v1/workout_file_uploads
Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
workout_file_upload[file] | File | yes | Base64 encoded FIT File | |
workout_file_upload[filename] | String | no | The name of the workout file | |
workout_file_upload[time_zone] | String | no | The time zone where the FIT file was recorded | |
workout_file_upload[workout_name] | String | no | Name to use for the workout summary | |
workout_file_upload[target_workout_id] | Number | no | Wahoo Id of the workout this file should be associated with |
Get a Workout File Upload
curl --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/workout_file_uploads/:token
Sample Response:
{
"id": 5,
"user_id": 1,
"token": "fRa2HvZ1N0WxuHw",
"status": "pending",
"time_zone": null,
"workout_id": null,
"workout_summary_id": null,
"workout_file_id": null,
"workout_name": null,
"error": null,
"target_workout_id": null,
"created_at": "2018-10-23T20:43:50.000Z",
"updated_at": "2018-10-23T20:43:50.000Z"
}
Requires the workouts_write
scope
Returns the workout file upload object with the corresponding token. Since the processing of a Workout File Upload is asynchronous it may take a few seconds to a few hours before the upload has been processed. On average Workout File Uploads are processed in less than 5 seconds.
When the status is complete
the file has completed processing and the workout_id
and workout_summary_id
fields will be populated with values that can be used to fetch those objects from the workouts and workout_summary endpoints.
When the status is error
the error
attribute will contain additional information regarding the failure of the upload.
HTTP Request
GET https://api.wahooligan.com/v1/workout_file_uploads/:token
Upload Status
Status | Description |
---|---|
pending | The file is waiting to be processed |
in_progress | The file is currently being processed and should complete within 1-5 seconds |
complete | The file has successfully been processed |
error | There was an error processing the file |
duplicate | The uploaded file exactly matches a previously uploaded file |
Workout Summaries
Workout Summary records contain the results of a workout.
How to download a file
The Workout Summary show endpoint will provide the url for the workout fit file. If you would like to download the fit file please copy the url, then paste it into your browser or make a GET call to download the fit ile.
Create a Workout Summary
curl --header "Authorization: Bearer users-token-goes-here" -X POST
-d workout_summary[power_avg]="240.52" https://api.wahooligan.com/v1/workouts/56519/workout_summary
Sample Response:
{
"id": 8297,
"ascent_accum": "450.00",
"cadence_avg": "50.00",
"calories_accum": "1500.00",
"distance_accum": "24909.71",
"duration_active_accum": "179.00",
"duration_paused_accum": "95.00",
"duration_total_accum": "275.24",
"heart_rate_avg": "124.54",
"power_bike_np_last": "150.00",
"power_bike_tss_last": "304.90",
"power_avg": "94.59",
"speed_avg": "10.75",
"work_accum": "1041480.00",
"created_at": "2018-10-23T20:43:50.000Z",
"updated_at": "2018-10-23T20:43:50.000Z",
"file": {
"url": "https://server.com/4_Mile_Segment_.fit"
}
}
Requires the workouts_write
scope
Creates a workout summary and associates it with a workout. If a workout summary already exists for the workout then the workout summary is updated.
HTTP Request
POST https://api.wahooligan.com/v1/workouts/:id/workout_summary
Parameters
Parameter | Type | Description |
---|---|---|
workout_summary[ascent_accum] | decimal | Ascent in meters |
workout_summary[cadence_avg] | decimal | Average rotations per minute |
workout_summary[calories_accum] | decimal | Calories (kCal) |
workout_summary[distance_accum] | decimal | Meters |
workout_summary[duration_active_accum] | decimal | Seconds |
workout_summary[duration_paused_accum] | decimal | Seconds |
workout_summary[duration_total_accum] | decimal | Seconds |
workout_summary[heart_rate_avg] | decimal | bpm |
workout_summary[power_avg] | decimal | Watts |
workout_summary[power_bike_np_last] | decimal | Watts |
workout_summary[power_bike_tss_last] | decimal | unitless |
workout_summary[speed_avg] | decimal | Meters/Sec |
workout_summary[work_accum] | decimal | joules |
workout_summary[file] | File | Fit file |
Get a Workout Summary
Sample Response:
{
"id": 8297,
"ascent_accum": "450.00",
"cadence_avg": "50.00",
"calories_accum": "1500.00",
"distance_accum": "24909.71",
"duration_active_accum": "179.00",
"duration_paused_accum": "95.25",
"duration_total_accum": "275.00",
"heart_rate_avg": "100.00",
"power_bike_np_last": "150.00",
"power_bike_tss_last": "304.90",
"power_avg": "94.59",
"speed_avg": "10.75",
"work_accum": "1041480.00",
"time_zone": "America/Denver",
"file": {
"url": "https://server.com/4_Mile_Segment_.fit"
},
"created_at": "2018-10-23T20:43:50.000Z",
"updated_at": "2018-10-23T20:43:50.000Z"
}
Requires the workouts_read
scope
Returns the workout summary object for a workout. When a workout is created, the workout summary will be empty until it is updated.
curl --header "Authorization: Bearer users-token-goes-here" https://api.wahooligan.com/v1/workouts/:id/workout_summary
HTTP Request
GET https://api.wahooligan.com/v1/workouts/:id/workout_summary
Webhooks
Receive API calls from Wahoo to your webhook url.
Please make sure the offline_data
scope is added to receive webhooks.
If we do not receive an HTTP 200 response code we will retry the api call on the following retry schedule:
- After 30 minutes
- After 4 hours
- After 24 hours
- After 72 hours
API Calls will be sent via HTTP POST with the HTTP header Content-Type: application/json
It is possible for duplicate webhooks to be made when files are updated or deleted.
Settings
Setting | Notes |
---|---|
webhook_enabled: | Toggle the webhook api calls on/off. |
webhook_url: | Receive an HTTP POST with a JSON payload to this url. |
webhook_token: | Specify a token that you would like us to send. Any request that doesn't include this token should be ignored. |
Workout Summary
Requires the offline_data
scope
Sample Workout Summary Webhook Message
{
"event_type": "workout_summary",
"webhook_token": <webhook_token>,
"user": {
"id": 60462
},
"workout_summary": {
"id": 8297,
"ascent_accum": "450.00",
"cadence_avg": "52.00",
"calories_accum": "1500.00",
"distance_accum": "24909.71",
"duration_active_accum": "179.00",
"duration_paused_accum": "85.00",
"duration_total_accum": "275.20",
"heart_rate_avg": "124.23",
"power_bike_np_last": "150.01",
"power_bike_tss_last": "304.90",
"power_avg": "94.59",
"speed_avg": "10.75",
"work_accum": "104148000.01",
"created_at": "2018-10-23T20:43:50.000Z",
"updated_at": "2018-10-23T20:43:50.000Z",
"file": {
"url": "https://server.com/4_Mile_Segment_.fit"
},
"workout": {
"id": 56519,
"starts": "2015-08-12T09:00:00.000Z",
"minutes": 12,
"name": "Friday Fun",
"created_at": "2018-10-23T20:41:55.000Z",
"updated_at": "2018-10-23T20:41:55.000Z",
"plan_id": null,
"workout_token": "123",
"workout_type_id": 40
}
}
}
Workout Types
The Wahoo Fitness API supports the following workout locations, families and types:
Workout Types:
Id | Description | Location | Family |
---|---|---|---|
0 | BIKING | OUTDOOR | BIKING |
1 | RUNNING | OUTDOOR | RUNNING |
2 | FE | INDOOR | N/A |
3 | RUNNING_TRACK | OUTDOOR | TRACK |
4 | RUNNING_TRAIL | OUTDOOR | TRAIL |
5 | RUNNING_TREADMILL | INDOOR | RUNNING |
6 | WALKING | OUTDOOR | WALKING |
7 | WALKING_SPEED | OUTDOOR | WALKING |
8 | WALKING_NORDIC | OUTDOOR | WALKING |
9 | HIKING | OUTDOOR | WALKING |
10 | MOUNTAINEERING | OUTDOOR | WALKING |
11 | BIKING_CYCLECROSS | OUTDOOR | BIKING |
12 | BIKING_INDOOR | INDOOR | BIKING |
13 | BIKING_MOUNTAIN | OUTDOOR | BIKING |
14 | BIKING_RECUMBENT | OUTDOOR | BIKING |
15 | BIKING_ROAD | OUTDOOR | BIKING |
16 | BIKING_TRACK | OUTDOOR | BIKING |
17 | BIKING_MOTOCYCLING | OUTDOOR | BIKING |
18 | FE_GENERAL | INDOOR | N/A |
19 | FE_TREADMILL | INDOOR | N/A |
20 | FE_ELLIPTICAL | INDOOR | GYM |
21 | FE_BIKE | INDOOR | N/A |
22 | FE_ROWER | INDOOR | GYM |
23 | FE_CLIMBER | INDOOR | N/A |
25 | SWIMMING_LAP | INDOOR | SWIMMING |
26 | SWIMMING_OPEN_WATER | OUTDOOR | SWIMMING |
27 | SNOWBOARDING | OUTDOOR | SNOW_SPORT |
28 | SKIING | OUTDOOR | SNOW_SPORT |
29 | SKIING_DOWNHILL | OUTDOOR | SNOW_SPORT |
30 | SKIINGCROSS_COUNTRY | OUTDOOR | SNOW_SPORT |
31 | SKATING | OUTDOOR | SKATING |
32 | SKATING_ICE | INDOOR | SKATING |
33 | SKATING_INLINE | INDOOR | SKATING |
34 | LONG_BOARDING | OUTDOOR | SKATING |
35 | SAILING | OUTDOOR | WATER_SPORTS |
36 | WINDSURFING | OUTDOOR | WATER_SPORTS |
37 | CANOEING | OUTDOOR | WATER_SPORTS |
38 | KAYAKING | OUTDOOR | WATER_SPORTS |
39 | ROWING | OUTDOOR | WATER_SPORTS |
40 | KITEBOARDING | OUTDOOR | WATER_SPORTS |
41 | STAND_UP_PADDLE_BOARD | OUTDOOR | WATER_SPORTS |
42 | WORKOUT | INDOOR | GYM |
43 | CARDIO_CLASS | INDOOR | GYM |
44 | STAIR_CLIMBER | INDOOR | GYM |
45 | WHEELCHAIR | OUTDOOR | OTHER |
46 | GOLFING | OUTDOOR | OTHER |
47 | OTHER | OUTDOOR | OTHER |
49 | BIKING_INDOOR_CYCLING_CLASS | INDOOR | BIKING |
56 | WALKING_TREADMILL | INDOOR | WALKING |
61 | BIKING_INDOOR_TRAINER | INDOOR | BIKING |
62 | MULTISPORT | OUTDOOR | N/A |
63 | TRANSITION | OUTDOOR | N/A |
64 | EBIKING | OUTDOOR | BIKING |
65 | TICKR_OFFLINE | OUTDOOR | N/A |
66 | YOGA | INDOOR | GYM |
67 | RUNNING_RACE | OUTDOOR | RUNNING |
68 | BIKING_INDOOR_VIRTUAL | INDOOR | BIKING |
69 | MENTAL_STRENGTH | INDOOR | OTHER |
70 | HANDCYCLING | OUTDOOR | BIKING |
71 | RUNNING_INDOOR_VIRTUAL | INDOOR | RUNNING |
255 | UNKNOWN |
Workout Type Locations:
Id | Description |
---|---|
0 | INDOOR |
1 | OUTDOOR |
255 | UNKNOWN |
Workout Type Families:
Id | Description |
---|---|
0 | BIKING |
1 | RUNNING |
2 | SWIMMING |
3 | WATER SPORTS |
4 | SNOW SPORTS |
5 | SKATING |
6 | GYM |
9 | WALKING |
30 | N/A |
31 | OTHER |
255 | UNKNOWN |
Errors
The Wahoo Fitness API uses the following error codes:
Code | Description |
---|---|
400 | Bad Request -- Your request is invalid. |
401 | Unauthorized -- Your API key is wrong. |
403 | Forbidden -- You do not have access to the specified resource. |
404 | Not Found -- The specified resource could not be found. |
405 | Method Not Allowed -- You tried to access a resource with an invalid method. |
406 | Not Acceptable -- You requested a format that isn't json. |
410 | Gone -- The resource requested has been removed from our servers. |
422 | Unprocessable Entity -- One or more parameters supplied are missing or invalid or your app is not approved. |
429 | Too Many Requests -- You are sending too many requests in short period of time. |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |