terra-planned-workouts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Terra API Planned Workouts

Terra API Planned Workouts

Push structured workouts directly to your users' fitness devices. Define a workout template once, and the Terra API syncs it to whatever device the user has connected: Garmin, COROS, Wahoo, Suunto, TrainingPeaks, Huawei, Zepp, Hevy, or Apple. This is a write-to-device product, the inverse of the read-focused Terra API Health & Fitness data flow.
Pre-release. This product is pre-release. Endpoints, fields, and provider behavior may change before general availability. Facts here are drawn from the Terra API docs; verify against docs.tryterra.co/planned-workouts-api before shipping.
将结构化训练计划直接推送给用户的健身设备。只需定义一次训练模板,Terra API就会将其同步到用户连接的任意设备:Garmin、COROS、Wahoo、Suunto、TrainingPeaks、华为、Zepp、Hevy或Apple设备。这是一个写入设备的产品,与以读取为主的Terra API健康与健身数据流方向相反。
预发布版本:本产品处于预发布阶段。正式发布前,端点、字段和服务商行为可能会有所变更。本文内容源自Terra API文档;上线前请务必对照docs.tryterra.co/planned-workouts-api进行验证。

When to Apply

适用场景

Reach for this skill when you are:
  • Pushing a planned or structured workout to a user's watch or bike computer
  • Building reusable workout templates or training plans in an app
  • Working with intervals, warmups, cooldowns, and repeat blocks
  • Setting HR, power, pace, speed, cadence, RPE, or zone targets
  • Personalizing one template per athlete via FTP, max HR, or threshold values
  • Handling
    coercion_warnings
    when a provider cannot represent a feature
当你遇到以下场景时,可以使用该功能:
  • 将计划好的或结构化训练推送到用户的手表或骑行码表
  • 在应用中构建可复用的训练模板或训练计划
  • 处理间歇训练、热身、放松和重复训练块
  • 设置心率、功率、配速、速度、步频、RPE或区间目标
  • 通过FTP、最大心率或阈值参数为每位运动员个性化定制训练模板
  • 处理服务商无法支持某功能时的
    coercion_warnings
    (强制转换警告)

Two-Phase Workflow

两阶段工作流程

