> 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/athlete-parameters.md).

# Athlete Parameters

### Overview

Athlete parameters are provided when scheduling a workout to a specific user. They give Terra the baseline it needs to express your targets on each provider: percentage targets become absolute values where the provider only accepts absolute numbers, and absolute heart rate and power targets become percentages on TrainingPeaks.

**Key concept:** Templates are generic. Athlete parameters are applied at scheduling time.

Athlete parameters apply only to workouts you schedule through Terra. Workouts created on the provider side, returned by `GET /plannedWorkouts` with `is_external: true`, already carry the provider's own targets and are not personalised. Intervals.icu is read only for planned workouts, so it takes no scheduled workouts and no athlete parameters.

### Parameters

| Parameter              | Unit   | Used By                                   |
| ---------------------- | ------ | ----------------------------------------- |
| `max_heart_rate`       | BPM    | `heart_rate_max_percentage` targets       |
| `threshold_heart_rate` | BPM    | `heart_rate_threshold_percentage` targets |
| `ftp`                  | Watts  | `power_percentage` targets                |
| `threshold_speed`      | m/s    | `speed_percentage` targets                |
| `pool_length_meters`   | Meters | Swimming workouts (overrides template)    |

### When Parameters Are Required

| Target Type                       | Required Parameter     | What Happens Without It                                                                                      |
| --------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------ |
| `heart_rate_max_percentage`       | `max_heart_rate`       | Falls back to 190 BPM, with a coercion warning                                                               |
| `heart_rate_threshold_percentage` | `threshold_heart_rate` | Falls back to 170 BPM, with a coercion warning                                                               |
| `power_percentage`                | `ftp`                  | Falls back to 200 W, with a coercion warning                                                                 |
| `speed_percentage`                | `threshold_speed`      | Falls back to 3.33 m/s, with a coercion warning                                                              |
| `heart_rate` (absolute BPM)       | `max_heart_rate`       | TrainingPeaks only: falls back to the athlete's TrainingPeaks profile, then 190 BPM, with a coercion warning |
| `power` (absolute watts)          | `ftp`                  | TrainingPeaks only: falls back to the athlete's TrainingPeaks profile, then 200 W, with a coercion warning   |

Fallbacks apply only where the provider needs the baseline. Garmin and TrainingPeaks take heart rate and power percentages directly, so those targets are sent unchanged and the parameter is not used (Garmin still needs `threshold_speed` for `speed_percentage`). The other providers either resolve the percentage against the baseline or carry the baseline alongside the workout so the device can.

### Example: One Template, Two Athletes

#### Create Template (once)

```json
POST /workouts
{
  "name": "Threshold Intervals",
  "sport": "cycling",
  "step_blocks": [{
    "completion_condition": { "type": "reps", "value": 3 },
    "steps": [{
      "completion_condition": { "type": "time", "value": 600 },
      "intensity_type": "active",
      "intensity_targets": [{
        "target_type": "power_percentage",
        "value_low": 95,
        "value_high": 100
      }]
    }]
  }]
}
```

Response: `{ "status": "success", "workout_id": "123" }`

#### Schedule to Athlete A (FTP: 200W)

```json
POST /workouts/123/plan?user_id=athlete_a
{
  "planned_date": "2026-02-10",
  "ftp": 200
}
```

**Result on device:** 3x10min @ 190-200W

#### Schedule to Athlete B (FTP: 300W)

```json
POST /workouts/123/plan?user_id=athlete_b
{
  "planned_date": "2026-02-10",
  "ftp": 300
}
```

**Result on device:** 3x10min @ 285-300W

These results assume a provider that needs the baseline. Garmin and TrainingPeaks receive 95-100% as a percentage, and the athlete's own FTP on the device or in their TrainingPeaks profile sets the watts.

### Conversion Formulas

```
Absolute HR (max %)       = Percentage × max_heart_rate / 100
Absolute HR (threshold %) = Percentage × threshold_heart_rate / 100
Absolute Power            = Percentage × ftp / 100
Absolute Speed            = Percentage × threshold_speed / 100
```

#### Example Conversion

Template target: `heart_rate_max_percentage` @ 80-85% Athlete's `max_heart_rate`: 190 BPM

```
Low:  80% × 190 = 152 BPM
High: 85% × 190 = 162 BPM
```

Device shows: 152-162 BPM

### Heart Rate Zones vs Percentages

| Approach                          | When to Use                      |
| --------------------------------- | -------------------------------- |
| `heart_rate_zone` (1-5)           | Device has preconfigured zones   |
| `heart_rate_max_percentage`       | You know user's max HR           |
| `heart_rate_threshold_percentage` | You know user's threshold HR     |
| `heart_rate` (absolute BPM)       | You've pre-calculated the values |

Zone targets are native only on Garmin and Apple. On every other provider Terra expands the zone to a percentage band first, then resolves it against a baseline: threshold HR on COROS and Zepp, max HR on Suunto, Wahoo, TrainingPeaks and Huawei, and FTP for power zones. Send `max_heart_rate`, `threshold_heart_rate` or `ftp` with zone targets too, or the same default baselines apply.

### Pool Length

For swimming workouts, `pool_length_meters` can be set in either:

1. **Template** - Default pool length for the workout
2. **Schedule request** - Override for specific user/pool

```json
// Template with default pool length
POST /workouts
{
  "name": "Swim Intervals",
  "sport": "swimming",
  "environment": "pool",
  "pool_length_meters": 25,
  "step_blocks": [...]
}

// Override for 50m pool
POST /workouts/456/plan?user_id=X
{
  "planned_date": "2026-02-10",
  "pool_length_meters": 50
}
```

### Best Practices

1. **Always provide required parameters** - Prevents coercion warnings
2. **Store athlete parameters in your app** - Fetch max HR, FTP from user profile
3. **Use percentage targets for personalization** - Same template works for all fitness levels
4. **Use absolute targets for fixed workouts** - When everyone should hit the same number
