API access to Intervals.icu

Thanks for this very quick reply.

I have to apologize. In so many situations, the issue was sitting in front of the screen. With too much refactoring I introduced a check too much. Could solve it in the meantime. Stuff works.

The set of APIs exposed from ICU is pretty amazing. Really! Thanks.

Background: I am not that happy when changing the HR-Zones, that all historical LTHR could not be simply kept. For this reason a script does the job to correct them.
image

3 Likes

Limited I mean, ZWO doesn’t support target range, which I like to see in my workouts.

Beautiful, thank you

I agree with this – @david, could you chime in?

I assume that it’s like this because FTP and Threshold Pace should change much more often than LTHR, but I think that it should be kept for previous activities if there’s a need to Re-analyze (e.g. to compute a new field).

I did some tests and LTHR is changed when you do Actions → Update zones under the ride timeline chart or use the activity list view to do the same.

(edit 2023-01-06: I must have been half asleep when I tested this before and said it didn’t change LTHR)

1 Like

Is that the same behavior for Re-analyze?

Also, does that mean that you’re not able to change the LTHR for an activity like you can with FTP/Threshold Pace?

Hello @William_Barnes ,

stumpled across this section in your gscripts. Looks like it didn´t really work for you:

function populateSheetWithJSON(sheet, csvUrl) {
   var resp = ImportJSON(csvUrl);
      sheet.getRange(
         1, 1,
         resp.length /* rows */,
         resp[0].length /* columns */).clearContent().setValues(resp);
   }

This one shall do the job, at least I could download for example all events via API and parse it from JSON to a table in sheets

function populateSheetWithJSON(sheet, csvUrl) {
   var resp = ImportJSON(csvUrl);
   const max = Math.max(...resp.map(r => r.length));
   resp = resp.map(r => r.length < max ? [...r, ...Array(max - r.length)] : r);
   sheet.getRange(1, 1)
       .offset(0, 0, resp.length, resp[0].length)
       .setValues(resp);
   }
 var sheet_json = SpreadsheetApp.getActive().getSheetByName('intervals.icu_events-export');
 populateSheetWithJSON(sheet_json,"https://API_KEY:" + API_KEY + "@intervals.icu/api/v1/athlete/" + athleteID + "/events?oldest=YYYY-MM-DD&newest=YYYY-MM-DD");

@david any plans for exposing all events from ICU also as CSV via API? (like we have with wellness or the activities) That would be nice and very helpful in many situations for others as well to either use it for programmatically further usage or to simply get an overview of all events in a list. Many thanks.

I thought you might be interested in as I made some step to fix it, but there is still sth weird and buggy. Handling NULL values seems to be issue when I look to my results in the table. It does not skip them and just copy from the one before. I assume the issue is being caused at function parseJSONObject_, during transformData_ the NULL values are not considered, but I stuck from there solving it.

Best,
Johannes

1 Like

I have just updated my post. Must have been half asleep before. Doing “Update Zones” does change LTHR. Probably not the best decision but on the other hand it isn’t something that changes much.

Re-analyze does not change zones, LTHR, FTP or threshold pace. All history is kept.

2 Likes

You can now download the events in CSV format. Just add .csv to the path.

2 Likes

Bähm :tada:… easy catch! Appreciated. Thx.

Leave from outside a huge impression of a proper designed code base and well-done contracts.

Is it possible to upload activities the same way, by providing base64 string?

No you need to use this endpoint for activities: POST /api/v1/athlete/{id}/activities

Activity files can be very big.

When endpoint GET /api/v1/athlete/{athleteId}/activities returns an empty array, the response doesn’t have content-type header. If the response returns a non-empty array, content-type is present.
Could you fix it, and add header for all cases?

Ohh I fixed that and a couple of others. Sorry about that. Will deploy Friday AM (GMT+2).

Has anyone manadged to Authenticate with the ChatGPT custom actions interface from GPTBuilder?

OAuth isn’t available for most common users as far as I know.

Did you try with an API Key?

Anyway, what do wanna ask Chat GPT? Would be interested in understanding your use case.

Hi! I actually did try with the API, but cant manage to get the call working.

I actually have cero dev experiance :sweat_smile:

I would love to access my data in natural language and be able to analyse it.

Try this:

Authentication Type: API Key
Client ID: API_KEY This text and not your apikey!!
Client Secret: Your Apikey found on the Intervals settings page
Authorization URL: https://intervals.icu/api/v1/athlete/AthleteID/activities.csv Where AthleteID is your ID found on the intervals settings page

Hi,

In my application i would like to convert workout step target from zone to actual ftp percentage (Z1 = 0% - 55%).
I’m thinking to use zoneTimes field from endpoint api/v1/athlete/.../events it has perfect zone description

"zoneTimes": [
  {
    "id": "Z1",
    "max": 55,
    "name": "Z1",
    "secs": 0,
    "zone": 1,
    "color": "#009e80",
    "maxWatts": 132,
    "minWatts": 1,
    "percentRange": "0% - 55%"
  },
  ...

My question, is it ok to use it or there is different rest endpoint which can return zone description?
If current one is ok, could you please add additional object to zone description, which contains percentage range not in string, but in int values. e.g.

"zoneTimes": [
  {
    ...
    "range": {
      "min": 0
      "max": 55
    }
  }
]

Looks like the PercentRange is exactly what you need and it’s already there. You should be able to Parse it with a delimiter.

You need to use this endpoint: GET /api/v1/athlete/{id}/events{format}

If you add resolve=true then all the workout step targets will be expanded into actual watts/bpm/pace values using the athlete’s zones and other settings.