API access to Intervals.icu

Intervals.icu now has a public API for other applications. To use it you need to generate an API key in /settings (look for “Developer Settings” near the bottom). Your API key allows other applications to access your Intervals.icu data. Be careful what you do with it! If you suspect that your key may have been compromised immediately clear or re-generate it.

The API uses basic authentication. The username is “API_KEY” and the password your API key. Example using curl:

$ curl -u API_KEY:1l0nlqjq3j1obdhg08rz5rfhx https://intervals.icu/api/v1/athlete/2049151/activities.csv

I generated some API docs. Its a bit sparse on details but you can click “Authorise” and enter an API Key or OAuth access token and make calls:



Great! Now I could try myself some metrics before suggesting them to you. Also it would be great to have an easy access to the detailed activity files.

E.g., I’ve been wondering if a series of week-to-week plots showing the HR @ running pace would be something useful to track improvement in aerobic fitness (conversely, HR @ power for cycling). For that I’d need the files. Or is there an easy way to get them from Strava?

PS: are there any privacy measures?

I have to be careful to not just proxy stuff you can get from Strava. Would be best if I added those HR stats you are looking for to each activity then they will be in the CSV and I can also plot them in Intervals.icu at some point.

The Strava API is relatively easy to use especially if you only want to look at your own data.

The Intervals.icu API will only let you see your own data and data for athletes you follow so I think is ok re privacy.

I need to re-do the athletes and followers pages (got some good ideas from @Cyclopaat) and then I will start adding support for custom calculated values and plots (e.g. for chronic intensity load).


I have added REST JSON endpoints for calendar access. If you have a clever way of generating training plans you can now get those into Intervals.icu easily.

GET /api/v1/athlete/{id}/calendars List all calendars

GET /api/v1/athlete/{id}/events List all calendar events. Requires parameters oldest and newest in yyyy-MM-dd format (local dates i.e. no timezone). The range may be expanded if oldest and/or newest fall inside a multiday event to include the whole event. Only events from enabled calendars are returned. Supports optional calendar_id parameter to filter for events for a particular calendar.

GET /api/v1/athlete/{id}/events/{eventId} Fetch an event by id.
GET /api/v1/athlete/{id}/events/{eventId}/download{ext} Download a planned workout in .zwo, .mrc or .erg format.
POST /api/v1/athlete/{id}/events Create event and return it.
PUT /api/v1/athlete/{id}/events/{eventId} Update event and return it.
DELETE /api/v1/athlete/{id}/events/{eventId} Delete the event.

Example POST payload to create a workout (note that the dates cannot have time i.e. must end with T00:00:00 and the athlete needs to be yourself or someone you are coaching):

    "start_date_local": "2020-05-01T00:00:00",
    "icu_training_load": 120,
    "category": "WORKOUT",
    "name": "Outdoor ride at last!",
    "description": "Lockdown finally over, just go ride around all over the place!",
    "type": "Ride",
    "moving_time": 7200


    "id": 127,
    "start_date_local": "2020-05-01T00:00:00",
    "icu_training_load": 120,
    "icu_atl": 18.852789,
    "icu_ctl": 39.18664,
    "calendar_id": 1,
    "uid": "fcb69e1a-934e-47ac-a5f1-a207830466f2",
    "category": "WORKOUT",
    "end_date_local": "2020-05-02T00:00:00",
    "name": "Outdoor ride at last!",
    "description": "Lockdown finally over, just go ride around all over the place!",
    "type": "Ride",
    "color": null,
    "moving_time": 7200,
    "icu_ftp": null,
    "atl_days": null,
    "ctl_days": null,
    "updated": "2020-04-13T14:58:50.314+0000"

Note that the future fitness parameters (after the workout) for that date have been calculated.

If anyone is looking at the athlete’s calendar or fitness chart they will see any changes immediately.

Update 22 April 2021:

  • The workout description is now parsed. This means that workouts created or updated via the API have training load calculated and get “time in zones” and so on. This also applies to workouts synced from an external calendar.
  • You can now create/update workouts from zwo, mrc and erg files.

