> For the complete documentation index, see [llms.txt](https://docs.tryterra.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tryterra.co/planned-workouts-api/provider-compatibility.md).

# Provider compatibility

## Provider Compatibility

Not all providers support all features. This guide helps you understand what works where.

### Handling Unsupported Features

When a feature isn't supported, Terra returns a **coercion warning** but still creates the workout:

```json
{
  "status": "success",
  "planned_workout_id": "12345",
  "provider_workout_id": "987654321",
  "warnings": [
    {
      "path": "step_blocks[0].steps[0].intensity_targets",
      "message": "Secondary targets not supported for this sport"
    }
  ]
}
```

`coercion_warnings` carries the same list and is deprecated. Read `warnings`. See [Coercion Warnings](/planned-workouts-api/coercion-warnings.md) for details.

### Operations Support

Not all providers support all operations. The table below shows what each provider supports for creating, updating, retrieving, and deleting planned workouts.

| Operation    | Garmin | COROS | Wahoo | Suunto | TrainingPeaks | Huawei | Zepp | Hevy | Apple | Intervals.icu |
| ------------ | ------ | ----- | ----- | ------ | ------------- | ------ | ---- | ---- | ----- | ------------- |
| **Create**   | ✓      | ✓     | ✓     | ✓      | ✓             | ✓      | ✓    | ✓    | ✓     | —             |
| **Update**   | ✓      | ✓\*   | ✓     | ✓      | ✓             | —†     | ✓§   | —    | ✓     | —             |
| **Retrieve** | ✓‡     | —     | ✓     | ✓      | ✓             | —      | —    | —‖   | —     | ✓             |
| **Delete**   | ✓      | ✓     | ✓     | ✓      | ✓             | —      | ✓    | —    | ✓     | —             |

\*COROS does not support in-place updates. Updates are performed by deleting the old workout and creating a new one.

†Huawei does not support updating workout content on the device. When you update a Huawei planned workout, only the planned date changes on Terra's copy. The workout on the device remains unchanged.

‡Garmin only returns workouts that were created by your application's API credentials. Workouts created by other apps or directly on the device will not appear.

§Zepp uses a 7-day sync window. Updates replace all workouts within the current window on the device.

‖Hevy routines are a library, not a calendar. They carry no date, so they are not planned workouts and never appear in the list. A workout pushed to Hevy becomes a routine, and its date is kept only on Terra's copy.

Intervals.icu is read only for planned workouts. Terra lists the athlete's Intervals.icu calendar workouts but cannot create, update or delete them. The athlete connects by entering their Intervals.icu API key on Terra's login screen, the same flow as Hevy.

**When an operation is not supported**, the API still returns a success response. For deletes, the workout is removed from Terra but remains on the user's device.

### Retrieving planned workouts

`GET /v2/plannedWorkouts` returns the workouts you created through Terra and the workouts the athlete created on the provider, where the provider exposes them. Every item has the same shape: `workout` holds the full body (name, sport, step blocks, estimates), `warnings` lists any adjustment made while reading it, and `planned_date` is always set. Provider-created items have `is_external: true` and no `workout_id`, so they cannot be rescheduled or deleted through Terra. A workout you pushed through Terra that the provider echoes back is listed once, as the Terra item.

Provider-created workouts are read from the provider on every call, so the response carries two headers:

| Header                            | Meaning                                                                                                                                                                                                           |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `X-Terra-Provider-Fetch`          | Outcome of the provider read: `ok`, `skipped`, `rate_limited`, `unauthorized`, `unavailable`, `timeout` or `failed`. `skipped` means the provider does not expose planned workouts, or the add-on is not enabled. |
| `X-Terra-Provider-Data-Truncated` | `true` when provider-created workouts could not be included. The response is still 200 and still contains the workouts you created through Terra.                                                                 |

`start_date` and `end_date` set the planned-date window and both ends are inclusive. If you omit both, provider-created workouts default to the trailing 30 days, so pass an explicit window to list upcoming workouts. Workouts you created through Terra are not windowed when the dates are omitted.

### Quick Reference

<table><thead><tr><th width="128">Feature</th><th align="center">Garmin</th><th align="center">COROS</th><th align="center">Wahoo</th><th align="center">Suunto</th><th align="center">TrainingPeaks</th><th align="center">Huawei</th><th align="center">Zepp</th><th>Hevy</th><th>Apple</th></tr></thead><tbody><tr><td><strong>Sports</strong></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td></td><td></td></tr><tr><td>Running</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td>—</td><td>✓</td></tr><tr><td>Cycling</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td>—</td><td>✓</td></tr><tr><td>Swimming</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td>—</td><td>✓</td></tr><tr><td>Strength</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td>✓</td><td>✓</td></tr><tr><td>Trail Running</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td>—</td><td>—</td></tr><tr><td>Mountain Biking</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td>—</td><td>—</td></tr><tr><td>Backcountry Skiing</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td>—</td><td>—</td></tr><tr><td><strong>Targets</strong></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td></td><td></td></tr><tr><td>Heart Rate (BPM)</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓*</td><td align="center">✓</td><td align="center">✓</td><td>—</td><td>✓</td></tr><tr><td>HR % of Max</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓*</td><td align="center">✓</td><td align="center">✓*</td><td align="center">✓*</td><td>—</td><td>✓</td></tr><tr><td>HR % of Threshold</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓*</td><td align="center">✓</td><td align="center">✓*</td><td align="center">✓*</td><td>—</td><td>✓</td></tr><tr><td>HR Zones</td><td align="center">✓</td><td align="center">✓†</td><td align="center">✓†</td><td align="center">✓†</td><td align="center">✓†</td><td align="center">✓†</td><td align="center">✓†</td><td>—</td><td>✓</td></tr><tr><td>Power (Watts)</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓*</td><td align="center">—</td><td align="center">✓</td><td>—</td><td>✓</td></tr><tr><td>Power % FTP</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓*</td><td align="center">✓</td><td align="center">—</td><td align="center">✓*</td><td>—</td><td>✓</td></tr><tr><td>Power Zones</td><td align="center">✓</td><td align="center">✓†</td><td align="center">✓†</td><td align="center">✓†</td><td align="center">✓†</td><td align="center">—</td><td align="center">✓†</td><td>—</td><td>✓</td></tr><tr><td>Pace</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓*</td><td align="center">✓</td><td align="center">✓</td><td>—</td><td>✓</td></tr><tr><td>Speed</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓*</td><td align="center">✓</td><td align="center">✓</td><td>—</td><td>✓</td></tr><tr><td>Cadence</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓¶</td><td>—</td><td>✓</td></tr><tr><td>RPE</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td>—</td><td>—</td></tr><tr><td><strong>Completion</strong></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td></td><td></td></tr><tr><td>Time</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td>✓</td><td>✓</td></tr><tr><td>Distance</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td>✓</td><td>✓</td></tr><tr><td>Reps</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td>✓</td><td>—</td></tr><tr><td>Calories</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td>—</td><td>✓</td></tr><tr><td>HR Trigger</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td>—</td><td>—</td></tr><tr><td>Power Trigger</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td>—</td><td>—</td></tr><tr><td><strong>Structure</strong></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td><td></td><td></td></tr><tr><td>Multiple targets/step</td><td align="center">✓ (2, cycling/swimming)</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">✓ (1+cadence)</td><td>—</td><td>—</td></tr><tr><td>Block repeats</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td>—</td><td>✓</td></tr><tr><td>Exercise names</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td>✓</td><td>—</td></tr><tr><td>Swim strokes</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td>—</td><td>—</td></tr></tbody></table>

\*Converted by Terra: TrainingPeaks converts absolute values to percentages using athlete profile. Suunto, Huawei, and Zepp convert percentage targets to absolute values using provided athlete parameters or defaults.

†Zone targets converted by Terra: HR zones (1-5) and power zones (1-7) are converted to each provider's native format. HR zones use **threshold HR** as baseline for COROS and Zepp, and **max HR** for Wahoo, TrainingPeaks, Suunto, and Huawei. Power zones use FTP for all providers that support them. Output format varies: percentage (COROS, Wahoo, TrainingPeaks) or absolute BPM/watts (Suunto, Huawei, Zepp).

¶Cadence only supported as a secondary target on Zepp. Must be paired with a primary target (heart rate, power, pace, or speed).

### Provider Details

#### Garmin

**Most complete support.** Garmin devices handle nearly all workout features. Supports create, update, retrieve, and delete.

**Strengths:**

* Full strength training with exercise categories
* Swimming with stroke types and equipment
* Up to 2 targets per step (cycling/swimming)
* HR and power trigger completions
* All completion condition types

**Limitations:**

* Time-based steps inside time-based repeat blocks get unwrapped
* Exercise names must match Garmin's catalog (see Exercise Reference)
* Only one equipment item per swimming step: if multiple are provided, the first is used and a coercion warning is returned
* **Retrieve only returns workouts created by your app**: workouts created by other apps or directly on the device will not appear

**Special behaviors:**

* Single values get ±5% range applied
* HR threshold percentage converts to max HR percentage with warning
* Pool length defaults to 25m if not provided

***

#### COROS

**Good support for endurance sports.** Supports create, update (via delete + recreate), and delete. Does not support retrieve.

**Strengths:**

* Running, cycling, swimming, strength
* HR and power percentage targets
* Equipment encoded in step names

**Limitations:**

* Single target per step only (extras ignored)
* Block completion only supports REPS
* No HR/power trigger completions
* Drill stroke type not supported
* **No retrieve support**: the COROS API does not provide an endpoint to fetch existing workouts

**Special behaviors:**

* Single values get ±5% range applied
* Weight converted to grams internally
* Stroke/equipment added to step name in brackets
* Updates delete the old workout and create a new one (the provider\_workout\_id will change)

***

#### Wahoo

**Focused on cycling and running.**

**Strengths:**

* Excellent power zone support
* RPE targets
* Multiple targets per step
* Grade control for smart trainers

**Limitations:**

* No swimming support
* No strength training

**Special behaviors:**

* Percentage targets divided by 100 for API
* Single values expanded ±5%
* Steps without intensity targets get RPE fallback coercion
* Only plan-backed workouts are planned workouts. Sessions the athlete recorded on a Wahoo device have no plan attached and are not returned by the list endpoint
* On the list, a Wahoo gym workout is reported as sport `strength` and a Wahoo cardio workout as `cardio`

***

#### Suunto

**Solid multi-sport support.**

**Strengths:**

* Wide sport type support
* Swimming with stroke metadata
* Strength with exercise text
* Percentage targets converted to absolute values using athlete parameters

**Limitations:**

* Single target per step
* No controls support
* Step names truncated to 13 characters
  * Descriptions truncated to 23 characters

**Special behaviors:**

* Cadence converted from RPM to Hz (÷60)
* Manual lap trigger for open/reps completion
* Percentage targets (HR %, power %, speed %) resolved to absolute values using provided athlete parameters or defaults

***

#### TrainingPeaks

**Training platform integration.**

**Strengths:**

* RPE support
* All sports including triathlon
* Integrates with athlete profile for conversions

**Limitations:**

* Single target per step
* No stroke type support

**Special behaviors:**

* Absolute HR converted to % using athlete's max HR from request, then TrainingPeaks profile, then defaults
* Absolute power converted to % using athlete's FTP from request, then TrainingPeaks profile, then defaults
* Reps estimated as 4 sec/rep (minimum 30 sec)
* Missing profile data falls back to defaults with coercion warning
* `estimated_tss`, `estimated_intensity_factor`, `estimated_distance_meters` and `estimated_calories` are sent to TrainingPeaks on create and on update
* TrainingPeaks ignores TSS, intensity factor and duration when any step target is not RPE: it derives them from the athlete's thresholds instead. Terra returns coercion warnings on `workout.estimated_tss`, `workout.estimated_intensity_factor` and `workout.estimated_duration_seconds` when that happens
* `estimated_tss` must be between 0 and 9999 and `estimated_intensity_factor` between 0 and 5. Outside those ranges the workout is rejected with a 400

***

#### Huawei

**Running workouts only.** Supports create only. Does not support update, retrieve, or delete on the device.

**Strengths:**

* Heart rate targets (absolute BPM, max %, threshold %, zones)
* Pace and speed targets (converted to milliseconds per kilometer)
* Cadence targets (as "steps rate")
* Calorie-based completion conditions
* Block repeats via ActionCombine

**Limitations:**

* Running only: other sports get a coercion warning and appear as a run
* No power targets (running-only device)
* Single target per step (first prioritized target used)
* No strength or swimming support
* **No retrieve support**: the Huawei API does not provide an endpoint to fetch existing workouts
* **No delete support**: the Huawei API does not provide a delete endpoint. Deleting from Terra removes the record from Terra but the workout remains on the user's device
* **No update support**: updates only change the planned date on Terra's copy. The workout on the device is not modified
* **No planned date support**: Huawei does not support scheduling workouts for a specific date. The workout will be available on the device immediately regardless of the `planned_date` value. A coercion warning is always returned noting this.

**Special behaviors:**

* Pace stored as milliseconds per kilometer internally
* HR zones converted to absolute BPM via max HR
* Cooldown and Recovery both map to Huawei's "Relax" action with coercion warning
* Single values expanded ±5%
* Step-level reps converted to separate repeating ActionCombine blocks
* Huawei enforces unique workout names per user: duplicate names return a 400 error
* Huawei may return a 500 "createWorkout error" but still create the workout. When this happens, `provider_workout_id` will be empty and a coercion warning is returned

***

#### Zepp

**Endurance sports with a sync window constraint.** Supports create, update, and delete. Does not support retrieve.

**Strengths:**

* Running, cycling, and swimming support
* Full heart rate and power target coverage including zones and percentages
* Cadence as a secondary target alongside a primary target
* Block repeats
* Pace targets automatically converted from sec/km to m/s

**Limitations:**

* No strength training
* No swim stroke types (ignored with coercion warning)
* No equipment weight targets (ignored with coercion warning)
* No controls support
* **No retrieve support**: the Zepp API does not provide an endpoint to fetch existing workouts
* **7-day sync window**: workouts only appear on the device when scheduled within the next 7 days (today to today + 6 days). Workouts outside this window are kept by Terra but are NOT automatically pushed to the device. They will only be synced when a subsequent write or delete operation for that user triggers a window refresh. To ensure delivery, schedule workouts within the window or trigger a sync by writing/deleting any workout for the user once the date falls within range

**Special behaviors:**

* Full window replacement: every write or delete re-syncs the entire 7-day window to Zepp
* Out-of-window workouts return a coercion warning but are still kept by Terra
* Unsupported sports default to RUNNING with coercion warning
* Missing completion conditions default to 60 seconds
* Cadence only supported as a secondary target: if provided as the only target, a warning is returned
* Step-level reps are wrapped in repeat blocks
* Single values expanded ±5%

***

**Hevy**

Strength training routines only. Supports create. Does not support retrieve, update or delete on the provider.

**Strengths:**

* Full exercise name resolution: Garmin UPPER\_CASE names, Hevy display names, and short aliases all resolve to built-in Hevy template IDs
* Exercise metadata enrichment: custom exercises get correct muscle group, equipment category, and exercise type inferred from the shared exercise metadata registry
* Weight unit conversion (lbs to kg)
* Duration-based and distance-based sets alongside standard weight/reps

**Limitations:**

* Strength only: other sports are accepted but produce a coercion warning; the exercises are still pushed as a routine
* No heart rate, power, pace, speed, or cadence targets (not applicable to strength routines)
* No RPE support: RPE targets are dropped with a coercion warning
* No block repeats: each StepBlock maps to one exercise, each WorkoutStep to one set
* No planned date support: Hevy routines are a library, not a calendar. The routine appears in the user's library immediately regardless of `planned_date`, and the date is kept only on Terra's copy
* No retrieve support: because routines carry no date they are not planned workouts, so they never appear in `GET /v2/plannedWorkouts`
* No delete support: deleting from Terra removes the record from Terra, but the routine remains in the user's Hevy account
* No update support: because routines are not tied to a planned date, updating the planned date has no effect on the provider side

**Special behaviors:**

* If the user's Hevy account hits the custom exercise limit, a 403 is returned per exercise with a coercion warning. The routine is still created with the remaining exercises
* Muscle group for custom exercises is inferred from the exercise name via the Garmin exercise→category mapping (e.g. "Bench Press" → BENCH\_PRESS → chest)

***

**Apple**

Workouts are delivered through the Terra iOS SDK. Terra holds the planned workout until the app next runs, then the SDK schedules it in Apple WorkoutKit and confirms delivery.

**Strengths:**

* Heart rate targets (absolute BPM, % of max, % of threshold, zones)
* Power targets (absolute watts, % of FTP, zones)
* Pace and speed targets
* Cadence targets
* Calorie-based completion conditions
* Block repeats via IntervalBlock iterations

**Limitations:**

* Single target per step: if multiple intensity targets are provided, only the first is used and a coercion warning is returned
* Single warmup and single cooldown per workout: Apple WorkoutKit only supports one of each. Additional warmup or cooldown blocks are dropped with a coercion warning
* No exercise names: WorkoutKit steps are defined by goals and alerts, not exercise names. Strength workouts are limited to timed interval blocks, not structured sets/reps
* No swim stroke types
* No RPE targets
* No multiple targets per step
* No retrieve support: Apple does not expose a server-side API to read scheduled workouts from WorkoutKit

**Special behaviors:**

* `provider_workout_id` is null until the SDK has scheduled the workout on the device. Once it has, the field holds the WorkoutKit identifier
* Unsupported sports (pilates, cardio, trail running, mountain biking, backcountry skiing) are mapped to the closest Apple activity with a coercion warning

***

**Intervals.icu**

Read only. Terra lists the athlete's planned workouts from their Intervals.icu calendar. Terra cannot create, update or delete them.

**Strengths:**

* Structured workouts with power, heart rate, pace and cadence targets, including zone targets
* Repeat groups are preserved
* Planned duration, distance, TSS and intensity factor are returned as workout estimates

**Limitations:**

* No create, update or delete: `POST /workouts/{workout_id}/plan` is not available for Intervals.icu connections
* Repeat groups are only nested when the workout text uses Intervals.icu's documented syntax, which needs a blank line before and after the `3x` line. Written any other way, Intervals.icu parses the group as plain steps and Terra returns them flat
* Pace zone targets are dropped with a coercion warning when the athlete has no threshold pace set
* One level of repeat nesting: a repeat inside a repeat is flattened with a coercion warning

**Connecting:** the athlete enters their Intervals.icu API key on Terra's login screen, the same flow as Hevy. There is no OAuth redirect.

***

### Best Practices

1. **Design for Garmin first** - Most complete support
2. **Use percentage targets** - Better cross-provider compatibility
3. **Check coercion warnings** - Know what was modified
4. **Test on target devices** - Verify appearance
5. **Keep step names short** - Some providers truncate
