# Days

> https://meetkeely.com/developers/api/days · Updated 2026-11-06 · Keely, by Metrica Fit LLC

## GET /v1/days/latest

- **Scope:** `nights` or `days`

The latest morning and the day it began: the newest date the account holds, shaped exactly as `GET /v1/days/{date}` answers it.

## GET /v1/days/{date}

- **Scope:** `nights` or `days`
- **Path:** `date`, a local date (`YYYY-MM-DD`)
- **Parts:** `recovery`, `night` and `sleep` need `nights`; `naps`, `load`, `steps` and `stress` need `days`; `workouts` needs `workouts` and `days`, because a workout belongs to the day whose summary lists it
- **Errors:** `404 not_found` when the date has neither a night nor a day

One morning and the day it began, exactly as the Keely app backs it up and as [the connector](https://meetkeely.com/connect) answers an assistant, so an assistant and your app read the same numbers for the same day.

```json Response
{
  "date": "2026-09-27",
  "recovery": {
    "status": "scored",
    "score_pct": 79,
    "state": "Primed",
    "focus": "Ready day: train as planned, hard sessions included.",
    "likely_range": [74, 83],
    "contributors": [
      { "input": "HRV", "value": 70.2, "unit": "ms", "normal": 61.5, "normal_range": [55.6, 68],
        "z": 1.4, "weight_pct": 45, "impact": "helping", "measured_by": "Keely" },
      { "input": "Resting heart rate", "value": 49, "unit": "bpm", "normal": 51, "normal_range": [49.5, 52.5],
        "z": 1.33, "weight_pct": 25, "impact": "helping", "measured_by": "Keely" },
      { "input": "Sleep", "value": 91, "unit": "% of need", "normal": 100, "normal_range": [85, 115],
        "z": -0.62, "weight_pct": 20, "impact": "holding back", "measured_by": "Polar Loop" },
      { "input": "Breathing rate", "value": 14.1, "unit": "breaths/min", "normal": 14, "normal_range": [13.6, 14.4],
        "z": -0.25, "weight_pct": 5, "impact": "normal", "measured_by": "Keely" },
      { "input": "Skin temperature", "value": 0.1, "unit": "°C from normal", "normal": 0, "normal_range": [-0.25, 0.25],
        "z": -0.4, "weight_pct": 5, "impact": "normal", "measured_by": "Polar Loop" }
    ]
  },
  "night": {
    "hrv_ms": 70.2, "hrv_measured_over": "early night",
    "resting_hr_bpm": 49, "lowest_hr_bpm": 46, "early_night_hr_bpm": 51.4, "average_hr_bpm": 55,
    "breathing_rate_per_min": 14.1, "skin_temp_deviation_c": 0.1, "average_stress_asleep": 12
  },
  "sleep": {
    "start": "2026-09-26T22:20:00Z", "end": "2026-09-27T06:20:00Z", "whose": "the band",
    "start_rule": { "learned": false, "taught_by_nights": 0, "corrected_nights": 2, "awake_at_stress": 40,
      "heart_over_median_bpm": null, "wrist_cooler_c": null, "tells_evenings": false },
    "in_bed_minutes": 480, "asleep_minutes": 440, "awake_minutes": 40,
    "light_minutes": 240, "deep_minutes": 95, "rem_minutes": 105, "wake_ups": 3,
    "need_minutes": 485, "need_parts_minutes": { "base": 470, "recent_debt": 15, "hard_day": 0 },
    "performance_pct": 91, "consistency": 84
  },
  "naps": [
    { "start": "2026-09-27T14:00:00Z", "end": "2026-09-27T14:45:00Z", "asleep_minutes": 45, "whose": "Keely, from your answers" }
  ],
  "asleep_with_naps_minutes": 485,
  "load": {
    "value": 98.4, "target": { "low": 132, "high": 179, "provisional": false }, "status": "34 to the target",
    "balance": 1.05, "balance_label": "Steady",
    "zone_minutes": { "z1": 20, "z2": 35, "z3": 10, "z4": 5, "z5": 0 }
  },
  "steps": 8123,
  "stress": {
    "day_average": 24, "day_level": "Calm", "night_average": 12, "still_average": 21,
    "minutes_by_level": { "calm": 400, "mild": 120, "elevated": 30, "high": 5 },
    "minutes_by_level_while_training": { "calm": 0, "mild": 10, "elevated": 20, "high": 5 },
    "moments": [
      { "start": "2026-09-27T10:20:00Z", "end": "2026-09-27T10:35:00Z", "peak": 64, "average": 57, "asleep": false }
    ]
  },
  "workouts": [ "… the day’s workouts, each as GET /v1/workouts lists them" ],
  "as_of": "2026-09-27T15:20:00Z",
  "methodology": "https://meetkeely.com/methodology"
}
```

What the parts mean:

- **`recovery`.** `status` is `scored`, `calibrating` (with `nights_recorded` and `nights_needed`) or `unavailable` (with a `note`). `state` is Primed (67–100), Balanced (34–66) or Restore (0–33), and `focus` is the app’s own line for the day. `likely_range` is where the score likely sits, from its inputs’ standard errors. Each contributor is one input against the person’s normal: its `z`, its `weight_pct`, and whether it was `helping`, `normal` or `holding back`. [How Recovery is scored](https://meetkeely.com/recovery).
- **`night`.** Last night’s vitals: HRV (RMSSD) and what it was measured over, resting, lowest, early-night and average heart rate, breathing rate, the skin temperature’s deviation from normal, and the average stress while asleep.
- **`sleep`.** When the night ran and `whose` times they are (the band’s, Keely’s or the person’s), the stages, wake-ups, the night’s need and its parts, performance against need, and the 14-day Sleep Regularity Index (`consistency`). `start_rule` says what read awake at the night’s start. [How sleep is read](https://meetkeely.com/sleep).
- **`naps`** the day’s other sleeps, and **`asleep_with_naps_minutes`** the night plus them.
- **`load`.** The day’s Load, its target range (`provisional` while the person’s 28-day average is still settling), a status line, Balance with its label, and minutes in each zone. [How Load is counted](https://meetkeely.com/load).
- **`stress`.** Averages for the day, the night and the still windows, minutes at each level (and inside workouts), and the moments: at least 10 minutes above 50 by day or 30 at night. [How Stress is scored](https://meetkeely.com/stress).
- **`workouts`.** The day’s workouts, each as [`GET /v1/workouts`](https://meetkeely.com/developers/api/workouts) lists them.
- **`missing`** lists what the date has no record of, in words.

## GET /v1/days

- **Scope:** `nights` or `days`
- **Query:** `from`, `to` (`YYYY-MM-DD`), at most 92 days; `to` defaults to the latest date, `from` to 29 days before it

`days` holds one object per date, in order, each shaped as above without `as_of` and `methodology`; a date without data has `null` parts and a `missing` list, never a gap.

```json Response
{
  "from": "2026-09-26",
  "to": "2026-09-27",
  "days": [
    { "date": "2026-09-26", "recovery": { "status": "calibrating", "score_pct": null, "nights_recorded": 2, "nights_needed": 3, "note": "…" }, "…": "…" },
    { "date": "2026-09-27", "recovery": { "status": "scored", "score_pct": 79, "…": "…" }, "…": "…" }
  ],
  "as_of": "2026-09-27T15:20:00Z",
  "methodology": "https://meetkeely.com/methodology"
}
```
