# API: Create or update workout without using description text syntax?

**URL:** <https://forum.intervals.icu/t/api-create-or-update-workout-without-using-description-text-syntax/124215>\
**Category:** External Projects\
**Created:** [9 March 2026 13:34 UTC](https://forum.intervals.icu/t/api-create-or-update-workout-without-using-description-text-syntax/124215 "2026-03-09T13:34:22Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Fohnbit](https://forum.intervals.icu/user_avatar/forum.intervals.icu/fohnbit/32/68664_2.png) [@Fohnbit](https://forum.intervals.icu/u/Fohnbit)\
**Post date:** [9 March 2026 13:34 UTC](https://forum.intervals.icu/t/api-create-or-update-workout-without-using-description-text-syntax/124215/1 "2026-03-09T13:34:22Z")

</div>

Hi,

I’m currently integrating the Intervals.icu API in my application and I’m able to create and update calendar workouts via:

`PUT /api/v1/athlete/{id}/events/{eventId}`

Until now I have been generating workouts by placing the steps inside the **description** field using the Intervals workout text syntax (e.g. - 10m 60%, 4x - 5m 110%, etc.), which works because Intervals parses the description and creates the workout structure automatically.

However, I would prefer to keep the **description clean** and define the workout structure directly in JSON (for example using workout\_doc.steps).

Something like:

```auto
{
  "category": "WORKOUT",
  "start_date_local": "2026-03-10T10:00:00",
  "type": "Ride",
  "name": "Lactate Test",
  "workout_doc": {
    "steps": [
      {
        "duration": 300,
        "power": { "units": "%ftp", "value": 90 }
      }
    ]
  }
}

```

But it’s not clear to me if this is actually supported.

From what I read in the forum, it seems that the API **expects either the workout description syntax or a workout file (zwo, mrc, erg, fit)** and that the server then generates the workout structure itself.

So my questions are:

1. Is it possible to **create or update a workout via the API using structured JSON steps** instead of the description syntax?
2. If yes, what is the **correct JSON schema** for the workout steps?
3. Or is the only supported way to:

- send the **description text syntax** , or
- upload a **ZWO/MRC/ERG workout file**?

My goal is simply to keep the workout **description clean for athletes** while still defining the structured steps programmatically.

Thanks!

---

<div class="post-metadata">

**Author:** ![Fohnbit](https://forum.intervals.icu/user_avatar/forum.intervals.icu/fohnbit/32/68664_2.png) [@Fohnbit](https://forum.intervals.icu/u/Fohnbit)\
**Post date:** [12 March 2026 08:12 UTC](https://forum.intervals.icu/t/api-create-or-update-workout-without-using-description-text-syntax/124215/2 "2026-03-12T08:12:42Z")

</div>

Guess I can answer my question by myself:  
I created a FIT file and uploaded. Even here interval API create the workout in the description. So it seems not possible to get a clear description with workout steps.

---

<div class="post-metadata">

**Author:** ![mreno](https://forum.intervals.icu/letter_avatar_proxy/v4/letter/m/ecc23a/32.png) [@mreno](https://forum.intervals.icu/u/mreno)\
**Post date:** [11 August 2026 21:23 UTC](https://forum.intervals.icu/t/api-create-or-update-workout-without-using-description-text-syntax/124215/3 "2026-08-11T21:23:16Z")

</div>

Did you upload using API or intervals UI?

---

<div class="post-metadata">

**Author:** ![mreno](https://forum.intervals.icu/letter_avatar_proxy/v4/letter/m/ecc23a/32.png) [@mreno](https://forum.intervals.icu/u/mreno)\
**Post date:** [11 August 2026 22:36 UTC](https://forum.intervals.icu/t/api-create-or-update-workout-without-using-description-text-syntax/124215/4 "2026-08-11T22:36:59Z")

</div>

I tried this:

marcosreno@MBAReno backend % curl -X POST \

“[https://intervals.icu/api/v1/athlete/i611360/events/bulk?upsert=true](https://intervals.icu/api/v1/athlete/i611360/events/bulk?upsert=true)” \

-u “API\_KEY:$TOKEN” \

-H “Content-Type: application/json” \

-d '[

{

```
"category": "WORKOUT",

"start_date_local": "2026-08-17T00:00:00",

"type": "Run",

"name": "TEST 2x1km Pace Range V2",

"description": "- 10m 5:30-6:16/km Pace\\n\\n2x\\n- 1km 3:30-3:50/km Pace\\n- 2m 5:10-6:00/km Pace\\n\\n- 10m 5:30-6:16/km Pace",

"external_id": "limiar-2x1km-pace-002"

```

}

]’

[{“id”:128751902,“start\_date\_local”:“2026-08-17T00:00:00”,“icu\_training\_load”:null,“icu\_atl”:null,“icu\_ctl”:null,“type”:“Run”,“carbs\_used”:null,“ss\_p\_max”:null,“ss\_w\_prime”:null,“ss\_cp”:null,“calendar\_id”:1,“uid”:“01263f45-93f2-42bf-bee2-872fdcede371”,“athlete\_id”:“i611360”,“category”:“WORKOUT”,“end\_date\_local”:“2026-08-18T00:00:00”,“name”:“TEST 2x1km Pace Range V2”,“description”:“- 10m 5:30-6:16/km Pace\n\n2x\n- 1km 3:30-3:50/km Pace\n- 2m 5:10-6:00/km Pace\n\n- 10m 5:30-6:16/km Pace”,“indoor”:null,“color”:null,“moving\_time”:1880,“icu\_ftp”:null,“w\_prime”:null,“p\_max”:null,“atl\_days”:null,“ctl\_days”:null,“updated”:“2026-08-11T22:28:09.608+00:00”,“not\_on\_fitness\_chart”:false,“show\_as\_note”:false,“show\_on\_ctl\_line”:false,“for\_week”:false,“target”:null,“joules”:null,“joules\_above\_ftp”:null,“workout\_doc”:{“steps”:[{“pace”:{“end”:376,“start”:330,“units”:“secs/km”},“duration”:600},{“reps”:2,“text”:“2x”,“steps”:[{“pace”:{“end”:230,“start”:210,“units”:“secs/km”},“distance”:1000,“duration”:220},{“pace”:{“end”:360,“start”:310,“units”:“secs/km”},“duration”:120}],“distance”:2720.430107526882,“duration”:680},{“pace”:{“end”:376,“start”:330,“units”:“secs/km”},“duration”:600}],“locales”:[],“options”:{},“distance”:6134.356606559764,“duration”:1880,“strain\_score”:null,“average\_watts”:0,“normalized\_power”:0,“variability\_index”:null,“polarization\_index”:null},“push\_errors”:null,“athlete\_cannot\_edit”:false,“hide\_from\_athlete”:false,“structure\_read\_only”:false,“created\_by\_id”:“i611360”,“shared\_event\_id”:null,“entered”:false,“carbs\_per\_hour”:null,“sub\_type”:null,“distance”:6134.3564,“tags”:null,“attachments”:null,“oauth\_client\_id”:null,“external\_id”:“limiar-2x1km-pace-002”,“load\_target”:null,“time\_target”:null,“distance\_target”:null,“training\_availability”:“NORMAL”,“max\_training\_time”:null,“can\_train\_sports”:null,“plan\_athlete\_id”:null,“plan\_folder\_id”:null,“plan\_workout\_id”:null,“plan\_applied”:null,“icu\_intensity”:null,“strain\_score”:null,“plan\_name”:null}] **%** marcosreno@MBAReno backend % curl \

“[https://intervals.icu/api/v1/athlete/i611360/events/128751902](https://intervals.icu/api/v1/athlete/i611360/events/128751902)” \

-u “API\_KEY:$TOKEN”

{“id”:128751902,“start\_date\_local”:“2026-08-17T00:00:00”,“icu\_training\_load”:null,“icu\_atl”:null,“icu\_ctl”:null,“type”:“Run”,“carbs\_used”:null,“ss\_p\_max”:null,“ss\_w\_prime”:null,“ss\_cp”:null,“calendar\_id”:1,“uid”:“01263f45-93f2-42bf-bee2-872fdcede371”,“athlete\_id”:“i611360”,“category”:“WORKOUT”,“end\_date\_local”:“2026-08-18T00:00:00”,“name”:“TEST 2x1km Pace Range V2”,“description”:“- 10m 5:30-6:16/km Pace\n\n2x\n- 1km 3:30-3:50/km Pace\n- 2m 5:10-6:00/km Pace\n\n- 10m 5:30-6:16/km Pace”,“indoor”:null,“color”:null,“moving\_time”:1880,“icu\_ftp”:null,“w\_prime”:null,“p\_max”:null,“atl\_days”:null,“ctl\_days”:null,“updated”:“2026-08-11T22:28:09.608+00:00”,“not\_on\_fitness\_chart”:false,“show\_as\_note”:false,“show\_on\_ctl\_line”:false,“for\_week”:false,“target”:null,“joules”:null,“joules\_above\_ftp”:null,“workout\_doc”:{“steps”:[{“pace”:{“end”:376,“start”:330,“units”:“secs/km”},“duration”:600},{“reps”:2,“text”:“2x”,“steps”:[{“pace”:{“end”:230,“start”:210,“units”:“secs/km”},“distance”:1000,“duration”:220},{“pace”:{“end”:360,“start”:310,“units”:“secs/km”},“duration”:120}],“distance”:2720.430107526882,“duration”:680},{“pace”:{“end”:376,“start”:330,“units”:“secs/km”},“duration”:600}],“locales”:[],“options”:{},“distance”:6134.356606559764,“duration”:1880,“strain\_score”:null,“average\_watts”:0,“normalized\_power”:0,“variability\_index”:null,“polarization\_index”:null},“push\_errors”:null,“athlete\_cannot\_edit”:false,“hide\_from\_athlete”:false,“structure\_read\_only”:false,“created\_by\_id”:“i611360”,“shared\_event\_id”:null,“entered”:false,“carbs\_per\_hour”:null,“sub\_type”:null,“distance”:6134.3564,“tags”:null,“attachments”:null,“oauth\_client\_id”:null,“external\_id”:“limiar-2x1km-pace-002”,“load\_target”:null,“time\_target”:null,“distance\_target”:null,“training\_availability”:“NORMAL”,“max\_training\_time”:null,“can\_train\_sports”:null,“plan\_athlete\_id”:null,“plan\_folder\_id”:null,“plan\_workout\_id”:null,“plan\_applied”:null,“icu\_intensity”:null,“strain\_score”:null,“plan\_name”:null} **%** marcosreno@MBAReno backend %

The `workout_doc` looks correct. However, when I open the workout on my Garmin, I only see the duration. The pace range is missing. Is the `pace` field in `workout_doc` supposed to be converted to a pace target when the workout is pushed to Garmin? The same problem when upload a FIT file.
