> ## Documentation Index
> Fetch the complete documentation index at: https://docs.saturday.fit/llms.txt
> Use this file to discover all available pages before exploring further.

# Activities

> Activity lifecycle — creating, prescribing, and tracking

# Activities

Activities represent individual training sessions or races. Each activity belongs to an athlete and can have a nutrition prescription, selected products, and post-activity feedback attached.

## Activity lifecycle

```
Create activity -> Calculate prescription -> (Optional) Add products -> (Optional) Submit feedback
```

1. **Create** the activity with type, duration, and optional intensity/thermal stress
2. **Calculate** a nutrition prescription for it
3. **Add products** the athlete plans to use (optional — for preparation planning)
4. **Submit feedback** after the activity (optional — improves future prescriptions)

## Creating an activity

<CodeGroup>
  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.saturday.fit/v1/athletes/ath_abc123/activities",
      headers={"Authorization": "Bearer sk_test_abc123def456"},
      json={
          "type": "run",
          "name": "Saturday long run",
          "duration_min": 120,
          "intensity_level": 5,
          "scheduled_at": "2025-01-15T07:00:00Z",
          "thermal_stress_level": 4,
      },
  )

  activity = response.json()
  print(f"Activity ID: {activity['id']}")
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch(
    "https://api.saturday.fit/v1/athletes/ath_abc123/activities",
    {
      method: "POST",
      headers: {
        Authorization: "Bearer sk_test_abc123def456",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        type: "run",
        name: "Saturday long run",
        duration_min: 120,
        intensity_level: 5,
        scheduled_at: "2025-01-15T07:00:00Z",
        thermal_stress_level: 4,
      }),
    }
  );

  const activity = await response.json();
  console.log(`Activity ID: ${activity.id}`);
  ```
</CodeGroup>

### Activity fields

| Field                  | Type    | Required | Description                                                                                   |
| ---------------------- | ------- | -------- | --------------------------------------------------------------------------------------------- |
| `type`                 | string  | Yes      | Activity type (see [supported types](/guides/nutrition-calculation#supported-activity-types)) |
| `duration_min`         | integer | Yes      | Expected duration in minutes                                                                  |
| `intensity_level`      | integer | No       | 1-9 scale                                                                                     |
| `thermal_stress_level` | integer | No       | 1-9 scale                                                                                     |
| `is_race_event`        | boolean | No       | Whether this is a race                                                                        |
| `name`                 | string  | No       | Human-readable label                                                                          |
| `scheduled_at`         | string  | No       | ISO 8601 datetime                                                                             |

### Multi-sport activities

For triathlons and brick workouts, specify sub-activities:

```json theme={null}
{
  "type": "bike",
  "name": "Olympic distance race",
  "duration_min": 165,
  "intensity_level": 8,
  "is_race_event": true
}
```

Saturday calculates prescriptions tailored to the activity type — you fuel differently on the bike than on a run.

## Calculating a prescription

```bash theme={null}
POST /v1/athletes/{athlete_id}/activities/{activity_id}/calculate
```

This uses the activity's parameters and the athlete's profile to generate a personalized prescription. Recalculating overwrites the previous prescription — use this when activity parameters change (e.g., updated weather forecast).

The response is tier-aware, with the same semantics as `/v1/nutrition/calculate`:

* **Full tier** (subscribed, covered, or in-trial athletes): `tier: "full"` with the exact `prescription` object (carb/sodium/fluid totals and per-hour rates), stored on the activity. Trial responses also carry `tier_source: "trial"`, `trial_ends_at`, and `trial_calls_remaining_today` — each calculation debits the trial's daily call allowance, exactly like nutrition calculate.
* **Teaser tier**: `tier: "teaser"` with per-hour *ranges* (`carb_range_g_per_hr`, `sodium_range_mg_per_hr`, `fluid_range_ml_per_hr`), a `subscription_cta` with the athlete's subscribe link, and required attribution. Nothing is stored — `GET .../prescription` keeps returning the last full-tier result, if any.

`safety` metadata is always included regardless of tier.

## Getting a stored prescription

```bash theme={null}
GET /v1/athletes/{athlete_id}/activities/{activity_id}/prescription
```

Returns the most recently calculated prescription for this activity, wrapped with safety metadata:

```json theme={null}
{
  "prescription": {
    "carb_g_per_hr": 62.5,
    "sodium_mg_per_hr": 485.0,
    "fluid_ml_per_hr": 620.0,
    "total_carb_g": 125,
    "total_sodium_mg": 970,
    "total_fluid_ml": 1240,
    "calculated_at": "2025-01-15T06:55:00Z"
  },
  "safety": {
    "max_safe_fluid_ml_per_hr": 1801,
    "max_safe_sodium_mg_per_hr": 5000,
    "confidence_score": 0.85,
    "not_instructions": true,
    "warnings": []
  }
}
```

<Note>
  The `{prescription, safety}` envelope is consistent across all Saturday endpoints that return prescription data. Always read `prescription.*` for values and `safety.*` for guardrail information. The `not_instructions: true` flag signals that these are recommendations for human consideration, not executable commands.
</Note>

## Getting an activity with prescription

```bash theme={null}
GET /v1/athletes/{athlete_id}/activities/{activity_id}
```

The activity response includes the prescription inline, along with any attached products.

## Listing activities

```bash theme={null}
GET /v1/athletes/{athlete_id}/activities?from=2025-01-01&to=2025-01-31&type=running
```

Supports filtering by date range and type.

## Submitting feedback

Post-activity feedback improves future prescriptions:

<CodeGroup>
  ```python Python theme={null}
  response = requests.post(
      "https://api.saturday.fit/v1/athletes/ath_abc123/activities/act_xyz789/feedback",
      headers={"Authorization": "Bearer sk_test_abc123def456"},
      json={
          "rating": 4,
          "notes": "Felt good until mile 18, then energy dropped",
      },
  )
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch(
    "https://api.saturday.fit/v1/athletes/ath_abc123/activities/act_xyz789/feedback",
    {
      method: "POST",
      headers: {
        Authorization: "Bearer sk_test_abc123def456",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        rating: 4,
        notes: "Felt good until mile 18, then energy dropped",
      }),
    }
  );
  ```
</CodeGroup>

### Feedback fields

| Field    | Type    | Required | Description                                             |
| -------- | ------- | -------- | ------------------------------------------------------- |
| `rating` | integer | Yes      | Overall prescription quality, 1 (poor) to 5 (excellent) |
| `notes`  | string  | No       | Free-text feedback on how the fueling went              |

<Tip>
  Feedback is the single most valuable signal for improving future prescriptions. The more activities with feedback, the more personalized Saturday becomes. Encourage athletes to submit feedback — even simple ratings help.
</Tip>

## Activity type inference

If your platform has activity metadata but not a clean type, Saturday can infer it:

```bash theme={null}
POST /v1/infer/activity-type
```

```json theme={null}
{
  "title": "Morning jog around Green Lake",
  "description": "Easy recovery after yesterday's intervals",
  "tags": ["recovery", "outdoor"]
}
```

Response:

```json theme={null}
{
  "inferred_type": "run",
  "confidence": 0.95,
  "intensity_hint": "easy"
}
```

For multi-sport titles like "Bike/run brick", use `POST /v1/infer/brick-types`.
