mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
v1.5.1 patch. Fixes the silent login failure self-hosters hit on plain-HTTP origins that aren't localhost — the bundled Docker image runs NODE_ENV=production, so every cookie carried Secure, and modern browsers drop those on http://10.x.x.x style origins. The session cookie never made it back to the browser, /api/auth/me returned 401, and the login page reloaded. New SESSION_COOKIE_SECURE env var with three values: - unset (default) — flag follows NODE_ENV === "production" (unchanged) - "false" — never set (LAN / VPN / Tailscale-only opt-out) - "true" — always set (pnpm dev fronted by HTTPS) Shared helper at src/lib/auth/secure-cookie.ts replaces four scattered literals across session, codex device-start, and withings connect. Six unit cases pin the decision matrix. OpenAPI spec generator now reads info.version from package.json so the drift gate stays meaningful instead of catching every release bump. Default behaviour unchanged for HTTPS-fronted deployments.
3170 lines
96 KiB
YAML
3170 lines
96 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: HealthLog API
|
|
version: 1.5.1
|
|
description: >-
|
|
Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest.
|
|
|
|
|
|
## Date-time contract
|
|
|
|
|
|
Every field marked `format: date-time` is an ISO-8601 instant. The schema pattern accepts both `Z` (UTC) and
|
|
`±HH:MM` (offset) suffixes; clients must accept either. Server responses since v1.4.25 emit timestamps with the
|
|
requesting user's display-timezone offset when a user context exists (exports, doctor-report PDF).
|
|
Background-job-authored payloads (backups, admin tools) emit `Z`. Native iOS clients should always parse via a
|
|
Foundation ISO-8601 formatter with the `withInternetDateTime` + `withTimeZone` options enabled.
|
|
license:
|
|
name: AGPL-3.0
|
|
url: https://github.com/MBombeck/HealthLog/blob/main/LICENSE
|
|
contact:
|
|
name: HealthLog
|
|
url: https://healthlog.dev
|
|
servers:
|
|
- url: https://healthlog.bombeck.io
|
|
description: Production
|
|
- url: http://localhost:3000
|
|
description: Local dev
|
|
tags:
|
|
- name: Auth
|
|
- name: Measurements
|
|
- name: Medications
|
|
- name: Mood
|
|
- name: Insights
|
|
- name: Notifications
|
|
- name: Devices
|
|
- name: Admin
|
|
paths:
|
|
/api/auth/login:
|
|
post:
|
|
tags:
|
|
- Auth
|
|
summary: Email-or-username login (password)
|
|
description: "Browser callers receive a session cookie. Native callers (X-Client-Type: native or HealthLog-iOS UA
|
|
prefix) additionally receive a paired access + refresh token."
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
email:
|
|
type: string
|
|
minLength: 1
|
|
password:
|
|
type: string
|
|
minLength: 1
|
|
required:
|
|
- email
|
|
- password
|
|
responses:
|
|
"200":
|
|
description: Login succeeded.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LoginResponse"
|
|
"401": &a1
|
|
description: Authentication required or invalid credentials.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"422": &a2
|
|
description: Request validation failed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"429": &a3
|
|
description: Rate limit exceeded.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
/api/auth/passkey/login-verify:
|
|
post:
|
|
tags:
|
|
- Auth
|
|
summary: Passkey assertion verification
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PasskeyLoginVerifyRequest"
|
|
responses:
|
|
"200":
|
|
description: Assertion verified — session + optional bearer issued.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PasskeyLoginVerifyResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/auth/refresh:
|
|
post:
|
|
tags:
|
|
- Auth
|
|
summary: Rotate refresh token (one-time use)
|
|
description: Reuse of a consumed refresh token revokes every refresh token still active for the originating device
|
|
(per-device blast radius from v1.4.23). Legacy tokens issued before v1.4.23 with a null deviceId fall back to
|
|
revoke-all-for-user.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RefreshTokenRequest"
|
|
responses:
|
|
"200":
|
|
description: Rotation succeeded — new pair issued.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RefreshResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/measurements:
|
|
get:
|
|
tags:
|
|
- Measurements
|
|
summary: List measurements
|
|
description: Filter by type + date range. Response is paged via offset/limit; default limit 100, hard cap 500.
|
|
parameters:
|
|
- in: query
|
|
name: type
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- WEIGHT
|
|
- BLOOD_PRESSURE_SYS
|
|
- BLOOD_PRESSURE_DIA
|
|
- PULSE
|
|
- BODY_FAT
|
|
- SLEEP_DURATION
|
|
- ACTIVITY_STEPS
|
|
- BLOOD_GLUCOSE
|
|
- TOTAL_BODY_WATER
|
|
- BONE_MASS
|
|
- OXYGEN_SATURATION
|
|
- HEART_RATE_VARIABILITY
|
|
- RESTING_HEART_RATE
|
|
- ACTIVE_ENERGY_BURNED
|
|
- FLIGHTS_CLIMBED
|
|
- WALKING_RUNNING_DISTANCE
|
|
- VO2_MAX
|
|
- BODY_TEMPERATURE
|
|
- FAT_FREE_MASS
|
|
- FAT_MASS
|
|
- MUSCLE_MASS
|
|
- SKIN_TEMPERATURE
|
|
- PULSE_WAVE_VELOCITY
|
|
- VASCULAR_AGE
|
|
- VISCERAL_FAT
|
|
- AUDIO_EXPOSURE_ENV
|
|
- AUDIO_EXPOSURE_HEADPHONE
|
|
- TIME_IN_DAYLIGHT
|
|
- WALKING_STEADINESS
|
|
- AUDIO_EXPOSURE_EVENT
|
|
- in: query
|
|
name: from
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
- in: query
|
|
name: to
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
- in: query
|
|
name: limit
|
|
schema:
|
|
default: 100
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 5000
|
|
- in: query
|
|
name: offset
|
|
schema:
|
|
default: 0
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
- in: query
|
|
name: sortBy
|
|
schema:
|
|
default: measuredAt
|
|
type: string
|
|
enum:
|
|
- type
|
|
- value
|
|
- measuredAt
|
|
- source
|
|
- in: query
|
|
name: sortDir
|
|
schema:
|
|
default: desc
|
|
type: string
|
|
enum:
|
|
- asc
|
|
- desc
|
|
- in: query
|
|
name: aggregate
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- raw
|
|
- daily
|
|
- weekly
|
|
- monthly
|
|
- in: query
|
|
name: source
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- rollup
|
|
- in: query
|
|
name: groupBy
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- day
|
|
- in: query
|
|
name: dayKey
|
|
schema:
|
|
type: string
|
|
pattern: ^\d{4}-\d{2}-\d{2}$
|
|
responses:
|
|
"200":
|
|
description: Measurement page.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ListMeasurementsResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
post:
|
|
tags:
|
|
- Measurements
|
|
summary: Create one measurement
|
|
description: Single ingest. Use `/api/measurements/batch` for Apple Health upload streams.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
type:
|
|
type: string
|
|
enum:
|
|
- WEIGHT
|
|
- BLOOD_PRESSURE_SYS
|
|
- BLOOD_PRESSURE_DIA
|
|
- PULSE
|
|
- BODY_FAT
|
|
- SLEEP_DURATION
|
|
- ACTIVITY_STEPS
|
|
- BLOOD_GLUCOSE
|
|
- TOTAL_BODY_WATER
|
|
- BONE_MASS
|
|
- OXYGEN_SATURATION
|
|
- HEART_RATE_VARIABILITY
|
|
- RESTING_HEART_RATE
|
|
- ACTIVE_ENERGY_BURNED
|
|
- FLIGHTS_CLIMBED
|
|
- WALKING_RUNNING_DISTANCE
|
|
- VO2_MAX
|
|
- BODY_TEMPERATURE
|
|
- FAT_FREE_MASS
|
|
- FAT_MASS
|
|
- MUSCLE_MASS
|
|
- SKIN_TEMPERATURE
|
|
- PULSE_WAVE_VELOCITY
|
|
- VASCULAR_AGE
|
|
- VISCERAL_FAT
|
|
- AUDIO_EXPOSURE_ENV
|
|
- AUDIO_EXPOSURE_HEADPHONE
|
|
- TIME_IN_DAYLIGHT
|
|
- WALKING_STEADINESS
|
|
- AUDIO_EXPOSURE_EVENT
|
|
value:
|
|
type: number
|
|
measuredAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
notes:
|
|
type: string
|
|
maxLength: 25
|
|
source:
|
|
default: MANUAL
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
glucoseContext:
|
|
type: string
|
|
enum:
|
|
- FASTING
|
|
- POSTPRANDIAL
|
|
- RANDOM
|
|
- BEDTIME
|
|
deviceType:
|
|
anyOf:
|
|
- type: string
|
|
minLength: 1
|
|
maxLength: 32
|
|
- type: "null"
|
|
required:
|
|
- type
|
|
- value
|
|
- measuredAt
|
|
responses:
|
|
"201":
|
|
description: Created.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateMeasurementResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/measurements/batch:
|
|
post:
|
|
tags:
|
|
- Measurements
|
|
summary: Apple Health batch ingest
|
|
description: Up to 500 HealthKit entries per call. Idempotent via the `Idempotency-Key` header (replay window 24h).
|
|
Per-entry status lets the iOS client advance its sync cursor accurately. v1.4.25 W8c adds an optional
|
|
`deviceType` per entry — feed it from `HKDevice.model` so the cross-source canonical picker can break
|
|
Apple-Watch-vs-iPhone ties; null/absent stays backward-compatible with v1.4.23 clients.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AppleHealthBatchRequest"
|
|
responses:
|
|
"200":
|
|
description: Batch processed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/BatchMeasurementsResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/measurements/by-external-ids:
|
|
delete:
|
|
tags:
|
|
- Measurements
|
|
summary: Delete measurements by external ID (iOS deletion-sync)
|
|
description: Removes the user's measurement rows whose externalId is in the request list. Rows owned by another user are
|
|
silently skipped (cross-user 404 guard). Up to 500 externalIds per call.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MeasurementsDeleteByExternalIdsRequest"
|
|
responses:
|
|
"200":
|
|
description: Delete batch processed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MeasurementsDeleteByExternalIdsResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/workouts:
|
|
get:
|
|
tags:
|
|
- Measurements
|
|
summary: List workouts (v1.4.32)
|
|
description: "Paginated workout list with cross-source canonical-row dedup. The picker reads the per-user
|
|
source-priority ladder and buckets by `(startedAt 5 min slot, sportType)` — twin workouts (Apple Watch +
|
|
Withings ScanWatch) collapse to a single canonical row per cluster. Field names mirror the iOS handoff contract:
|
|
`distanceM`, `activeEnergyKcal`, `avgHr`, `maxHr`."
|
|
parameters:
|
|
- in: query
|
|
name: limit
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 200
|
|
- in: query
|
|
name: offset
|
|
schema:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
- in: query
|
|
name: since
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
- in: query
|
|
name: until
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
- in: query
|
|
name: sportType
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: Canonical workout page.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ListWorkoutsResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/workouts/{id}:
|
|
get:
|
|
tags:
|
|
- Measurements
|
|
summary: Workout detail (v1.4.32)
|
|
description: Single-workout envelope. Owns the optional `WorkoutRoute` GeoJSON geometry + `canonicalId` pointer that
|
|
resolves to the cluster winner so deep-links into non-canonical twin rows can redirect cleanly. Cross-user rows
|
|
surface as 404 (existence channel sealed).
|
|
parameters:
|
|
- in: path
|
|
name: id
|
|
schema:
|
|
type: string
|
|
required: true
|
|
responses:
|
|
"200":
|
|
description: Workout detail.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/GetWorkoutResponse"
|
|
"401": *a1
|
|
"404":
|
|
description: Workout not found (or owned by another user).
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/workouts/batch:
|
|
post:
|
|
tags:
|
|
- Measurements
|
|
summary: Typed workout batch ingest (v1.4.25 W16b)
|
|
description: Server-side ingest endpoint for HKWorkout records (iOS) and Withings activity rows (server-to-server). Up
|
|
to 100 workouts per call; nested route geometry (GeoJSON LineString) is capped at 20 000 points and stored in a
|
|
1:1 `WorkoutRoute` row keyed by `workoutId`. Idempotent via the `Idempotency-Key` header (replay window 24h).
|
|
Per-entry status (`inserted | duplicate | skipped`) lets the iOS sync cursor checkpoint accurately. The request
|
|
body ceiling is 5 MB enforced at the HTTP layer — clients above the ceiling receive a 413 with
|
|
`workout.batch.payload_too_large`.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
workouts:
|
|
minItems: 1
|
|
maxItems: 100
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
sportType:
|
|
type: string
|
|
enum:
|
|
- walking
|
|
- running
|
|
- cycling
|
|
- hiking
|
|
- swimming
|
|
- rowing
|
|
- elliptical
|
|
- stairClimber
|
|
- yoga
|
|
- mindAndBody
|
|
- strength
|
|
- hiit
|
|
- dance
|
|
- golf
|
|
- tennis
|
|
- basketball
|
|
- soccer
|
|
- crossTraining
|
|
- mixedCardio
|
|
- other
|
|
startedAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
endedAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
totalEnergyKcal:
|
|
type: number
|
|
minimum: 0
|
|
maximum: 50000
|
|
totalDistanceM:
|
|
type: number
|
|
minimum: 0
|
|
maximum: 1000000
|
|
avgHeartRate:
|
|
type: integer
|
|
minimum: 20
|
|
maximum: 300
|
|
maxHeartRate:
|
|
type: integer
|
|
minimum: 20
|
|
maximum: 300
|
|
minHeartRate:
|
|
type: integer
|
|
minimum: 20
|
|
maximum: 300
|
|
stepCount:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 200000
|
|
elevationM:
|
|
type: number
|
|
minimum: -500
|
|
maximum: 10000
|
|
pauseDurationSec:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 86400
|
|
source:
|
|
default: MANUAL
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
externalId:
|
|
type: string
|
|
maxLength: 128
|
|
externalSourceVersion:
|
|
type: string
|
|
maxLength: 64
|
|
metadata:
|
|
type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
route:
|
|
type: object
|
|
properties:
|
|
geometry:
|
|
type: object
|
|
properties:
|
|
type:
|
|
type: string
|
|
const: LineString
|
|
coordinates:
|
|
minItems: 2
|
|
maxItems: 20000
|
|
type: array
|
|
items:
|
|
type: array
|
|
prefixItems:
|
|
- type: number
|
|
minimum: -180
|
|
maximum: 180
|
|
- type: number
|
|
minimum: -90
|
|
maximum: 90
|
|
items:
|
|
type: number
|
|
required:
|
|
- type
|
|
- coordinates
|
|
sampleTimestamps:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
t:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
speedMs:
|
|
type: number
|
|
minimum: 0
|
|
maximum: 50
|
|
hr:
|
|
type: integer
|
|
minimum: 20
|
|
maximum: 300
|
|
required:
|
|
- t
|
|
required:
|
|
- geometry
|
|
required:
|
|
- sportType
|
|
- startedAt
|
|
- endedAt
|
|
required:
|
|
- workouts
|
|
responses:
|
|
"200":
|
|
description: Batch processed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/BatchWorkoutsResponse"
|
|
"400":
|
|
description: Batch validation failed (over-cap, schema reject, or oversized route).
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"401": *a1
|
|
"413":
|
|
description: Request body exceeds the 5 MB ceiling.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/devices:
|
|
post:
|
|
tags:
|
|
- Devices
|
|
summary: Register native device + APNs token
|
|
description: Idempotent upsert by `token`. APNs token + environment are paired — supplying one without the other returns
|
|
422. Cross-user re-registration of either identifier returns 409.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DeviceRegisterRequest"
|
|
responses:
|
|
"201":
|
|
description: Device registered or refreshed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DeviceRegisterResponse"
|
|
"401": *a1
|
|
"409":
|
|
description: Device or APNs token already registered to another user.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/auth/me/coach-prefs:
|
|
get:
|
|
tags:
|
|
- Auth
|
|
summary: Read per-user Coach prompt-tuning preferences
|
|
description: Returns the persisted preferences with defaults filled in. Null persisted state resolves to the legacy
|
|
v1.4.22 defaults.
|
|
responses:
|
|
"200":
|
|
description: Resolved preferences.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/GetCoachPrefsResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
put:
|
|
tags:
|
|
- Auth
|
|
summary: Replace per-user Coach prompt-tuning preferences
|
|
description: Persists the supplied prefs. Body is validated against `CoachPrefs`; missing keys fall back to the
|
|
documented defaults.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
tone:
|
|
default: warm
|
|
type: string
|
|
enum:
|
|
- warm
|
|
- neutral
|
|
- concise
|
|
verbosity:
|
|
default: default
|
|
type: string
|
|
enum:
|
|
- brief
|
|
- default
|
|
- detailed
|
|
excludeMetrics:
|
|
default: []
|
|
maxItems: 11
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- bp
|
|
- weight
|
|
- pulse
|
|
- mood
|
|
- compliance
|
|
- hrv
|
|
- sleep
|
|
- resting_hr
|
|
- steps
|
|
- medications
|
|
- anthropometrics
|
|
showEvidenceByDefault:
|
|
default: false
|
|
type: boolean
|
|
defaultWindow:
|
|
default: allTime
|
|
type: string
|
|
enum:
|
|
- last7days
|
|
- last30days
|
|
- last90days
|
|
- allTime
|
|
responses:
|
|
"200":
|
|
description: Saved preferences echoed back.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PutCoachPrefsResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/auth/me/disable-coach:
|
|
get:
|
|
tags:
|
|
- Auth
|
|
summary: Read per-user Coach opt-out flag
|
|
description: Returns the user's per-account Coach opt-out flag. Default `false` (Coach visible). Powers the Settings →
|
|
Insights "Hide Coach" Switch and the layout FAB short-circuit.
|
|
responses:
|
|
"200":
|
|
description: Resolved flag.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/GetDisableCoachResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
patch:
|
|
tags:
|
|
- Auth
|
|
summary: Toggle per-user Coach opt-out flag
|
|
description: Flips the per-account Coach opt-out flag. Idempotent — the DB write fires even when the value matches so
|
|
the audit-log row mirrors the API call. Rate-limit 60/min per user.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DisableCoachFlag"
|
|
responses:
|
|
"200":
|
|
description: Resolved next-state echoed back for optimistic-update consumers.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PatchDisableCoachResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/auth/me/source-priority:
|
|
get:
|
|
tags:
|
|
- Auth
|
|
summary: Read per-user source priority
|
|
description: Returns the per-metric-class source priority used by the analytics aggregator. Missing keys fall back to
|
|
`DEFAULT_SOURCE_PRIORITY`. Null persisted state resolves to the documented defaults.
|
|
responses:
|
|
"200":
|
|
description: Resolved priority.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/GetSourcePriorityResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
put:
|
|
tags:
|
|
- Auth
|
|
summary: Replace per-user source priority
|
|
description: Persists the supplied priority. Body is validated against `SourcePriority`; missing keys read as
|
|
`DEFAULT_SOURCE_PRIORITY` at the call site.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
steps:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
activeEnergy:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
walkingRunningDistance:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
flightsClimbed:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
sleep:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
weight:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bloodPressure:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
pulse:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyFat:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyTemperature:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
spo2:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
hrv:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
restingHeartRate:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
vo2Max:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
metricPriority:
|
|
type: object
|
|
properties:
|
|
steps:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
activeEnergy:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
walkingRunningDistance:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
flightsClimbed:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
sleep:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
weight:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bloodPressure:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
pulse:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyFat:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyTemperature:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
spo2:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
hrv:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
restingHeartRate:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
vo2Max:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
deviceTypePriority:
|
|
type: object
|
|
properties:
|
|
default:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- watch
|
|
- band
|
|
- ring
|
|
- phone
|
|
- scale
|
|
- other
|
|
- unknown
|
|
additionalProperties:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- watch
|
|
- band
|
|
- ring
|
|
- phone
|
|
- scale
|
|
- other
|
|
- unknown
|
|
responses:
|
|
"200":
|
|
description: Saved priority (defaulted) echoed back.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PutSourcePriorityResponse"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/insights/chat/messages/{id}/feedback:
|
|
post:
|
|
tags:
|
|
- Insights
|
|
summary: Rate a Coach assistant message
|
|
description: Persists a helpful/unhelpful rating for a single Coach reply. Reuses the v1.4.16 RecommendationFeedback
|
|
table via the polymorphic `targetType` column. The aggregator buckets ratings by (promptVersion, tone,
|
|
verbosity).
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CoachMessageFeedbackRequest"
|
|
responses:
|
|
"201":
|
|
description: Feedback saved.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CoachMessageFeedbackResponse"
|
|
"401": *a1
|
|
"404":
|
|
description: Message not found or not owned by the caller.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"409":
|
|
description: Caller has already rated this message text.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/admin/notifications/diagnostic:
|
|
get:
|
|
tags:
|
|
- Admin
|
|
summary: Admin notification diagnostic snapshot
|
|
description: "Admin-only. Returns what the dispatcher would see when targeting the calling admin's account: registered
|
|
devices (APNs tokens masked to prefix + suffix), per-channel enabled + configPresent flags, and recent push
|
|
attempts (currently always `[]` pending the v1.4.48+ PushAttempt table). Cookie auth only — never Bearer."
|
|
responses:
|
|
"200":
|
|
description: Diagnostic snapshot.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminDiagnosticResponse"
|
|
"401": *a1
|
|
"403":
|
|
description: Caller is not an admin.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorEnvelope"
|
|
"422": *a2
|
|
"429": *a3
|
|
/api/insights/comprehensive:
|
|
get:
|
|
tags:
|
|
- Insights
|
|
summary: Comprehensive AI insights bundle
|
|
description: Full Insights surface — daily briefing, recommendations with rationale, optional weekly report + storyboard
|
|
annotations. Strict-schema validated server-side.
|
|
responses:
|
|
"200":
|
|
description: Insights bundle.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/InsightsComprehensiveResponseEnvelope"
|
|
"401": *a1
|
|
"422": *a2
|
|
"429": *a3
|
|
components:
|
|
schemas:
|
|
PasskeyLoginVerifyRequest:
|
|
type: object
|
|
properties:
|
|
challengeId:
|
|
type: string
|
|
minLength: 1
|
|
description: Server-issued WebAuthn challenge id.
|
|
credential:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
rawId:
|
|
type: string
|
|
type:
|
|
type: string
|
|
const: public-key
|
|
response:
|
|
type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
authenticatorAttachment:
|
|
type: string
|
|
enum:
|
|
- platform
|
|
- cross-platform
|
|
clientExtensionResults:
|
|
type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
required:
|
|
- id
|
|
- rawId
|
|
- type
|
|
- response
|
|
description: SimpleWebAuthn-style assertion response payload.
|
|
required:
|
|
- challengeId
|
|
- credential
|
|
description: Passkey assertion verification. Same native-client token issuance as the password path.
|
|
RefreshTokenRequest:
|
|
type: object
|
|
properties:
|
|
refreshToken:
|
|
type: string
|
|
minLength: 1
|
|
description: Caller-presented refresh token (`hlr_<64hex>`).
|
|
revoke:
|
|
description: When true, revoke the supplied token instead of rotating.
|
|
type: boolean
|
|
required:
|
|
- refreshToken
|
|
description: Exchange a one-time-use refresh token for a fresh access + refresh pair.
|
|
AppleHealthBatchRequest:
|
|
type: object
|
|
properties:
|
|
entries:
|
|
minItems: 1
|
|
maxItems: 500
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/AppleHealthBatchEntry"
|
|
required:
|
|
- entries
|
|
description: Apple Health batch ingest. ≤500 entries per call; idempotent via `Idempotency-Key`.
|
|
AppleHealthBatchEntry:
|
|
type: object
|
|
properties:
|
|
hkIdentifier:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 120
|
|
description: HealthKit identifier (e.g. `HKQuantityTypeIdentifierBodyMass`).
|
|
value:
|
|
type: number
|
|
unit:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 60
|
|
startDate:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
endDate:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
sleepStage:
|
|
description: HKCategoryValueSleepAnalysis codepoint; only for sleep samples.
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 20
|
|
externalId:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 120
|
|
description: HKSample.uuid string — the dedup key.
|
|
externalSourceVersion:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 120
|
|
deviceType:
|
|
description: Device class mapped from `HKDevice.model`. Used by the analytics aggregator to break ties when the same
|
|
source contributed multiple devices for the same day. Omit (or send null) on legacy clients — the server
|
|
treats it as `unknown` and the picker falls through.
|
|
anyOf:
|
|
- type: string
|
|
enum:
|
|
- watch
|
|
- band
|
|
- ring
|
|
- phone
|
|
- scale
|
|
- other
|
|
- unknown
|
|
- type: "null"
|
|
required:
|
|
- hkIdentifier
|
|
- value
|
|
- unit
|
|
- startDate
|
|
- endDate
|
|
- externalId
|
|
MeasurementsDeleteByExternalIdsRequest:
|
|
type: object
|
|
properties:
|
|
externalIds:
|
|
minItems: 0
|
|
maxItems: 500
|
|
type: array
|
|
items:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 120
|
|
required:
|
|
- externalIds
|
|
description: iOS deletion-sync. Up to 500 externalIds per call; matching rows owned by other users are silently skipped
|
|
(cross-user 404 guard).
|
|
DeviceRegisterRequest:
|
|
type: object
|
|
properties:
|
|
token:
|
|
type: string
|
|
minLength: 8
|
|
maxLength: 512
|
|
pattern: ^[A-Za-z0-9+/=._:-]+$
|
|
description: Generic device identifier (legacy; APNs token below).
|
|
bundleId:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 128
|
|
locale:
|
|
type: string
|
|
minLength: 2
|
|
maxLength: 16
|
|
appVersion:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 32
|
|
model:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 64
|
|
apnsToken:
|
|
description: Hex-encoded APNs device token. Must be paired with `apnsEnvironment`.
|
|
type: string
|
|
minLength: 8
|
|
maxLength: 256
|
|
pattern: ^[A-Fa-f0-9]+$
|
|
apnsEnvironment:
|
|
description: Gateway the iOS client received `apnsToken` from. Server never auto-detects.
|
|
type: string
|
|
enum:
|
|
- sandbox
|
|
- production
|
|
required:
|
|
- token
|
|
- bundleId
|
|
description: Native device registration. Re-registering an APNs token belonging to another user returns 409
|
|
(cross-user-hijack guard).
|
|
DisableCoachFlag:
|
|
type: object
|
|
properties:
|
|
disableCoach:
|
|
type: boolean
|
|
required:
|
|
- disableCoach
|
|
description: Per-account Coach opt-out toggle (v1.4.47 W3). `true` hides the Coach FAB and short-circuits its API gates.
|
|
CoachMessageFeedbackRequest:
|
|
type: object
|
|
properties:
|
|
rating:
|
|
type: string
|
|
enum:
|
|
- helpful
|
|
- unhelpful
|
|
reason:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 200
|
|
required:
|
|
- rating
|
|
description: Per-message helpful/unhelpful feedback (v1.4.23 H7). Optional `reason` is free-form prose, capped at 200 chars.
|
|
LoginResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/AccessRefreshBundle"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
AccessRefreshBundle:
|
|
type: object
|
|
properties:
|
|
user:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
username:
|
|
type: string
|
|
required:
|
|
- id
|
|
- username
|
|
additionalProperties: false
|
|
token:
|
|
type: string
|
|
description: Access token (`hlk_<64hex>`).
|
|
tokenExpiresAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
refreshToken:
|
|
description: Refresh token (`hlr_<64hex>`); only present for native-policy callers.
|
|
type: string
|
|
refreshTokenExpiresAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
required:
|
|
- token
|
|
- tokenExpiresAt
|
|
additionalProperties: false
|
|
description: Native-client token bundle returned by login + refresh. Web cookie-only callers see only `user`.
|
|
ErrorEnvelope:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: "null"
|
|
error:
|
|
type: string
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
errorCode:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
description: "Standard error response: data is null, error is human prose."
|
|
PasskeyLoginVerifyResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/AccessRefreshBundle"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
RefreshResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/AccessRefreshBundle"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
ListMeasurementsResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
measurements:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/MeasurementResource"
|
|
total:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
required:
|
|
- measurements
|
|
- total
|
|
additionalProperties: false
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
MeasurementResource:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
type:
|
|
type: string
|
|
enum:
|
|
- WEIGHT
|
|
- BLOOD_PRESSURE_SYS
|
|
- BLOOD_PRESSURE_DIA
|
|
- PULSE
|
|
- BODY_FAT
|
|
- SLEEP_DURATION
|
|
- ACTIVITY_STEPS
|
|
- BLOOD_GLUCOSE
|
|
- TOTAL_BODY_WATER
|
|
- BONE_MASS
|
|
- OXYGEN_SATURATION
|
|
- HEART_RATE_VARIABILITY
|
|
- RESTING_HEART_RATE
|
|
- ACTIVE_ENERGY_BURNED
|
|
- FLIGHTS_CLIMBED
|
|
- WALKING_RUNNING_DISTANCE
|
|
- VO2_MAX
|
|
- BODY_TEMPERATURE
|
|
- FAT_FREE_MASS
|
|
- FAT_MASS
|
|
- MUSCLE_MASS
|
|
- SKIN_TEMPERATURE
|
|
- PULSE_WAVE_VELOCITY
|
|
- VASCULAR_AGE
|
|
- VISCERAL_FAT
|
|
- AUDIO_EXPOSURE_ENV
|
|
- AUDIO_EXPOSURE_HEADPHONE
|
|
- TIME_IN_DAYLIGHT
|
|
- WALKING_STEADINESS
|
|
- AUDIO_EXPOSURE_EVENT
|
|
value:
|
|
type: number
|
|
unit:
|
|
type: string
|
|
measuredAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
source:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
notes:
|
|
anyOf:
|
|
- type: string
|
|
- type: "null"
|
|
required:
|
|
- id
|
|
- type
|
|
- value
|
|
- unit
|
|
- measuredAt
|
|
- source
|
|
additionalProperties: false
|
|
description: Server-shaped measurement row returned by GET endpoints.
|
|
CreateMeasurementResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/MeasurementResource"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
BatchMeasurementsResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/AppleHealthBatchResponse"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
AppleHealthBatchResponse:
|
|
type: object
|
|
properties:
|
|
inserted:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
duplicate:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
skipped:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
entries:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/AppleHealthBatchEntryResult"
|
|
required:
|
|
- inserted
|
|
- duplicate
|
|
- skipped
|
|
- entries
|
|
additionalProperties: false
|
|
AppleHealthBatchEntryResult:
|
|
type: object
|
|
properties:
|
|
index:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
status:
|
|
type: string
|
|
enum:
|
|
- inserted
|
|
- duplicate
|
|
- skipped
|
|
reason:
|
|
type: string
|
|
required:
|
|
- index
|
|
- status
|
|
additionalProperties: false
|
|
MeasurementsDeleteByExternalIdsResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/MeasurementsDeleteByExternalIdsResult"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
MeasurementsDeleteByExternalIdsResult:
|
|
type: object
|
|
properties:
|
|
deletedCount:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
required:
|
|
- deletedCount
|
|
additionalProperties: false
|
|
ListWorkoutsResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/WorkoutListResponse"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
WorkoutListResponse:
|
|
type: object
|
|
properties:
|
|
workouts:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/WorkoutListEntry"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
total:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
limit:
|
|
type: integer
|
|
exclusiveMinimum: 0
|
|
maximum: 9007199254740991
|
|
offset:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
droppedDuplicates:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
required:
|
|
- total
|
|
- limit
|
|
- offset
|
|
- droppedDuplicates
|
|
additionalProperties: false
|
|
required:
|
|
- workouts
|
|
- meta
|
|
additionalProperties: false
|
|
WorkoutListEntry:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
sportType:
|
|
type: string
|
|
startedAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
endedAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
durationSec:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
distanceM:
|
|
anyOf:
|
|
- type: number
|
|
- type: "null"
|
|
activeEnergyKcal:
|
|
anyOf:
|
|
- type: number
|
|
- type: "null"
|
|
avgHr:
|
|
anyOf:
|
|
- type: integer
|
|
minimum: -9007199254740991
|
|
maximum: 9007199254740991
|
|
- type: "null"
|
|
maxHr:
|
|
anyOf:
|
|
- type: integer
|
|
minimum: -9007199254740991
|
|
maximum: 9007199254740991
|
|
- type: "null"
|
|
source:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
externalId:
|
|
anyOf:
|
|
- type: string
|
|
- type: "null"
|
|
required:
|
|
- id
|
|
- sportType
|
|
- startedAt
|
|
- endedAt
|
|
- durationSec
|
|
- distanceM
|
|
- activeEnergyKcal
|
|
- avgHr
|
|
- maxHr
|
|
- source
|
|
- externalId
|
|
additionalProperties: false
|
|
GetWorkoutResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/WorkoutDetailResponse"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
WorkoutDetailResponse:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
sportType:
|
|
type: string
|
|
startedAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
endedAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
durationSec:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
distanceM:
|
|
anyOf:
|
|
- type: number
|
|
- type: "null"
|
|
activeEnergyKcal:
|
|
anyOf:
|
|
- type: number
|
|
- type: "null"
|
|
avgHr:
|
|
anyOf:
|
|
- type: integer
|
|
minimum: -9007199254740991
|
|
maximum: 9007199254740991
|
|
- type: "null"
|
|
maxHr:
|
|
anyOf:
|
|
- type: integer
|
|
minimum: -9007199254740991
|
|
maximum: 9007199254740991
|
|
- type: "null"
|
|
minHr:
|
|
anyOf:
|
|
- type: integer
|
|
minimum: -9007199254740991
|
|
maximum: 9007199254740991
|
|
- type: "null"
|
|
stepCount:
|
|
anyOf:
|
|
- type: integer
|
|
minimum: -9007199254740991
|
|
maximum: 9007199254740991
|
|
- type: "null"
|
|
elevationM:
|
|
anyOf:
|
|
- type: number
|
|
- type: "null"
|
|
pauseDurationSec:
|
|
anyOf:
|
|
- type: integer
|
|
minimum: -9007199254740991
|
|
maximum: 9007199254740991
|
|
- type: "null"
|
|
source:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
externalId:
|
|
anyOf:
|
|
- type: string
|
|
- type: "null"
|
|
metadata:
|
|
anyOf:
|
|
- {}
|
|
- type: "null"
|
|
route:
|
|
anyOf:
|
|
- $ref: "#/components/schemas/WorkoutRouteGeometry"
|
|
- type: "null"
|
|
canonicalId:
|
|
type: string
|
|
required:
|
|
- id
|
|
- sportType
|
|
- startedAt
|
|
- endedAt
|
|
- durationSec
|
|
- distanceM
|
|
- activeEnergyKcal
|
|
- avgHr
|
|
- maxHr
|
|
- minHr
|
|
- stepCount
|
|
- elevationM
|
|
- pauseDurationSec
|
|
- source
|
|
- externalId
|
|
- metadata
|
|
- route
|
|
- canonicalId
|
|
additionalProperties: false
|
|
WorkoutRouteGeometry:
|
|
type: object
|
|
properties:
|
|
geometry: {}
|
|
sampleTimestamps:
|
|
anyOf:
|
|
- type: array
|
|
items:
|
|
type: string
|
|
- type: "null"
|
|
required:
|
|
- geometry
|
|
- sampleTimestamps
|
|
additionalProperties: false
|
|
BatchWorkoutsResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/WorkoutBatchResponse"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
WorkoutBatchResponse:
|
|
type: object
|
|
properties:
|
|
processed:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
inserted:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
duplicates:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
skipped:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
index:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
reason:
|
|
type: string
|
|
required:
|
|
- index
|
|
- reason
|
|
additionalProperties: false
|
|
entries:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/WorkoutBatchEntryResult"
|
|
required:
|
|
- processed
|
|
- inserted
|
|
- duplicates
|
|
- skipped
|
|
- entries
|
|
additionalProperties: false
|
|
WorkoutBatchEntryResult:
|
|
type: object
|
|
properties:
|
|
index:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 9007199254740991
|
|
status:
|
|
type: string
|
|
enum:
|
|
- inserted
|
|
- duplicate
|
|
- skipped
|
|
reason:
|
|
type: string
|
|
required:
|
|
- index
|
|
- status
|
|
additionalProperties: false
|
|
DeviceRegisterResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
required:
|
|
- id
|
|
additionalProperties: false
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
GetCoachPrefsResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
tone:
|
|
default: warm
|
|
type: string
|
|
enum:
|
|
- warm
|
|
- neutral
|
|
- concise
|
|
verbosity:
|
|
default: default
|
|
type: string
|
|
enum:
|
|
- brief
|
|
- default
|
|
- detailed
|
|
excludeMetrics:
|
|
default: []
|
|
maxItems: 11
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- bp
|
|
- weight
|
|
- pulse
|
|
- mood
|
|
- compliance
|
|
- hrv
|
|
- sleep
|
|
- resting_hr
|
|
- steps
|
|
- medications
|
|
- anthropometrics
|
|
showEvidenceByDefault:
|
|
default: false
|
|
type: boolean
|
|
defaultWindow:
|
|
default: allTime
|
|
type: string
|
|
enum:
|
|
- last7days
|
|
- last30days
|
|
- last90days
|
|
- allTime
|
|
required:
|
|
- tone
|
|
- verbosity
|
|
- excludeMetrics
|
|
- showEvidenceByDefault
|
|
- defaultWindow
|
|
additionalProperties: false
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
PutCoachPrefsResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
tone:
|
|
default: warm
|
|
type: string
|
|
enum:
|
|
- warm
|
|
- neutral
|
|
- concise
|
|
verbosity:
|
|
default: default
|
|
type: string
|
|
enum:
|
|
- brief
|
|
- default
|
|
- detailed
|
|
excludeMetrics:
|
|
default: []
|
|
maxItems: 11
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- bp
|
|
- weight
|
|
- pulse
|
|
- mood
|
|
- compliance
|
|
- hrv
|
|
- sleep
|
|
- resting_hr
|
|
- steps
|
|
- medications
|
|
- anthropometrics
|
|
showEvidenceByDefault:
|
|
default: false
|
|
type: boolean
|
|
defaultWindow:
|
|
default: allTime
|
|
type: string
|
|
enum:
|
|
- last7days
|
|
- last30days
|
|
- last90days
|
|
- allTime
|
|
required:
|
|
- tone
|
|
- verbosity
|
|
- excludeMetrics
|
|
- showEvidenceByDefault
|
|
- defaultWindow
|
|
additionalProperties: false
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
GetDisableCoachResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/DisableCoachFlagOutput"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
PatchDisableCoachResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/DisableCoachFlagOutput"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
GetSourcePriorityResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
steps:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
activeEnergy:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
walkingRunningDistance:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
flightsClimbed:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
sleep:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
weight:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bloodPressure:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
pulse:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyFat:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyTemperature:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
spo2:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
hrv:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
restingHeartRate:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
vo2Max:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
metricPriority:
|
|
type: object
|
|
properties:
|
|
steps:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
activeEnergy:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
walkingRunningDistance:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
flightsClimbed:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
sleep:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
weight:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bloodPressure:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
pulse:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyFat:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyTemperature:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
spo2:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
hrv:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
restingHeartRate:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
vo2Max:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
additionalProperties: false
|
|
deviceTypePriority:
|
|
type: object
|
|
properties:
|
|
default:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- watch
|
|
- band
|
|
- ring
|
|
- phone
|
|
- scale
|
|
- other
|
|
- unknown
|
|
additionalProperties:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- watch
|
|
- band
|
|
- ring
|
|
- phone
|
|
- scale
|
|
- other
|
|
- unknown
|
|
additionalProperties: false
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
PutSourcePriorityResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
steps:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
activeEnergy:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
walkingRunningDistance:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
flightsClimbed:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
sleep:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
weight:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bloodPressure:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
pulse:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyFat:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyTemperature:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
spo2:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
hrv:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
restingHeartRate:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
vo2Max:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
metricPriority:
|
|
type: object
|
|
properties:
|
|
steps:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
activeEnergy:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
walkingRunningDistance:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
flightsClimbed:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
sleep:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
weight:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bloodPressure:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
pulse:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyFat:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
bodyTemperature:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
spo2:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
hrv:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
restingHeartRate:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
vo2Max:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- MANUAL
|
|
- WITHINGS
|
|
- IMPORT
|
|
- APPLE_HEALTH
|
|
additionalProperties: false
|
|
deviceTypePriority:
|
|
type: object
|
|
properties:
|
|
default:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- watch
|
|
- band
|
|
- ring
|
|
- phone
|
|
- scale
|
|
- other
|
|
- unknown
|
|
additionalProperties:
|
|
maxItems: 8
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum:
|
|
- watch
|
|
- band
|
|
- ring
|
|
- phone
|
|
- scale
|
|
- other
|
|
- unknown
|
|
additionalProperties: false
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
CoachMessageFeedbackResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
required:
|
|
- id
|
|
- createdAt
|
|
additionalProperties: false
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
AdminDiagnosticResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/AdminDiagnosticData"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
AdminDiagnosticData:
|
|
type: object
|
|
properties:
|
|
devices:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/AdminDiagnosticDevice"
|
|
notificationChannels:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/AdminDiagnosticChannel"
|
|
recentPushAttempts:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/AdminDiagnosticPushAttempt"
|
|
required:
|
|
- devices
|
|
- notificationChannels
|
|
- recentPushAttempts
|
|
additionalProperties: false
|
|
description: Admin notification diagnostic snapshot for the calling user — what the dispatcher would see when targeting
|
|
this account. Surfaces device tokens (masked), channel state, and recent push attempts so an operator can debug
|
|
an iOS / Web Push / Telegram / ntfy issue without DB shell access.
|
|
AdminDiagnosticDevice:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
platform:
|
|
type: string
|
|
hasApnsToken:
|
|
type: boolean
|
|
apnsTokenPrefix:
|
|
anyOf:
|
|
- type: string
|
|
- type: "null"
|
|
apnsTokenSuffix:
|
|
anyOf:
|
|
- type: string
|
|
- type: "null"
|
|
apnsEnvironment:
|
|
anyOf:
|
|
- type: string
|
|
- type: "null"
|
|
lastSeenAt:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
required:
|
|
- id
|
|
- platform
|
|
- hasApnsToken
|
|
- apnsTokenPrefix
|
|
- apnsTokenSuffix
|
|
- apnsEnvironment
|
|
- lastSeenAt
|
|
additionalProperties: false
|
|
description: Per-device APNs registration snapshot. The APNs token is masked to its 8-char hex prefix + 8-char suffix so
|
|
an operator can correlate with iOS-side logs without disclosing the delivery target.
|
|
AdminDiagnosticChannel:
|
|
type: object
|
|
properties:
|
|
type:
|
|
type: string
|
|
enabled:
|
|
type: boolean
|
|
configPresent:
|
|
type: boolean
|
|
required:
|
|
- type
|
|
- enabled
|
|
- configPresent
|
|
additionalProperties: false
|
|
description: Per-channel state. `configPresent` is true when the channel's encrypted-JSON config blob carries the field
|
|
the corresponding sender will read (chatId+botToken for TELEGRAM, topic for NTFY); WEB_PUSH/APNS rely on sibling
|
|
tables so the row's existence is the signal.
|
|
AdminDiagnosticPushAttempt:
|
|
type: object
|
|
properties:
|
|
eventType:
|
|
type: string
|
|
channel:
|
|
type: string
|
|
result:
|
|
type: string
|
|
reason:
|
|
anyOf:
|
|
- type: string
|
|
- type: "null"
|
|
at:
|
|
type: string
|
|
format: date-time
|
|
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
|
required:
|
|
- eventType
|
|
- channel
|
|
- result
|
|
- reason
|
|
- at
|
|
additionalProperties: false
|
|
description: Single push delivery attempt. Reserved for the v1.4.48+ follow-up that adds the dedicated PushAttempt table
|
|
— currently always returned as an empty array so the response shape stays stable for iOS consumers.
|
|
InsightsComprehensiveResponseEnvelope:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: "#/components/schemas/InsightsComprehensiveResponse"
|
|
error:
|
|
type: "null"
|
|
meta:
|
|
type: object
|
|
properties:
|
|
requestId:
|
|
type: string
|
|
additionalProperties: false
|
|
required:
|
|
- data
|
|
- error
|
|
additionalProperties: false
|
|
InsightsComprehensiveResponse:
|
|
type: object
|
|
properties:
|
|
summary:
|
|
type: string
|
|
recommendations:
|
|
type: array
|
|
items:
|
|
type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
citations:
|
|
type: array
|
|
items:
|
|
type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
warnings:
|
|
type: array
|
|
items:
|
|
type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
dailyBriefing:
|
|
anyOf:
|
|
- type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
- type: "null"
|
|
trendAnnotations:
|
|
anyOf:
|
|
- type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
- type: "null"
|
|
storyboardAnnotations:
|
|
type: array
|
|
items:
|
|
type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
metricSource:
|
|
type: object
|
|
propertyNames:
|
|
type: string
|
|
additionalProperties: {}
|
|
required:
|
|
- summary
|
|
- recommendations
|
|
- citations
|
|
- warnings
|
|
additionalProperties: false
|
|
description: AI-generated insights bundle. Strict-schema validated server-side; Coach-routed when the insight surface
|
|
needs day-level grounding.
|
|
DisableCoachFlagOutput:
|
|
type: object
|
|
properties:
|
|
disableCoach:
|
|
type: boolean
|
|
required:
|
|
- disableCoach
|
|
additionalProperties: false
|
|
description: Per-account Coach opt-out toggle (v1.4.47 W3). `true` hides the Coach FAB and short-circuits its API gates.
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: hlk_<64hex>
|
|
description: Native-client API token. Use the `token` field returned by /api/auth/login on a native client.
|
|
cookieAuth:
|
|
type: apiKey
|
|
in: cookie
|
|
name: healthlog_session
|
|
description: Browser session cookie — set by /api/auth/login.
|