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

# Introduction

## Introduction & Quick Start

### What Are Planned Workouts?

Planned workouts let you push structured training sessions directly to your users' fitness devices. Instead of users manually creating workouts on their watch or bike computer, your app can:

1. **Create reusable workout templates** - Define the structure once
2. **Schedule to any user** - Apply athlete-specific parameters at scheduling time
3. **Sync to device** - Workout appears on user's Garmin, COROS, Wahoo, etc.
4. **Read the calendar back** - List a user's planned workouts, including ones a coach created on the provider's side

Reading back works where the provider's API exposes planned workouts: see the **Retrieve** row in [Provider Compatibility](/planned-workouts-api/provider-compatibility.md). [Overview](/planned-workouts-api/overview.md) has the response shape and the date window.

Planned Workouts is a paid add-on to your Terra plan. See [Pricing & Access](/planned-workouts-api/pricing.md).

### Two-Phase Workflow

```
┌─────────────────────────────────────────────────────────────────┐
│  Phase 1: Create Template (once)                                │
│  POST /workouts                                                 │
│  → Returns workout_id                                           │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│  Phase 2: Schedule to User (per athlete)                        │
│  POST /workouts/{workout_id}/plan?user_id=X                     │
│  → Applies athlete's max HR, FTP, etc.                          │
│  → Pushes to user's connected device                            │
└─────────────────────────────────────────────────────────────────┘
```

### Quick Start Example

#### Step 1: Create a Workout Template

Create a simple 20-minute interval run: 5min warmup → 3x(3min fast, 2min easy) → 5min cooldown

```bash
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": "20min Interval Run",
    "sport": "running",
    "description": "Warmup, 3x intervals, cooldown",
    "step_blocks": [
      {
        "steps": [{
          "completion_condition": { "type": "time", "value": 300 },
          "intensity_type": "warmup"
        }]
      },
      {
        "completion_condition": { "type": "reps", "value": 3 },
        "steps": [
          {
            "completion_condition": { "type": "time", "value": 180 },
            "intensity_type": "active",
            "intensity_targets": [{
              "target_type": "heart_rate_max_percentage",
              "value_low": 85,
              "value_high": 90
            }]
          },
          {
            "completion_condition": { "type": "time", "value": 120 },
            "intensity_type": "rest"
          }
        ]
      },
      {
        "steps": [{
          "completion_condition": { "type": "time", "value": 300 },
          "intensity_type": "cooldown"
        }]
      }
    ]
  }'
```

**Response:**

```json
{
  "status": "success",
  "workout_id": "12345"
}
```

#### Step 2: Schedule to a User

Push the workout to a specific user for tomorrow, with their max heart rate:

```bash
curl -X POST "https://access.tryterra.co/api/v2/workouts/12345/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-05",
    "max_heart_rate": 185
  }'
```

**Response:**

```json
{
  "status": "success",
  "planned_workout_id": "67890",
  "provider_workout_id": "abc123",
  "warnings": []
}
```

The workout now appears on the user's device. Providers that accept percentage targets, such as Garmin, receive 85-90% unchanged. Providers that need absolute values, such as Suunto and Zepp, receive 157-167 BPM, resolved from the max heart rate of 185 you passed.

#### Step 3: List the User's Planned Workouts

```bash
curl -X GET "https://access.tryterra.co/api/v2/plannedWorkouts?user_id=USER_ID&start_date=2026-02-05&end_date=2026-02-12" \
  -H "dev-id: YOUR_DEV_ID" \
  -H "x-api-key: YOUR_API_KEY"
```

The list holds both the workouts you scheduled through Terra and the workouts created on the provider's side, in one shape. Every item carries `planned_date` and the full body under `workout`. Provider-created items have `is_external: true` and no `workout_id`, so they cannot be updated or deleted through Terra. A workout you pushed that the provider echoes back is listed once.

**Response (abbreviated):**

```json
[
  {
    "planned_workout_id": "67890",
    "workout_id": "12345",
    "planned_date": "2026-02-05",
    "provider_workout_id": "abc123",
    "is_external": false,
    "warnings": [],
    "workout": {
      "name": "20min Interval Run",
      "sport": "running",
      "step_blocks": [
        {
          "steps": [
            {
              "completion_condition": { "type": "time", "value": 300 },
              "intensity_type": "warmup"
            }
          ]
        }
      ]
    }
  }
]
```

Two things to know:

* `start_date` and `end_date` are planned dates and both ends are included. Leave them out and provider-created workouts default to the trailing 30 days, so upcoming ones do not appear. Pass an explicit window to list what is ahead.
* `X-Terra-Provider-Fetch` reports the live provider read: `ok`, `skipped`, `rate_limited`, `unauthorized`, `unavailable`, `timeout` or `failed`. Anything other than `ok` also sets `X-Terra-Provider-Data-Truncated: true`, and the response is still a 200 carrying the workouts you scheduled through Terra.

### Authentication

All requests require two headers:

| Header      | Description             |
| ----------- | ----------------------- |
| `dev-id`    | Your Terra developer ID |
| `x-api-key` | Your Terra API key      |

### Supported Providers

Terra pushes workouts to these providers:

| Provider      | Running | Cycling | Swimming | Strength |
| ------------- | ------- | ------- | -------- | -------- |
| Garmin        | ✓       | ✓       | ✓        | ✓        |
| COROS         | ✓       | ✓       | ✓        | ✓        |
| Wahoo         | ✓       | ✓       | —        | —        |
| Suunto        | ✓       | ✓       | ✓        | ✓        |
| TrainingPeaks | ✓       | ✓       | ✓        | ✓        |
| Huawei        | ✓       | —       | —        | —        |
| Zepp          | ✓       | ✓       | ✓        | —        |
| Hevy          | —       | —       | —        | ✓        |
| Apple         | ✓       | ✓       | ✓        | ✓        |

Intervals.icu is read only: Terra lists the workouts an athlete has planned there, but cannot push to it. Users connect it with their Intervals.icu API key on Terra's login screen.

`GET /plannedWorkouts` also returns workouts created on the provider's side for Garmin, Wahoo, Suunto, TrainingPeaks and Intervals.icu. Garmin returns only the workouts your app created. COROS, Zepp, Huawei, Hevy and Apple offer no way to read a calendar back, so for those the list holds only what you scheduled through Terra.

Not all providers support all operations (update, retrieve, delete). See [Provider Compatibility](/planned-workouts-api/provider-compatibility.md) for detailed feature and operations support.

### Next Steps

* Core Concepts - Understand workout structure
* Athlete Parameters - Personalize for each user
* Sport-Specific Examples - Copy-paste examples