Base URL
https://access.tryterra.co/api/v2
. Every request needs two headers:
dev-id
(your Terra developer ID) and
x-api-key
(your Terra API key).
Phase 1 – Create a template (once).
POST /workouts
with the workout structure returns a reusable
workout_id
. The template is generic: it holds structure and, where you want personalization, percentage-based targets.
Phase 2 – Schedule to a user (per athlete).
POST /workouts/{workout_id}/plan?user_id=X
applies that athlete's parameters (max HR, FTP, etc.) at scheduling time, converts percentage targets to absolute values, and pushes to the connected device. Returns a
planned_workout_id
(Terra API's ID) and a
provider_workout_id
(the device's ID).
bash
undefined
基础URL为
https://access.tryterra.co/api/v2
。每个请求都需要两个请求头:
dev-id
(你的Terra开发者ID)和
x-api-key
(你的Terra API密钥)。
阶段1——创建模板(仅需一次):向
POST /workouts
发送训练结构数据,会返回一个可复用的
workout_id
。该模板是通用的:它包含训练结构,并且在需要个性化的地方使用基于百分比的目标值。
阶段2——为用户安排训练(针对每位运动员):调用
POST /workouts/{workout_id}/plan?user_id=X
,会在安排训练时应用该运动员的参数(最大心率、FTP等),将百分比目标转换为绝对值,并推送到连接的设备。返回
planned_workout_id
(Terra API的ID)和
provider_workout_id
(设备的ID)。
bash
undefined

Phase 1: create a reusable template

Phase 1: create a reusable template

curl -X POST "https://access.tryterra.co/api/v2/workouts"
-H "Content-Type: application/json"
-H "dev-id: YOUR_DEV_ID" -H "x-api-key: YOUR_API_KEY"
-d '{ "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}] }] }] }'
curl -X POST "https://access.tryterra.co/api/v2/workouts"
-H "Content-Type: application/json"
-H "dev-id: YOUR_DEV_ID" -H "x-api-key: YOUR_API_KEY"
-d '{ "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}] }] }] }'

→ { "status": "success", "workout_id": "123" }

→ { "status": "success", "workout_id": "123" }

Phase 2: apply this athlete's FTP and push to their device

Phase 2: apply this athlete's FTP and push to their device

curl -X POST "https://access.tryterra.co/api/v2/workouts/123/plan?user_id=USER_ID"
-H "Content-Type: application/json"
-H "dev-id: YOUR_DEV_ID" -H "x-api-key: YOUR_API_KEY"
-d '{ "planned_date": "2026-02-10", "ftp": 280 }'
curl -X POST "https://access.tryterra.co/api/v2/workouts/123/plan?user_id=USER_ID"
-H "Content-Type: application/json"
-H "dev-id: YOUR_DEV_ID" -H "x-api-key: YOUR_API_KEY"
-d '{ "planned_date": "2026-02-10", "ftp": 280 }'

→ 201 { "status": "success", "planned_workout_id": "67890", "provider_workout_id": "abc123" }

→ 201 { "status": "success", "planned_workout_id": "67890", "provider_workout_id": "abc123" }


All Terra API IDs (`workout_id`, `planned_workout_id`) are serialized as JSON **strings**, because JavaScript clients lose precision on numbers past 2^53. The `plan` call returns HTTP 201 on success.

所有Terra API的ID(`workout_id`、`planned_workout_id`)都序列化为JSON字符串,因为JavaScript客户端对超过2^53的数字会丢失精度。`plan`调用成功时返回HTTP 201状态码。

Endpoints

端点

MethodEndpointDescription
POST
/workouts
Create a workout template, returns
workout_id
GET
/workouts
List all templates
GET
/workouts/{id}
Get template details
DELETE
/workouts/{id}
Delete a template. Cascades – see gotchas
POST
/workouts/{id}/plan?user_id=X
Schedule a template to a user, applying athlete params
GET
/plannedWorkouts/{id}
Get one planned workout
GET
/plannedWorkouts?user_id=X
List a user's scheduled workouts (optional
start_date
and
end_date
filters – both required together; one alone is ignored)
PATCH
/plannedWorkouts/{id}?user_id=X
Update the scheduled date. Only
planned_date
, never athlete params
DELETE
/plannedWorkouts/{id}?user_id=X
Unschedule a workout for one user
方法端点描述
POST
/workouts
创建训练模板,返回
workout_id
GET
/workouts
列出所有模板
GET
/workouts/{id}
获取模板详情
DELETE
/workouts/{id}
删除模板。级联操作——注意事项部分有说明
POST
/workouts/{id}/plan?user_id=X
为用户安排训练,应用运动员参数
GET
/plannedWorkouts/{id}
获取单个已安排的训练计划
GET
/plannedWorkouts?user_id=X
列出用户的已安排训练计划(可选
start_date
end_date
过滤器——两者必须同时提供;单独提供其中一个会被忽略)
PATCH
/plannedWorkouts/{id}?user_id=X
更新训练计划的日期。仅支持更新
planned_date
,不支持修改运动员参数
DELETE
/plannedWorkouts/{id}?user_id=X
取消为某用户安排的训练计划

Data Model

数据模型

A template is a hierarchy:
WorkoutTemplate → step_blocks[] → steps[] → intensity_targets[]
.
WorkoutTemplate
name
(required),
sport
(required), optional
description
,
environment
(
indoor
/
outdoor
/
pool
), and
pool_length_meters
(swimming only). At least one block is required.
step_blocks[] – a group of steps executed together. The block's
completion_condition
controls repetition:
Block conditionBehavior
{"type":"reps","value":4}
Repeat all steps 4 times
{"type":"time","value":1200}
Repeat until 20 minutes total
{"type":"distance","value":5000}
Repeat until 5 km total
{"type":"open"}
or omitted
Execute once (no repeat)
steps[] – each step needs a
completion_condition
(defaults to
open
if omitted) and an
intensity_type
(required:
warmup
,
active
,
rest
,
recovery
,
cooldown
). Optional:
intensity_targets[]
,
notes
,
strength
(exercise details),
swimming
(stroke and equipment).
Completion condition types:
time
(seconds),
distance
(meters),
reps
,
calories
,
open
(manual lap),
hr_less_than
/
hr_greater_than
(BPM),
power_less_than
/
power_greater_than
(watts).
intensity_targets[] – the goal metric for a step. Three families:
  • Absolute
    heart_rate
    (BPM),
    power
    (watts),
    speed
    (m/s),
    pace
    (sec/km),
    cadence
    (rpm or spm),
    rpe
    (1-10). No athlete params needed.
  • Percentage (needs athlete params at scheduling) –
    heart_rate_max_percentage
    (needs
    max_heart_rate
    ),
    heart_rate_threshold_percentage
    (needs
    threshold_heart_rate
    ),
    power_percentage
    (needs
    ftp
    ),
    speed_percentage
    (needs
    threshold_speed
    ).
  • Zone
    heart_rate_zone
    (1-5),
    power_zone
    (1-7). Providers convert to their native format.
Target value rules:
  • Absolute targets accept either a single
    value
    or a
    value_low
    /
    value_high
    range. A single
    value
    auto-expands to a ±5% range on most providers, except
    rpe
    , which stays a point value
    .
  • Percentage targets (
    power_percentage
    ,
    heart_rate_max_percentage
    ,
    heart_rate_threshold_percentage
    ,
    speed_percentage
    ) reject a single
    value
    with a 400 at template creation
    . Supply
    value_low
    and/or
    value_high
    ; a lone bound is expanded to a ±5% range.
  • Never send both
    value
    and
    value_low
    /
    value_high
    on the same target.
  • For ranges,
    value_low
    must be strictly less than
    value_high
    .
  • pool_length_meters
    is swimming-only; setting it elsewhere is invalid.
  • Athlete metrics (
    ftp
    ,
    max_heart_rate
    ,
    threshold_heart_rate
    ,
    threshold_speed
    ,
    pool_length_meters
    ) must be positive.
  • Sanity ranges are hard 400 rejections at
    POST /workouts
    , not warnings: heart rate 30-250 BPM, power 1-2000 W, speed 0-15 m/s, pace 1-7200 sec/km, cadence 1-300, RPE 1-10, percentage targets 0-200%.
模板采用层级结构:
WorkoutTemplate → step_blocks[] → steps[] → intensity_targets[]
WorkoutTemplate——
name
(必填)、
sport
(必填),可选字段包括
description
environment
indoor
/
outdoor
/
pool
)和
pool_length_meters
(仅适用于游泳项目)。至少需要一个训练块。
step_blocks[]——一组共同执行的训练步骤。训练块的
completion_condition
控制重复次数:
训练块条件行为
{"type":"reps","value":4}
重复执行所有步骤4次
{"type":"time","value":1200}
重复执行直到累计时长20分钟
{"type":"distance","value":5000}
重复执行直到累计距离5公里
{"type":"open"}
或省略
执行一次(不重复)
steps[]——每个步骤需要
completion_condition
(如果省略则默认为
open
)和
intensity_type
(必填:
warmup
active
rest
recovery
cooldown
)。可选字段:
intensity_targets[]
notes
strength
(训练细节)、
swimming
(泳姿和装备)。
完成条件类型:
time
(秒)、
distance
(米)、
reps
calories
open
(手动 lap)、
hr_less_than
/
hr_greater_than
(BPM)、
power_less_than
/
power_greater_than
(瓦)。
intensity_targets[]——步骤的目标指标。分为三类:
  • 绝对值——
    heart_rate
    (BPM)、
    power
    (瓦)、
    speed
    (米/秒)、
    pace
    (秒/公里)、
    cadence
    (转/分钟或划水次数/分钟)、
    rpe
    (1-10)。无需运动员参数。
  • 百分比(安排训练时需要运动员参数)——
    heart_rate_max_percentage
    (需要
    max_heart_rate
    )、
    heart_rate_threshold_percentage
    (需要
    threshold_heart_rate
    )、
    power_percentage
    (需要
    ftp
    )、
    speed_percentage
    (需要
    threshold_speed
    )。
  • 区间——
    heart_rate_zone
    (1-5)、
    power_zone
    (1-7)。服务商会将其转换为原生格式。