POST /api/v1/athlete/{id}/events

  "category": "WORKOUT",
  "start_date_local": "2021-04-29T00:00:00",
  "type": "Ride",
  "filename": "4x8m.zwo",
  "file_contents": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<workout_file>..."


  "id": 610062,
  "icu_training_load": 116,
  "name": "4x8m VO2 Max",
  "description": "These are horribly nasty.\nCategory: Horrible\n\n- 20m 60% 90-100rpm\n\nMain set 4x\n- 8m 110%\n- 8m 50%\n\n- 10m 60%\n",
  "workout_doc": {
    "steps": [
        "power": {"units": "%ftp", "value": 60},
        "cadence": {"end": 100, "start": 90, "units": "rpm"}, "duration": 1200
      }, ...
    "duration": 5640,
    "zoneTimes": [1920, 1800, 0, 0, 1920, 0, 0, 0],
    "hrZoneTimes": [1920, 1800, 0, 0, 1920, 0, 0, 0]
  "icu_intensity": 86.04798
1 Like

Hi David,

First of all, thank your for the very well designed and highly useful web platform!

I am relatively new to programming, actually working with R.
I tried to access the API but was unsuccessful.
Does I need to have some specific id to replace {id} in the endpoint: /api/v1/athlete/{id}/activities.csv ?

Tx. Yes that {id} is a Strava athlete id. If you “copy link” on the CSV link in the app you can see the ID for the athlete you are looking at (2049151 is me):


You can just edit that (add in the /v1).

Got it thanks!

Is there an option to access also the raw data?

What data in particular? I need to be careful to not just proxy things that you can get from the Strava API.

Oh ok!

Actually I am working as a sport scientist with a national track cycling team and was looking for a way to easily get the data from athletes via the cloud and compute some additional metrics like the numbers of sprints in a session, etc.

As I understand, I should look at the Strava API if I want the raw data?
I was hoping for an easy way via Intervals.icu… and your’s API access seemed a good alternative to get data from multiples athletes!

I’d really appreciate any suggestions in that regard.

I can give your the intervals detected or manually added in Intervals.icu via the API if that helps?

Yes it would be cool to have the intervals detected!

Thanks a lot David, very excited to follow the development of Intervals.icu!

Hi David,

I would really like to have access to the intervals detected in Intervals.icu via the API.

Hopefully this is an easy add…!

Thanks a lot!

1 Like

Not too hard. Will get on it soon.

1 Like

I have added API access to the data for each activity:

GET /api/v1/activity/{id}?intervals=true

This returns a JSON document which includes the interval data and lots of other stuff:

"icu_intervals": [
      "start_index": 1582,
      "distance": 3872.1006,
      "moving_time": 719,
      "elapsed_time": 719,
      "average_watts": 327,
      "min_watts": 6,
      "max_watts": 626,
      "average_watts_kg": 4.52,
      "max_watts_kg": 8.67,
      "intensity": 112,
      "w5s_variability": 0.022526897,
      "weighted_average_watts": 327,
      "training_load": 13.339117,
      "joules": 235394,
      "decoupling": 2.050206,
      "zone": 5,
      "zone_min_watts": 305,
      "zone_max_watts": 348,
      "average_speed": 5.3853974,
      "min_speed": 3.9,
      "max_speed": 7.8,
      "average_heartrate": 173,
      "min_heartrate": 139,
      "max_heartrate": 185,
      "average_cadence": 72,
      "min_cadence": 53,
      "max_cadence": 96,
      "average_torque": 43,
      "min_torque": 11,
      "max_torque": 89,
      "total_elevation_gain": 217.8,
      "min_altitude": -61.4,
      "max_altitude": 156.4,
      "average_gradient": 0.056248534,
      "id": 1582,
      "type": "WORK",
      "end_index": 2299,
      "group_id": "719s@327w72rpm",
      "segment_effort_ids": [
      "estimated_cp": null,
      "start_time": 1586,
      "end_time": 2305

Leave out intervals or set it to false if you don’t need interval data.


Thank you very much David! Very useful for me.

1 Like

Hi David, outstanding work!

Do you have an end point for adding to a work out to library ?


I will add that soon. On the list.


ive made a phpsdk to collect workouts from zwift and add them as workouts / session.

Welcome to the code if you wish, will make it available on GitHub as a package


I have added some endpoints for this (will deploy Tuesday AM GMT+2):

GET /api/v1/athlete/{id}/folders List all folders and workouts
POST /api/v1/athlete/{id}/folders Create a folder
PUT /api/v1/athlete/{id}/folders/{folderId} Update folder
DELETE /api/v1/athlete/{id}/folders/{folderId} Delete folder
GET /api/v1/athlete/{id}/folders/{folderId}/shared-with Show who folder has been shared with
PUT /api/v1/athlete/{id}/folders/{folderId}/shared-with Update folder sharing
GET /api/v1/athlete/{id}/workouts List all workouts (excluding those shared by others)
GET /api/v1/athlete/{id}/workouts/{workoutId} Get a workout
POST /api/v1/athlete/{id}/workouts Create a workout
PUT /api/v1/athlete/{id}/workouts/{workoutId} Update a workout
DELETE /api/v1/athlete/{id}/workouts/{workoutId} Delete a workout
POST /api/v1/download-workout{ext} Download a workout in .zwo .mrc or .erg format

These mirror the private endpoints used by Intervals.icu so you can use the browser inspector to see what payloads to send and so on.

There is a catch: Workouts have a “workout_doc” field which is the parsed workout steps. Currently the parser is only available client side. So before you can download a workout in a different format or have it sync to Garmin Connect you need to edit it using the Intervals.icu app so the workout_doc field is populated.

The Intervals.icu server is Java and the parsing code is JavaScript. So I need to setup a little node service to do the parsing.


Hi David;
Get 401s on those end points; I’ve tried regenerating api key etc as well and still the same.