/user/<user_id>
/me
/user/<user_id>/heartrate/resting/<date>
/user/<user_id>/heartrate/maximum/<date>
/user/<user_id>/power/ftp/<date>
/user/<user_id>/weight/<date>
/user/<user_id>/rides
/user/<user_id>/upload
/user/<user_id>/upload/<upload_id>
/ride/<ride_id>
/ride/<ride_id>/raw
/user/<user_id>/training-plan
/plan/<plan_id>
/user/<user_id>/power-curve/period
/tokens
All API endpoints are relative to https://www.cyclinganalytics.com/api
. Therefore, the URL to use for /me/rides
is https://www.cyclinganalytics.com/api/me/rides
.
Note: Using http
instead of https
works at the moment, but support for this will be discontinued soon.
There are not yet API endpoints for everything. Please get in contact if you want something that doesn’t exist yet.
Authentication for this API is based on the OAuth 2.0 framework. Once an authentication token has been acquired, request must include the token in the Authorization
HTTP header:
Authorization: Bearer qr4hI35VeCmOfPAQhXSHGNX5JZcsJyIP
More information about authentication can be found in the authentication documentation.
The HTTP methods POST
, GET
, PUT
and DELETE
are used to indicate the type of action to perform for the call to any API endpoint, with the following meanings:
POST
— Create.GET
— Read.PUT
— Create/update.DELETE
— Delete.The difference between POST
and PUT
is that doing the same PUT
twice in a row will be exactly the same as doing it once, whereas the same POST
twice in a row will result in two objects being created (or an error on the second POST
if the request contains something that prevents it from being added twice).
For GET
requests, any parameters must be encoded in the URL:
/me?power=true&heartrate=true
For POST
and PUT
requests, unless otherwise specified, parameters must JSON encoded as the body of the request. A Content-Type: application/json
header must also be included.
When the response isn’t very short, it is compressed with gzip
. There is a Content-Encoding: gzip
header when this is the case. Most tools handle this transparently, so this can generally be ignored.
The easiest way to see exactly what is being sent and returned is to use the API console and use the Chrome developer tools (network tab) or the Firefox developer tools (web console) to inspect the requests and responses.
Values are returned in the following format:
YYYY-MM-DD
.YYYY-MM-DDThh:mm:ss
.This JavaScript function turns an array index into a time:
function indexToTime(i) {
return i < 300 ? i + 1 : (i < 600 ? 300 + (i - 299) * 5 : (i < 900 ? 1800 + (i - 599) * 30 : 10800 + (i - 899) * 300));
}
This JavaScript function turns a time into an array index:
function timeToIndex(t) {
return t <= 300 ? t - 1 : (t <= 1800 ? (t - 300) / 5 + 299 : (t <= 10800 ? (t - 1800) / 30 + 599 : (t - 10800) / 300 + 899));
}
If an error occurs, the returned JSON will include an error
and the HTTP status code will be a 4xx or 5xx code. It is currently possible that no JSON will be returned in some cases, so the status code should be checked first.
/me
/me
is an alias for /user/<id>
for the authenticated user. /me
is not available when using the API with a team authorisation token.
/user/<id>
/me
GET
Gets user information.
All are optional.
weight
— If true
, also returns the user’s weight history.power
— If true
, also returns the user’s FTP history and power zones.heartrate
— If true
, also returns the user’s resting and maximum heart rate history, and heart rate zones.id
name
email
timezone
— A timezone name in the pytz common_timezones_set
.units
— Currently either metric
or us
.sex
— Either male
or female
.weight
— An array of {date: <date>, value: <weight>}
objects.power
— An object containing:
ftp
— An array of {date: <date>, value: <ftp>}
objects.zones
— An array of {value: <minimum power FTP%>, name: <name>}
objects. The maximum power for a zone is based on the minimum power for the next zone. All values are specified as a percentage of FTP.heartrate
— An object containing:
resting
— An array of {date: <date>, value: <resting heart rate>}
objects.maximum
— An array of {date: <date>, value: <maximum heart rate>}
objects.zones
— An array of {value: <minimum heart rate>, name: <name>}
objects. The maximum heart rate for a zone is the minimum heart rate for the next zone minus one./user/<id>/heartrate/resting/<date>
/user/<id>/heartrate/maximum/<date>
/user/<id>/power/ftp/<date>
/user/<id>/weight/<date>
/me/heartrate/maximum/<date>
/me/heartrate/resting/<date>
/me/power/ftp/<date>
/me/weight/<date>
The endpoints for resting heart rate, maximum heart rate, FTP and weight behave in the same way. For each there is an array of {value: <value>, date: <date>}
objects (which is what is returned by /me
), and these endpoints provide easy ways to view and modify these arrays.
GET
Get the resting heart rate, maximum heart rate, FTP or weight for a day.
The value returned is normally the most recent value on or before the requested date. If the date is before all entries, the value of the earliest entry is returned. If there are no entries, null
is returned.
value
— a number or null
.PUT
Adds an entry on the given day (or changes the entry if it already exists).
value
success
DELETE
Deletes the entry for the given day. This has no effect if there is no entry on the given day, but it will return the same success message.
success
/user/<id>/rides
/me/rides
GET
Get the list of rides of a user.
minimal
— If true
, only include id
and local_datetime
for each ride in the response.curves
— If true
, then power_curve
(highest average power curve) and epower_curve
(highest effective power curve) for each ride will be included in the response. Alternatively, use power_curve=true
or epower_curve=true
to get only one of them. This significantly increases the size of the reponse.rides
— An array of rides in the format that /ride/<ride_id> returns, but not including streams
or user_id
. If minimal=true
was included in the request, the elements in rides
only contain id
and local_datetime
./user/<id>/upload
/me/upload
POST
Uploads a new ride.
This method returns immediately and the ride file is then processed asynchronously. This returns an upload_id
(amongst other things), which can then be used to query the upload status.
A common workflow would be to upload rides with this method, then check /me/upload/<upload_id>
every few seconds until processing has finished, and then get the ride summary data from /ride/<ride_id>
.
This method supports directly uploading the ride data, or being given a URL for the ride data file that is then downloaded from the server.
data
and either filename
or format
are required when uploading a file. When url
is provided, the filename will be read if available, or else filename
or format
is required.
It is preferable to send these requests with data
as multipart/form-data
rather than application/json
, as the data must be Base64 encoded when sent as JSON, which results in a 33% size increase.
data
— The raw file data.url
— A reachable URL for the ride data file.format
— The file format. One of fit
, tcx
, gpx
, pwx
, srm
, bin
or csv
.filename
title
notes
virtual
— For rides ridden on a trainer that have artificial GPS data (e.g., Zwift rides), but isn’t necessary if the ride file itself specifies it is virtual.This returns the same as GET /me/upload/<upload_id>
.
>>> POST /user/3910838/upload {data: '...', filename: '2013-02-02-10-17-40.fit'}
{
"status": "processing",
"ride_id": null,
"user_id": 1000000,
"format": "fit",
"datetime": "2013-10-07T20:11:09",
"upload_id": 3739085130,
"filename": "2013-02-02-10-17-40.fit",
"size": 45374
}
/user/<id>/upload/<upload_id>
/me/upload/<upload_id>
GET
Get the status of a newly uploaded ride.
status
will be processing
until it is finished processing, when it will be either done
or error
. If done
, it was successful, and ride_id
will contain the ID of the ride. If error
, there will also be an error
in the response.
This method is only available within two weeks of the ride being uploaded — the ride is still there, but its upload status cannot be queried.
upload_id
user_id
filename
format
size
— The size of the file, in bytes.datetime
status
— processing
, done
or error
.ride_id
— null
until status
is done
.error
— Only included if the value of status
is error
.error_code
— Only included if the value of status
is error
.error_code
will be one of:
expired_account
— If the user’s account has expired.empty_file
— When the file is 0 bytes long.unsupported_file
— When the format, or variation of format, is unsupported.invalid_file
— If there is something obviously wrong with the file (bad headers often result in this).duplicate_ride
— When the ride already exists (based on a hash of the ride).too_short
— If the ride is less than five seconds long.processing_error
— When something else goes wrong parsing or processing the file./ride/<id>
GET
Gets a ride.
streams
— all
, or one or more of power
, speed
, distance
, heartrate
, cadence
, lrbalance
, latitude
, longitude
, elevation
, gradient
, temperature
, torque_effectiveness
, pedal_smoothness
, platform_center_offset
, power_phase
, power_direction
, thb
, smo2
, respiration_rate
, heart_rate_variability
, gears
. This causes the raw ride data to be returned. These must be joined together as a comma separated string. If this is not given, no raw data is provided (and the request is a lot faster).curves
— If true
, then power_curve
(highest average power curve) and epower_curve
(highest effective power curve) will be included in the response. Alternatively, use power_curve=true
or epower_curve=true
to get only one of them.id
user_id
title
notes
local_datetime
utc_datetime
type
— cycling
, gym
, running
, swimming
, walking
, hiking
, rowing
, kayaking
, sup
(stand-up paddleboarding), skiing
, snowboarding
or other
subtype
— road
, trainer
, virtual
, tt
, cx
, track
, mtb
or bmx
.purpose
— ride
, training
, race
, social
or commute
. Presently, ride
is a generic type for all activity types.trainer
— Whether or not the ride was ridden on a trainer.format
— The file format the ride was uploaded in.summary
total_time
— Time from beginning to end of ride.duration
— total_time
with all gaps longer than three minutes reduced to three minutes.moving_time
— Time when speed was above 3km/h (not 0km/h, to account for GPS errors).distance
climbing
work
epower
— Effective power.intensity
— Intensity, based on power.variability
— Variability, based on power.load
— Training load, based on power.trimp
— TRIMP, like load
, but based on heart rate.pwc150
— Physical Work Capacity; estimated power at 150BPM based on a statistical correlation between power output and HR.pwc170
— As above, but power output at 170BPM.pwc_r2
— The r2 value of the PWC values, indicating the quality of the statistical relationship between HR and power.lrbalance
— Left/right power balance. The percentage of power produced by the left leg, or null
if the ride has no power balance data.avg_cadence
avg_speed
avg_heartrate
avg_power
max_cadence
max_speed
max_heartrate
max_power
zones
power
heartrate
has
— Whether or not the ride file contains the data stream.
power
heartrate
cadence
speed
lrbalance
gps
elevation
temperature
ps
— Pedal smoothness. This and the following are only included when they are true.te
— Torque effectiveness.pco
— Platform center offset.pp
— Power phase.pd
— Power direction.thb
smo2
rr
— Respiration rate.hrv
— Heart rate variability.gears
power_curve
— An array with the highest average power for all time intervals. See data format for details about the structure of this array.epower_curve
— As above, but for effective power.streams
— Not included unless streams
is in the request. Streams are only included when data exists for the stream.
power
speed
distance
heartrate
cadence
lrbalance
latitude
longitude
elevation
gradient
temperature
thb
smo2
respiration_rate
heart_rate_variability
gears
left_te
, right_te
— Torque effectiveness.left_ps
, right_ps
— Pedal smoothness.left_pco
, right_pco
— Platform center offset.left_pp_s
, right_pp_s
— Power phase start.left_pp_e
, right_pp_e
— Power phase end.left_ppp_s
, right_ppp_s
— Peak power phase start.left_ppp_e
, right_ppp_e
— Peak power phase end.left_tangential
, right_tangential
— This and the following are power direction metrics (from Pioneer devices).left_radial
, right_radial
left_torque
, right_torque
left_efficiency
, right_efficiency
>>> GET /ride/928389327473?streams=power,heartrate
{id: 928389327473, title: "74km around Richmond", summary: {duration: 5134, ...}, ..., streams: {power: [86, 98, 98, ...], heartrate: [...]}}
PUT
Updates a ride.
This currently only supports updating the title and notes. Get in contact if you want this expanded.
title
notes
The same as GET
if successful, or a list of errors.
DELETE
Deletes a ride.
success
— a short message if the operation was successful./ride/<id>/raw
GET
Gets the raw ride file that was originally uploaded.
The returned data is bitwise identical to the file that was originally uploaded. No processing or editing is applied. The file format is the same as it was when originally uploaded.
This method returns the file as raw bytes. A filename, which includes the start date/time, and the format as the file extension, is included in the Content-Disposition
header.
/user/<id>/training-plan
/me/training-plan
POST
Creates a new plan.
All fields are required. (Provide an empty string for unused fields.)
title
date
— Must be in the format YYYY-MM-DD.duration
cadence
load
description
notes
This returns the same as GET /plan/<id>
.
GET
Get the list of training plans of a user.
plans
— An array of plans in the format that /plan/<plan_id> returns./plan/<id>
GET
Gets an individual training plan.
id
user_id
title
date
order
— Multiple plans can exist on the same day. This is normally 1
.duration
cadence
load
description
notes
ride_id
— Only exists when the plan has been linked to a ride.DELETE
Deletes a training plan.
The same as GET
.
PUT
Updates a training plan.
All are optional.
title
date
— Must be in the format YYYY-MM-DD.order
duration
cadence
load
description
notes
The same as GET
.
/user/<id>/power-curve/<period>
/me/power-curve/<period>
GET
Gets the maximum power achieved for all time durations for a period.
period
can be either all
, a year (i.e., 2018
), or a year and month (i.e., 2018-9
).
curve
— An array of elements that form the power curve, each in a three element array of:
name
The duration that each element of the array represents is described in data format.
/tokens
POST
Create a new token for authenticating with the API.
permissions
— Must be all
and provided.team_id
— If the user is the administrator of a team, they can create a token for the team instead of for themself.token
— The token.timestamp
— When the token was created.type
— Either user
or team
.user_id
— The user ID of the token owner. Included if type
is user
.team_id
— The team ID of the token owner. Included if type
is team
.permissions
— A list of permissions this token allows the bearer to do. Currently always only includes all
.>>> POST /tokens {permissions: 'all'}
{ "timestamp": 1371671316, "user_id": 1000000, "token": "tgReLjMnGlW9RdPuuyQz4NXc4nQX2QT0", "type": "user", "permissions": [ "all" ] }
>>> POST /tokens {permissions: 'all', team_id: 308150}
{ "timestamp": 1374137008, "token": "ZmaQBjCEGMYwAdZeaxTKGLLgTxQnss4n", "type": "team", "team_id": 308150, "permissions": [ "all" ] }
GET
Gets the list of tokens that are owned by the user/team.
tokens
— An array of tokens in the same format as the response of the POST
request.>>> GET /tokens
{ "tokens" : [ { "timestamp": 1371671323, "user_id": 1000000, "token": "tgReLjMnGlW9RdPuuyQz4NXc4nQX2QT0", "type": "user", "permissions": [ "all" ] } ] }