目标值规则:
  • 绝对值目标可以接受单个
    value
    value_low
    /
    value_high
    范围。单个
    value
    在大多数服务商处会自动扩展为±5%的范围,
    rpe
    除外,它保持为单点值
  • 百分比目标
    power_percentage
    heart_rate_max_percentage
    heart_rate_threshold_percentage
    speed_percentage
    在创建模板时如果仅提供单个
    value
    会返回400错误
    。需提供
    value_low
    和/或
    value_high
    ;单个边界会被扩展为±5%的范围。
  • 不要在同一个目标中同时发送
    value
    value_low
    /
    value_high
  • 对于范围,
    value_low
    必须严格小于
    value_high
  • pool_length_meters
    仅适用于游泳项目;在其他项目中设置该字段会无效。
  • 运动员指标(
    ftp
    max_heart_rate
    threshold_heart_rate
    threshold_speed
    pool_length_meters
    )必须为正数。
  • 合理性范围在
    POST /workouts
    时会直接返回400错误,而非警告:心率30-250 BPM,功率1-2000瓦,速度0-15米/秒,配速1-7200秒/公里,步频1-300,RPE 1-10,百分比目标0-200%。

Athlete Parameters

运动员参数

Templates are generic; personalization happens at scheduling time. Supply these in the
plan
request body:
ParameterUnitUsed 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
metersswimming (overrides the template value)
Conversion is linear:
Absolute = Percentage × param / 100
. A
power_percentage
of 95-100 with
ftp: 280
becomes 266-280 W on the device; the same template scheduled with
ftp: 200
becomes 190-200 W. If a percentage target's required parameter is missing, the Terra API emits a coercion warning and falls back to a provider default rather than failing.
模板是通用的;个性化设置在安排训练时进行。在
plan
请求体中提供以下参数:
参数单位适用的目标类型
max_heart_rate
BPM
heart_rate_max_percentage
目标
threshold_heart_rate
BPM
heart_rate_threshold_percentage
目标
ftp
power_percentage
目标
threshold_speed
米/秒
speed_percentage
目标
pool_length_meters
游泳项目(会覆盖模板中的值)
转换方式为线性计算:
绝对值 = 百分比 × 参数值 / 100
。例如,
power_percentage
为95-100且
ftp: 280
时,在设备上会转换为266-280瓦;同一模板在
ftp: 200
时会转换为190-200瓦。如果百分比目标所需的参数缺失,Terra API会发出强制转换警告,并回退到服务商默认值,而不会请求失败。

