> ## 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.

# Nutrition Calculation

> The core of Saturday — personalized fuel, hydration, and electrolyte prescriptions

# Nutrition Calculation

The nutrition calculation endpoint is Saturday's core product. It takes an activity description and returns a personalized fuel prescription — carbohydrate, hydration, and electrolyte targets — with safety guardrails applied.

```bash theme={null}
POST /v1/nutrition/calculate
```

## Progressive enrichment

Saturday works with whatever data you have. More data produces more accurate prescriptions — but even minimal inputs return useful results.

### Minimal inputs

The bare minimum for a calculation:

<CodeGroup>
  ```python Python theme={null}
  response = requests.post(
      "https://api.saturday.fit/v1/nutrition/calculate",
      headers={"Authorization": "Bearer sk_test_abc123def456"},
      json={
          "activity_type": "run",
          "duration_min": 90,
          "athlete_weight_kg": 70,
      },
  )
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch(
    "https://api.saturday.fit/v1/nutrition/calculate",
    {
      method: "POST",
      headers: {
        Authorization: "Bearer sk_test_abc123def456",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        activity_type: "run",
        duration_min: 90,
        athlete_weight_kg: 70,
      }),
    }
  );
  ```
</CodeGroup>

This returns a prescription with a low `confidence_score`. The numbers are based on population-level defaults for the given activity type and body weight.

### Standard inputs

Add intensity and environmental conditions for a meaningfully better prescription:

```json theme={null}
{
  "activity_type": "bike",
  "duration_min": 180,
  "intensity_level": 7,
  "athlete_weight_kg": 68,
  "thermal_stress_level": 8
}
```

Thermal stress dramatically affects hydration and sodium needs. A 3-hour ride at high thermal stress requires very different fueling than the same ride in cool conditions.

### Comprehensive inputs

For the highest accuracy, include an athlete reference:

```json theme={null}
{
  "activity_type": "bike",
  "duration_min": 300,
  "intensity_level": 8,
  "is_race": true,
  "athlete_id": "ath_abc123",
  "thermal_stress_level": 7
}
```

When you include an `athlete_id`, Saturday pulls their stored profile — sweat level, saltiness, carb experience, fitness level, and past activity feedback. This is where prescriptions become genuinely personalized.

<Tip>
  **The enrichment path:** Start with minimal inputs to get integrated fast, then progressively add more data as your integration matures. Every additional field improves accuracy.
</Tip>

## Understanding the response

```json theme={null}
{
  "tier": "full",
  "carb_g_per_hr": 72,
  "sodium_mg_per_hr": 800,
  "fluid_ml_per_hr": 750,
  "total_carb_g": 360,
  "total_sodium_mg": 4000,
  "total_fluid_ml": 3750,
  "safety": {
    "max_safe_fluid_ml_per_hr": 1500,
    "max_safe_sodium_mg_per_hr": 3000,
    "confidence_score": 0.85,
    "requires_human_review": false,
    "warnings": [
      "High thermal stress. Consider ice, cold fluids, and shade."
    ],
    "not_instructions": true
  },
  "attribution": {
    "text": "Powered by Saturday",
    "logo_url": "https://saturday.fit/logo.png",
    "link": "https://saturday.fit",
    "required": false
  }
}
```

### Confidence score

The `safety.confidence_score` (0.0-1.0) indicates how personalized the prescription is:

| Range   | Meaning                                  | Typical inputs                            |
| ------- | ---------------------------------------- | ----------------------------------------- |
| 0.8-1.0 | Strong personalization, athlete history  | Athlete profile + conditions + feedback   |
| 0.5-0.8 | Good estimates with some personalization | Weight + intensity + thermal stress       |
| 0.0-0.5 | Population-level defaults applied        | Minimal inputs (type + duration + weight) |

## Comparing across conditions

To compare fueling across different conditions (e.g. a cool morning vs. a hot afternoon), call `POST /v1/nutrition/calculate` once per scenario and diff the results yourself, or use `POST /v1/nutrition/calculate/batch` to submit up to 50 scenarios in a single request.

<Note>
  **Two prescription shapes.** The `calculate` endpoints return a **flat** response (`carb_g_per_hr`, `sodium_mg_per_hr`, … with a nested `safety` block). The stored-prescription read (`GET /v1/athletes/{id}/activities/{id}/prescription`) returns a **wrapped** response: `{ "prescription": { … }, "safety": { … } }`. Read the fields accordingly depending on which endpoint you called.
</Note>

## Calculation timing

Running the calculator is a deliberate computation window, not an instant lookup — the same processing experience athletes see in the Saturday app:

* **Single calculation** (`POST /v1/nutrition/calculate`, `POST .../activities/{id}/calculate`): expect roughly **1–3 seconds**, scaling gently with activity duration. Recalculating an activity that already has a prescription takes about half that.
* **Batch** (`POST /v1/nutrition/calculate/batch`): each scenario adds roughly half a single calculation's time. The response headers arrive immediately with `X-Batch-Estimated-Ms` — the expected total processing time — so you can size progress indicators before the body lands. The completed body includes `estimated_ms` and `elapsed_ms`.
* **Estimate without calculating:** send the same batch payload with `"estimate_only": true` to get `estimated_ms` back instantly, with no calculations run. Useful when your HTTP client can't read streamed headers early.
* **Reads are instant.** Fetching a stored prescription (`GET .../prescription`) never carries a computation window.

<Tip>
  **Show a progress indicator during calculation.** Athletes trust a prescription more when they see it being computed. Use the calculation window to display a "calculating fueling plan…" state rather than a spinner-free freeze.
</Tip>

## Teaser vs. full responses

Responses depend on the athlete's Saturday subscription status:

* **Subscribed athletes** get exact numbers: `"carb_g_per_hr": 72`
* **Free/teaser athletes** get ranges: `"carb_range_g_per_hr": "55-85"`

See [Freemium Model](/guides/freemium-model) for implementation details.

## Safety

Every calculation response includes a `safety` block. This is non-negotiable — Saturday is a nutrition API for athletes, and bad recommendations can cause real harm.

See [Safety](/guides/safety) for the full guide on safety fields, risk levels, and display requirements.

<Warning>
  **Safety data is never gated behind subscription status.** Even teaser responses include complete safety metadata.
</Warning>

## Supported activity types

| Type          | Key    | Notes                             |
| ------------- | ------ | --------------------------------- |
| Running       | `run`  | Road, trail, track                |
| Cycling       | `bike` | Road, gravel, mountain            |
| Swimming      | `swim` | Pool, open water                  |
| Rowing        | `row`  | On-water, ergometer               |
| Skiing        | `ski`  | Cross-country, classic, skate     |
| Hiking        | `hike` | Long-duration, variable intensity |
| Weightlifting | `lift` | Strength training                 |

Use `GET /v1/activity-types` for the complete list with descriptions.

<Note>
  **Graduated precision (2026-06):** every calculation response now carries a `precision` object — `profile_complete`, impact-sorted `missing_fields`, and an onboarding invite URL. Exact numbers require a complete fueling profile; incomplete profiles get honest bands (never wider than teaser ranges). See [Athlete Onboarding](/guides/onboarding).
</Note>
