API access to Intervals.icu

I am trying to get and update wellness records in my profile but I keep getting the 403: Access denied error.

curl -X GET "https://intervals.icu/api/v1/athlete/iXXXXX/wellness/2024-11-14" \
 -H 'accept: */*'\
 -H 'authorization: Bearer MYCURRENTAPIKEY'

Response:

{
  "status": 403,
  "error": "Access denied"
}

Sorry if I’m making some really basic mistake.

you’re using bearer instead of API_KEY

Bearer is for OAuth and you need to get an oAuth Token for that.

Refer to above thread (the 1st post) to use the API_KEY username and where to get the password.

1 Like

That seems to be it, this expects an activity ID, thanks!

In case someone looks this up later, one way to get a list of activities is using the /api/v1/athlete/{id}/activities endpoint.

1 Like

You can now use “0” for the athlete id for endpoints that accept an athlete id in the path. This will use the athlete for the API key or bearer token used to make the call.

Example:

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

That will return activity data for whoever’s API_KEY that is.

Hi David - the new API capability is brilliant. It’s so great to see this feature!

is there any documentation for what the fields in the API responses mean? Some are obvious but others aren’t (to me at least)

I looked at the Swagger docs and the OpenAPI doc, but when checking the doc for "$ref": "#/components/schemas/Activity" (for example), there doesn’t seem to be any explanation of the field values

Did you check if your answer is in here somewhere?

There isn’t much of that yet. You can figure some of it out using the dom inspector and watching what the web app does. I will get to it for the main things eventually. At least the endpoints have docs now!

1 Like

Just an FYI @david that the schema and response for
https://intervals.icu/api-docs.html#get-/api/v1/athlete/-id-/weather-forecast is incorrect as it returns the set of daily forecasts and not the weather config/settings

Just an fyi that /api/v1/athlete/{id}/athlete-summary returns 500
If there is some other way that you would like to know about these or would prefer us not to let you know, please say. Thanks

I just tested that one and it did return the config info. The field is named “forecasts” but just includes the lat, lng etc:

curl 'https://intervals.icu/api/v1/athlete/0/weather-config' -u API_KEY:xxx
{
  "forecasts": [
    {
      "id": 1,
      "provider": "OPEN_WEATHER",
      "location": "Cape Town,Western Cape,ZA",
      "label": "Cape Town",
      "lat": -33.928993,
      "lon": 18.417397,
      "enabled": true
    },
 ...

This is the best place to post issues. I have fixed that 500 and added some docs for that endpoint. Will deploy Monday AM (GMT+2).

So using postman, this endpoint
https://{{server}}/api/v1/athlete/{{id}}/weather-config
returns

"forecasts": [
        {
            "id": 1,
            "provider": "OPEN_WEATHER",
            "location": "London,England,GB",
            "label": "London",
            "lat": 51.50853,
            "lon": -0.12574,
            "enabled": true
        }
    ]
}

While this one
https://{{server}}/api/v1/athlete/{{id}}/weather-forecast
returns

{
    "forecasts": [
        {
            "id": 1,
            "provider": "OPEN_WEATHER",
            "location": "London,England,GB",
            "label": "London",
            "lat": 51.50853,
            "lon": -0.12574,
            "error": null,
            "daily": [
                {
                    "id": "2024-11-23",
                    "pressure": 1003.0,
                    "humidity": 87.0,
                    "dew_point": 12.167119,
                    "clouds": 100.0,
                    "wind_speed": 11.41,
                    "wind_deg": 202.0,
                    "wind_gust": 24.11,
                    "rain": 9.66,
                    "snow": 0.0,
                    "weather": [
                        {
                            "id": 501,
                            "main": null,
                            "description": "moderate rain",
                            "icon": "10d"
                        }
                    ],
                    "sunrise": "07:32",
                    "sunset": "16:01",
                    "moon_phase": 0.0,
                    "temp": {
                        "day": 9.08,
                        "night": 14.3,
                        "eve": 12.96,
                        "morn": 4.07,
                        "min": 3.31,
                        "max": 14.3
                    },
                    "feels_like": {
                        "day": 5.15,
                        "night": 14.11,
                        "eve": 12.71,
                        "morn": 2.11
                    }
                }, ...

So I think the endpoints work as intended it’s just the the docs for the latter endpoint are incorrect

This is actually my bug because I didn’t supply the date range
Doing this works as expected:
curl --location 'https://intervals.icu/api/v1/athlete/0/athlete-summary?start=2024-11-01&end=2024-11-24'

Ideally the API would report a 4xx bad request error instead of 500 (crash?)

Hi @david - is it possible to change the /api/v1/athlete/{{id}}/gear endpoint to include a date range?
This would allow me to determine the time and distance accumulated on the bike between the two dates.

Looking at my own gear stats, I see
Brompton 2110km 19h
Orca 12580km 276h

which don’t really make much sense. I really don’t think I can cycle 2k km on a brompton in 19hrs! :slight_smile:

Hi,

A bit of conceptual question about the API and data model:

Do I get it right, that the API is designed to track metrics in two ways:

  1. Part of the workout (continuous)
  2. Wellness metrics, once per day

Is there a way or plan to track 24x7 metrics, like HR, Stress and so on, assuming that integrations that are able to provide such data exist?

hi @david i think there is a bug in https://{{server}}/api/v1/athlete/{{id}}/activities?oldest=2024-11-03&newest=2024-11-10

The gear object is not populated correctly - it always lists the same gear.id and the other fields including name is null

You’re right, there is only the ID field being populated there. The rest are in the “gears” endpoint.

If you set a default gear, this will default to that gear.id each time.

If I do want to list the gears, I would match it. What I do is get the gears from the gear endpoint and match it with the gears ID on the activity.
Screenshot 2024-12-06 at 8.21.15 AM

edit: Read some of your earlier post - What you’re wanting to do, i don’t believe the current endpoints supports it. There is a # of activities, but AFAIK there is no linkages to the actual activities that are using those gears.

I suggest using the list view for your purpose. And then using the Filter for the gear that you want

if you notice on the bottom, there’s already a helpful total for dist and time.

It’s not so much a bug but undocumented behaviour :slight_smile: Only the gear id is filled in for performance reasons. If you need the full gear object you can make a new call to the list gear endpoint.

Looking up the gear_id lookup would be fine, however I’m seeing the same gear ID for two rides when only one of the bikes (gear ID is correct)

This bug means that I can’t detect which bike was used for the ride using the API call.

You can reproduce this with the following API call
'https://intervals.icu/api/v1/athlete/i189303/activities?oldest=2024-11-17&newest=2024-11-18'

The ride on the 17-Nov should have gear.id == b10966650
and the ride on 18-Nov should have gear.id == b12116607

But the response from the api is:

[
    {
        "id": "12938769888",
        "start_date_local": "2024-11-18T07:16:54",
        ...
       "gear": {
            "id": "b10966650",
            ...
        },
        ...
        "icu_variability_index": null
    },
    {
        "id": "12920827048",
        "start_date_local": "2024-11-17T09:18:20",
        ...
        "gear": {
            "id": "b10966650",
            ...
        },
        "perceived_exertion": null,
        ...
        "icu_variability_index": null
    }
]

Thanks

Those activities both have the same gear in the db? I just ran some SQL to check.

     id      |  gear_id  |   start_date_local   |     name     | deleted 
-------------+-----------+----------------------+--------------+---------
 12920827048 | b10966650 | 2024-11-17T09:18:20Z | Morning Ride | 
 12938769888 | b10966650 | 2024-11-18T07:16:54Z | Morning Ride | 

Thanks for checking - you’re right something weird is going on as each bike has its own Wahoo head unit which should be setting the gear (bike) correctly

I’ll keep investigating and sorry for wasting your time!