Coercion Model

强制转换模型

Providers differ in what they can represent. When a provider cannot express a feature exactly, the Terra API adapts the payload, still creates the workout, and returns a
coercion_warnings[]
array
. Each warning is
{ "path": "...", "message": "..." }
pointing at the field that was changed and why.
json
{
  "status": "success",
  "planned_workout_id": "12345",
  "provider_workout_id": "garmin_abc123",
  "coercion_warnings": [
    {
      "path": "workout.sport",
      "message": "Unsupported sport type: yoga. Defaulting to OTHER."
    }
  ]
}
Coercion is a success path, not an error. How you handle warnings is your choice: log them for debugging, surface a "some features were adjusted for your device" notice to users, or ignore informational ones. Read
references/coercion-scenarios.md
before relying on a feature that may not exist on the target provider.
不同服务商支持的功能有所不同。当服务商无法准确表达某个功能时,Terra API会调整请求负载,仍然创建训练计划,并返回
coercion_warnings[]
数组
。每个警告的格式为
{ "path": "...", "message": "..." }
,指向被修改的字段及原因。
json
{
  "status": "success",
  "planned_workout_id": "12345",
  "provider_workout_id": "garmin_abc123",
  "coercion_warnings": [
    {
      "path": "workout.sport",
      "message": "Unsupported sport type: yoga. Defaulting to OTHER."
    }
  ]
}
强制转换是成功路径,而非错误。如何处理警告由你决定:记录用于调试、向用户显示“部分功能已针对你的设备进行调整”的提示,或忽略信息性警告。在依赖可能不被目标服务商支持的功能之前,请阅读
references/coercion-scenarios.md

Gotchas

