Core Concepts
Workout Structure
A workout template is a hierarchy of blocks and steps:
WorkoutTemplate
├── name: "FTP Intervals"
├── sport: "cycling"
├── environment: "outdoor" (optional: indoor, outdoor, pool)
├── description: "Build threshold power"
├── pool_length_meters: null (only for swimming)
├── estimated_duration_seconds: 1800 (optional)
├── estimated_distance_meters: null (optional)
├── estimated_calories: null (optional)
├── estimated_tss: null (optional, 0-9999)
├── estimated_intensity_factor: null (optional, 0-5)
│
└── step_blocks: [
StepBlock {
completion_condition: { type: "reps", value: 4 } ← Repeat 4 times
steps: [
WorkoutStep { ... }, ← Do this
WorkoutStep { ... } ← Then this
]
}
]Step Blocks
A step block groups one or more steps that execute together. The block's completion_condition controls repetition:
{ "type": "reps", "value": 4 }
Repeat all steps 4 times
{ "type": "time", "value": 1200 }
Repeat until 20 minutes total
{ "type": "distance", "value": 5000 }
Repeat until 5km total
{ "type": "open" } or omitted
Execute once (no repeat)
Example: 4x400m Intervals
This creates: 400m fast → 200m easy → 400m fast → 200m easy → 400m fast → 200m easy → 400m fast → 200m easy
Workout Steps
Each step defines:
completion_condition
Yes
When this step ends
intensity_type
Yes
How hard (warmup/active/rest/recovery/cooldown)
intensity_targets
No
Target metrics (HR, power, pace, etc.)
notes
No
Text shown to athlete
controls
No
Equipment settings held during the step: grade or resistance
strength
No
Exercise details for strength training
swimming
No
Stroke/equipment for swimming
Completion Conditions
How a step (or block) ends:
time
Seconds
End after duration (e.g., 300 = 5 minutes)
distance
Meters
End after distance (e.g., 1000 = 1km)
reps
Count
End after N repetitions
calories
kcal
End after calories burned
open
—
Manual end (lap button)
hr_less_than
BPM
End when HR drops below
hr_greater_than
BPM
End when HR rises above
power_less_than
Watts
End when power drops below
power_greater_than
Watts
End when power rises above
Example: Recovery Until HR Drops
Intensity Types
warmup
Warmup
Gradual start
active
Work / Interval
Main effort
rest
Rest
Full stop between intervals
recovery
Recovery
Easy effort between intervals
cooldown
Cooldown
Gradual end
Intensity Targets
Targets define the goal metric for a step. You can have multiple targets per step (provider-dependent).
Target Types
Absolute Targets:
heart_rate
BPM
150-160 BPM
All except Hevy
power
Watts
250-280W
All except Huawei and Hevy
speed
m/s
4.0-4.5 m/s
All except Hevy
pace
sec/km
270-300 sec/km (4:30-5:00/km)
All except Hevy
cadence
rpm or spm
170-180 spm
All except Hevy (Zepp: secondary only)
rpe
1-10
7-8 RPE
Wahoo, TrainingPeaks only
Percentage Targets (require athlete parameters at scheduling):
heart_rate_max_percentage
max_heart_rate
80-85% of max HR
heart_rate_threshold_percentage
threshold_heart_rate
95-100% of threshold
power_percentage
ftp
90-95% of FTP
speed_percentage
threshold_speed
85-90% of threshold pace
Zone Targets (device-configured zones):
heart_rate_zone
1-5
All except Hevy (Garmin native, others convert to BPM or %). Uses threshold HR (COROS, Zepp) or max HR (others) as baseline
power_zone
1-7
All except Huawei and Hevy (Garmin native, others convert to % FTP or watts)
Target Value Formats
Targets support single values or ranges. Percentage targets (heart_rate_max_percentage, heart_rate_threshold_percentage, power_percentage, speed_percentage) must use value_low and/or value_high: an exact value is rejected with a 400. Expanding a single value into a range also returns a coercion warning.
Sport Types
running
Running
All except Hevy
cycling
Cycling
All except Huawei and Hevy
swimming
Swimming
Garmin, COROS, Suunto, TrainingPeaks, Zepp, Apple
strength
Weight training
Garmin, COROS, Suunto, TrainingPeaks, Apple, Hevy
rowing
Rowing
TrainingPeaks, Apple
yoga
Yoga
Garmin, Apple
pilates
Pilates
Garmin only
cardio
General cardio
Garmin only
trail_running
Trail running
Garmin, COROS, Wahoo, Suunto, Zepp
mountain_biking
Mountain biking
Garmin, Wahoo, Suunto, TrainingPeaks
backcountry_skiing
Backcountry / ski touring
Garmin, Suunto
hiking
Hiking
Garmin, Suunto
walking
Walking
Garmin, Suunto, TrainingPeaks
elliptical
Elliptical
Garmin
stair_climbing
Stair climbing
None native, coerced with a warning
Unsupported sport types are coerced to the provider's closest equivalent with a coercion warning. See Provider Compatibility for details.
Environment (Optional)
Use the environment field to distinguish indoor/outdoor variants:
indoor
Indoor (treadmill, stationary bike, etc.)
outdoor
Outdoor
pool
Pool swimming
If omitted, the provider uses its default. Examples:
Workout Estimates (Optional)
Estimates describe the workout as a whole, not a single step. All five are optional.
estimated_duration_seconds
Seconds
Planned total time
estimated_distance_meters
Meters
Planned total distance
estimated_calories
kcal
Planned energy
estimated_tss
0-9999
Planned Training Stress Score
estimated_intensity_factor
0-5
Planned Intensity Factor
Terra forwards all five to TrainingPeaks when the workout is scheduled or rescheduled, and returns them on workouts read back from any provider that exposes them.
TrainingPeaks derives TSS, Intensity Factor and duration from the athlete's own thresholds whenever any step target is not RPE. Your values are ignored in that case, and Terra returns coercion warnings on workout.estimated_tss, workout.estimated_intensity_factor and workout.estimated_duration_seconds. Distance and calories are always forwarded.
An estimated_tss outside 0-9999, or an estimated_intensity_factor outside 0-5, is rejected when the template is created.
Complete Example
A 30-minute cycling workout with warmup, FTP intervals, and cooldown:
Reading Workouts Back
GET /plannedWorkouts?user_id=X returns this same structure. Every item carries the workout body under workout: name, sport, step_blocks and estimates, whether you scheduled it through Terra or the athlete created it on the provider.
Provider-created workouts are marked is_external: true, have no workout_id, and are listed for Garmin, Wahoo, Suunto, TrainingPeaks and Intervals.icu. Their sport is unspecified when the provider's sport has no Terra equivalent. warnings lists anything that could not be represented exactly when the provider's workout was read into this structure. Repeat blocks are preserved.
Intervals.icu is read-only for planned workouts: workouts created there are listed, but Terra cannot push workouts to it.
Without start_date and end_date, provider-created workouts default to the trailing 30 days. Pass an explicit window to list upcoming workouts. When the provider cannot be read the response is still a 200 carrying the workouts Terra scheduled, with X-Terra-Provider-Data-Truncated: true and X-Terra-Provider-Fetch giving the reason.
Validation Rules
Templates are validated when created. Key rules:
name
Required, non-empty
sport
Required, must be a valid sport type
step_blocks
At least one block required
Each block
At least one step required
Each step
intensity_type required (warmup, active, rest, recovery, cooldown)
Each step
completion_condition defaults to open if omitted
pool_length_meters
Only allowed for swimming workouts
value_low / value_high
Cannot use both value and value_low/value_high on the same target
Range targets
value_low must be strictly less than value_high
Athlete metrics
All values must be positive if provided (ftp, max_heart_rate, threshold_heart_rate, threshold_speed, pool_length_meters)
planned_date
Format: YYYY-MM-DD
estimated_tss
Between 0 and 9999 if provided
estimated_intensity_factor
Between 0 and 5 if provided
Percentage targets
Must use value_low and/or value_high, not value
Target value sanity checks. A value outside these ranges is rejected with a 400 when the template is created:
Heart rate (BPM)
30–250
Power (watts)
1–2000
Speed (m/s)
0–15
Pace (sec/km)
1–7200
Cadence (rpm/spm)
1–300
RPE
1–10
Percentage targets
0–200%
Last updated
Was this helpful?