What it is
freddy's Personal API is a read-only REST API for pulling your own health data into your own tools: a Grafana dashboard, a Google Sheet, a script, or a personal app you built. It is the code-facing companion to your MCP connection, which is for talking to your data through an AI. Everything the API returns is your own already-connected data, bounded by your plan's history window.
Beta access
The Personal API is in beta. The “API keys” card appears in freddy under AI apps automatically, no request needed. Learn more at freddy.coach/api.
Get a key
- Open AI apps in freddy.
- In the API keys card, enter a label (for example grafana) and create a key.
- Copy the key. It starts with fk_live_ and is shown only once. Store it in your tool's secret store, never in code you share. You can create up to 10 keys and revoke any of them at any time.
Authenticate
Send the key as a bearer token on every request:
curl -H "Authorization: Bearer fk_live_..." https://freddy.coach/api/v1/profileEndpoints
- GET /api/v1/metrics: your normalized health metrics, newest first.
- GET /api/v1/catalog: the distinct metrics, providers, and units available to you.
- GET /api/v1/sources: your connected sources.
- GET /api/v1/profile: your profile and plan window.
The full reference, with every parameter, is at https://freddy.coach/api-docs, and the machine-readable spec is at https://freddy.coach/api/openapi.json (import it into Postman, Insomnia, or your own tooling).
Read your metrics
curl -H "Authorization: Bearer fk_live_..." \
"https://freddy.coach/api/v1/metrics?from=2026-06-01&limit=100"Each row is a small object: date, timestamp, provider, metric, device, deviceLabel, sourceId, numValue, textValue, unit. timestamp is the exact moment in UTC, and date is its day. device is the source device as freddy stores it, and deviceLabel is the friendly name you see in freddy. sourceId is the source's own id for the record, so rows with the same provider and sourceId belong to the same workout or night. Narrow the results with:
- metric: one or more metric names, repeated or comma-separated, for example metric=sleep_score,hrv.
- provider: one or more providers, case-insensitive, for example provider=garmin,oura.
- device: one or more stored device values (the device field, not the label). It needs metric, for example metric=steps&device=Forerunner 965. provider is optional.
- source_id: one or more record ids from sourceId. It needs provider, for example provider=garmin&source_id=12345.
- from and to: ISO dates. A from earlier than your plan window is clamped to the window rather than rejected.
- limit: page size, up to 1000 (default 200).
The meta block
Every response includes a meta block describing the plan window that produced it:
"meta": {
"plan": "FREE",
"history_window_days": 7,
"history_floor": "2026-07-02",
"source_cap": 1
}On a paid plan the window fields are null, meaning unbounded. This tells your tool exactly how far back the data goes, so nothing is silently truncated.
Read everything (pagination)
Responses include next_cursor. To pull a full range, keep calling with the cursor until it comes back null:
FK="fk_live_..."
cursor=""
while true; do
page=$(curl -s -H "Authorization: Bearer $FK" \
"https://freddy.coach/api/v1/metrics?limit=1000${cursor:+&cursor=$cursor}")
echo "$page" | jq -c '.data[]'
cursor=$(echo "$page" | jq -r '.next_cursor')
[ "$cursor" = "null" ] && break
doneRaw records
Add include_raw=true to get the full record behind each row: exercise sets, sleep stages, heart-rate streams, whatever the source sent. It's the same data your AI reads through freddy, at full resolution.
curl -H "Authorization: Bearer fk_live_..." \
"https://freddy.coach/api/v1/metrics?metric=workout_raw&include_raw=true"Each row then has raw and rawStatus:
- ok: raw holds the record exactly as the source sent it.
- none: this row has no record attached. Another row of the same workout often has it.
- unavailable: there is a record, but we couldn't read it. Try again later; if it stays unavailable, that record can't be read.
A few things that help:
- One workout or night is usually several rows. Group them by provider and sourceId.
- Where the record sits depends on the source. Garmin, Withings and Intervals.icu attach it to one row of the record, and Oura to every row. For Apple Health and Health Connect, ask for the metric that ends in _raw, for example workout_raw.
- Keep following next_cursor to get every page.
Rate limits
If you receive a 429, wait and retry.
Sync into your own tools
Because the API is plain HTTP with a bearer key, most tools can read it directly. A common setup is a scheduled Google Apps Script that pulls /api/v1/metrics into a sheet each morning, or a Grafana or personal database that queries it on a timer. If you would like a ready-made Google Sheets script to start from, ask us in the chat.
Good to know
- Read-only. The API never changes your data or your connections.
- Retired sources are not returned.
- Revoking a key stops it working immediately, with no caching.