注意事项

  • DELETE /workouts/{id}
    cascades and is irreversible.
    It first removes every planned workout linked to that template from every user's device across every provider, then deletes the template. To unschedule one user without touching others, use
    DELETE /plannedWorkouts/{id}
    instead.
  • PATCH /plannedWorkouts/{id}
    updates only
    planned_date
    .
    It never re-applies athlete parameters. To change targets or params, delete and re-plan.
  • Provider operations differ wildly. Some providers do not support update, retrieve, or delete. An unsupported operation still returns a success response, so success does not always mean the device changed. Read
    references/provider-compatibility.md
    before targeting a specific provider.
  • COROS update = delete + recreate. COROS has no in-place update, so an "update" deletes the old workout and creates a new one; the
    provider_workout_id
    changes.
  • Huawei is create-only, running-only, no scheduling. No update, retrieve, or delete on the device. It ignores
    planned_date
    – the workout is available immediately and always returns a coercion warning noting this. Duplicate workout names per user are rejected with a 400. Non-running sports appear as a run.
  • Zepp has a 7-day sync window (today to today + 6 days). Workouts scheduled outside the window are stored in Terra API's database but not pushed to the device until a later write or delete for that user triggers a window refresh. There is no background auto-sync.
  • Hevy is strength-only. RPE targets are silently dropped with a warning, there are no block repeats (one block maps to one exercise, one step to one set), and it has no scheduling and no provider-side delete. Updates are supported: when a
    provider_workout_id
    exists, the existing Hevy routine is updated in place.
  • Apple syncs via the Terra iOS SDK. The server queues the action; the SDK pushes to WorkoutKit and reports back via
    POST /v2/plannedWorkouts/{id}/synced
    . Until then
    provider_workout_id
    is
    null
    .
  • Garmin retrieve only returns workouts created by your own credentials. Workouts made by other apps or on the device itself are invisible to your GET calls.
  • Deletes remove from Terra API's database but may leave the workout on the device for providers without a delete endpoint (e.g. Huawei, Hevy).
  • DELETE /workouts/{id}
    是级联操作且不可撤销
    。它会先从所有用户的所有设备上移除与该模板关联的所有已安排训练计划,然后删除模板。如果只想取消某用户的训练计划而不影响其他用户,请使用
    DELETE /plannedWorkouts/{id}
  • PATCH /plannedWorkouts/{id}
    仅更新
    planned_date
    。它不会重新应用运动员参数。如果要修改目标或参数,请删除原计划并重新安排。
  • 服务商的操作差异很大。有些服务商不支持更新、检索或删除操作。不支持的操作仍会返回成功响应,因此成功并不总是意味着设备已更改。在针对特定服务商开发前,请阅读
    references/provider-compatibility.md
  • COROS的更新操作等于删除+重新创建。COROS不支持原地更新,因此“更新”操作会删除旧训练计划并创建新的;
    provider_workout_id
    会发生变化。
  • 华为仅支持创建、仅适用于跑步项目、不支持安排。不支持设备上的更新、检索或删除操作。它会忽略
    planned_date
    ——训练计划会立即可用,并且总是返回强制转换警告说明这一点。同一用户下重复的训练计划名称会被拒绝并返回400错误。非跑步项目会显示为跑步。
  • Zepp有7天同步窗口(今日至今日+6天)。安排在窗口外的训练计划会存储在Terra API的数据库中,但不会推送到设备,直到针对该用户的后续写入或删除操作触发窗口刷新。没有后台自动同步。
  • Hevy仅支持力量训练。RPE目标会被静默丢弃并发出警告,不支持训练块重复(一个训练块对应一个训练动作,一个步骤对应一组),不支持安排训练且不支持服务商端删除。支持更新操作:当
    provider_workout_id
    存在时,会原地更新现有的Hevy训练计划。
  • Apple通过Terra iOS SDK同步。服务器会将操作加入队列;SDK会推送到WorkoutKit并通过
    POST /v2/plannedWorkouts/{id}/synced
    报告结果。在此之前
    provider_workout_id
    null
  • Garmin的检索操作仅返回由你自己的凭据创建的训练计划。其他应用或设备本身创建的训练计划对你的GET请求不可见。
  • 删除操作会从Terra API的数据库中移除训练计划,但对于不支持删除端点的服务商(如华为、Hevy),训练计划可能仍会保留在设备上

References

参考资料

Read the reference file that matches your task before writing the request:
  • references/provider-compatibility.md
    – the full operations matrix (create/update/retrieve/delete per provider) plus each provider's sport, target, completion, and structure support and special behaviors. Read this before targeting a specific provider.
  • references/coercion-scenarios.md
    – the full catalog of coercion scenarios, handling patterns (log / surface / ignore), and a prevention checklist. Read this before relying on a feature a provider may not support.
  • references/exercise-reference.md
    – exercise name normalization rules, the Garmin/Hevy flexibility table, and what happens when a name is not found. Read this before building a strength template.
Two things live in the docs rather than this skill, because they are large and change with the API:
Full API documentation: docs.tryterra.co/planned-workouts-api (append
.md
to any docs URL for a markdown version). If the terra-docs MCP server (
https://docs.tryterra.co/~gitbook/mcp
) is connected, use its tools to search and fetch the docs instead.
在编写请求前,请阅读与你的任务匹配的参考文件:
  • references/provider-compatibility.md
    ——完整的操作矩阵(各服务商的创建/更新/检索/删除支持情况)以及每个服务商的运动项目、目标、完成条件和结构支持情况及特殊行为。在针对特定服务商开发前请阅读此文件。
  • references/coercion-scenarios.md
    ——完整的强制转换场景目录、处理模式(记录/显示/忽略)以及预防清单。在依赖可能不被服务商支持的功能前请阅读此文件。
  • references/exercise-reference.md
    ——训练动作名称标准化规则、Garmin/Hevy的灵活性表格,以及找不到名称时的处理方式。在构建力量训练模板前请阅读此文件。
有两项内容在文档中而非本功能说明中,因为它们内容较多且会随API更新而变化:
完整API文档:docs.tryterra.co/planned-workouts-api(在任何文档URL后添加
.md
即可获取markdown版本)。如果已连接terra-docs MCP服务器(
https://docs.tryterra.co/~gitbook/mcp
),请使用其工具搜索和获取文档。