Scopes
The API uses a least-privilege scope taxonomy: each scope authorizes a single data domain, and no scope maps to more than one domain. v1 is read-only — there are no write scopes. Health data is split further, scope-wise, into one scope per metric category so an app can read (say) heart metrics without ever touching glucose or sleep.
Each scope authorizes a single domain and limits responses to a fixed field
projection. The same field set is returned across single-record, list, and
aggregation responses. Fields outside the projection — and all internal fields
such as userId and credential hashes — are never returned.
The scope taxonomy
Health data is scope-wise: rather than a single read:health-data scope
that exposes every metric, the health-data domain is split into independent
metric categories. Each category has its own scope read:health-data:<category>
and its own endpoint /api/v1/health-data/<category>. A category scope can only
ever read its own metric types — for example read:health-data:heart never
returns glucose or sleep readings.
All health-data category scopes share the same fixed projection:
id, type, value, unit, timestamp, source.
Health-data category scopes
| Scope | Category | Canonical metric types |
|---|---|---|
read:health-data:heart | Heart & cardiac | Heart Rate, Resting HR, Walking HR, HRV, ECG |
read:health-data:blood-pressure | Blood pressure | Blood Pressure, BP Diastolic |
read:health-data:oxygen | Blood oxygen | SPO2 |
read:health-data:respiratory | Respiratory | Respiratory Rate, Respiratory |
read:health-data:glucose | Blood glucose | Glucose |
read:health-data:temperature | Body temperature | Temperature |
read:health-data:activity | Activity & movement | Steps, Distance, Calories, Basal Calories, Exercise, Flights |
read:health-data:sleep | Sleep | Sleep, Sleep Deep, Sleep Core, Sleep REM, Sleep Awake, Time in Bed |
read:health-data:body-composition | Body composition | Weight, Height, BMI, Body Fat |
read:health-data:mindfulness | Mindfulness | Mindfulness |
Other domain scopes
| Scope | Data domain | Projected fields |
|---|---|---|
read:aggregations | aggregations / summaries | summary shape only (derived) |
read:trends | trends | bucketized trend points only (derived) |
read:symptoms | symptoms | id, description, severity, timestamp |
read:medications | medications & adherence | id, name, dosage, frequency, condition, pattern |
read:conditions | conditions | id, name, severity, sinceDate |
read:allergies | allergies | id, name, severity, sinceDate |
read:appointments | appointments | id, title, dateTime, specialty, location |
read:weight | weight | id, weightKg, date |
read:mood | mood | id, mood, note, timestamp |
read:reports | reports | id, generatedAt, dateRange, summary |
read:profile | profile (demographics) | name, gender, dateOfBirth, bloodType |
read:ehr | EHR-derived data | id, resourceType, summary, timestamp |
How scopes are enforced
On every authenticated /api/v1 request, the platform:
- Resolves the single scope the endpoint requires.
- Rejects with
INSUFFICIENT_SCOPE(HTTP 403) if the token lacks that scope, or presents a scope not in this taxonomy. The error names the missing scope. - Rejects with
CONSENT_REQUIRED(HTTP 403) if no active consent grant covers that scope for the requesting client and target user.
A scope can never reach data outside its own domain.
Requesting scopes
Request only the scopes your app needs. Users can approve a subset, so design your app to degrade gracefully when some requested scopes are not granted.