# Ultrahuman API to FHIR: get Ultrahuman Ring data into your app

> Ultrahuman OAuth API, personal tokens and MCP: read Ring AIR heart rate, HRV, sleep and steps and store them as FHIR R4 Observations, with code.

Source: https://developers.anpheros.com/guides/ultrahuman-api

**Ultrahuman has a public developer portal, Ultrahuman Vision, with an OAuth API that gives your app a person's daily Ring AIR data after they approve it: heart rate, HRV, sleep, steps, skin temperature and, with the M1 sensor, glucose metrics. It also offers personal API tokens and a read-only MCP server. You can store each reading as a LOINC-coded FHIR R4 Observation with one standard API call. Anpheros does not connect to Ultrahuman's cloud itself: your code reads Ultrahuman (or the phone's health store), and Anpheros keeps the record with the person's consent. The Ultrahuman app also syncs to Apple Health, including HRV and temperature, and to Health Connect.**

## Read Ultrahuman data and store it in FHIR

First, one day of ring data from Ultrahuman (an access token from your Ultrahuman OAuth app with the `ring_data` scope):

```bash
curl -X GET "https://partner.ultrahuman.com/api/partners/v1/user_data/metrics?date=2026-11-02" \
  -H "Authorization: Bearer $ULTRAHUMAN_TOKEN"
```

Then the day's steps as a FHIR Observation in the person's record (sandbox key `sk_test_…`):

```bash
curl -X POST https://platform.anpheros.com/fhir/R4/Observation \
  -H "Authorization: Bearer $ANPHEROS_KEY" \
  -H "Content-Type: application/fhir+json" \
  -H "X-Anpheros-Author-Type: device" \
  -d '{"resourceType":"Observation","status":"final",
       "category":[{"coding":[{"system":"http://terminology.hl7.org/CodeSystem/observation-category","code":"activity"}]}],
       "code":{"coding":[{"system":"http://loinc.org","code":"41950-7","display":"Number of steps in 24 hour Measured"}]},
       "subject":{"reference":"Patient/<id>"},
       "effectivePeriod":{"start":"2026-11-02","end":"2026-11-02"},
       "valueQuantity":{"value":7840,"unit":"{steps}","system":"http://unitsofmeasure.org","code":"{steps}"},
       "device":{"display":"Ultrahuman Ring AIR"}}'
```

The same in Python: one request per day, all days sent together in one transaction Bundle.

```python
import os, requests

ULTRAHUMAN = "https://partner.ultrahuman.com/api/partners/v1/user_data/metrics"
FHIR = "https://platform.anpheros.com/fhir/R4"
uh = {"Authorization": f"Bearer {os.environ['ULTRAHUMAN_TOKEN']}"}
fhir = {"Authorization": f"Bearer {os.environ['ANPHEROS_KEY']}", "Content-Type": "application/fhir+json"}

def steps_from_metrics(ultrahuman_json):
    """Return the day's step total. `steps` is one of the metrics; its place in the JSON is in Ultrahuman's docs."""
    raise NotImplementedError

entries = []
for day in ["2026-11-01", "2026-11-02"]:
    metrics = requests.get(ULTRAHUMAN, headers=uh, params={"date": day}).json()
    entries.append({
        "request": {"method": "POST", "url": "Observation"},
        "resource": {
            "resourceType": "Observation", "status": "final",
            "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "activity"}]}],
            "code": {"coding": [{"system": "http://loinc.org", "code": "41950-7", "display": "Number of steps in 24 hour Measured"}]},
            "subject": {"reference": "Patient/<id>"},
            "effectivePeriod": {"start": day, "end": day},
            "valueQuantity": {"value": steps_from_metrics(metrics), "unit": "{steps}",
                              "system": "http://unitsofmeasure.org", "code": "{steps}"},
            "device": {"display": "Ultrahuman Ring AIR"},
        },
    })

r = requests.post(FHIR, headers=fhir, json={"resourceType": "Bundle", "type": "transaction", "entry": entries})
print(r.status_code, len(entries), "days saved")
```

And in JavaScript (Node 18+), the night's resting heart rate with a personal API token. That token goes in `Authorization` as is, without `Bearer`:

```js
const uh = { Authorization: process.env.ULTRAHUMAN_PERSONAL_TOKEN };
const fhir = { Authorization: `Bearer ${process.env.ANPHEROS_KEY}`, 'Content-Type': 'application/fhir+json' };

const day = '2026-11-02';
const json = await (await fetch(
  `https://partner.ultrahuman.com/api/v1/partner/daily_metrics?date=${day}`, { headers: uh })).json();

// The night's resting heart rate in /min. Where it sits in the JSON is in Ultrahuman's docs.
const readRestingHr = (json) => { throw new Error('map the Ultrahuman resting heart rate here'); };

await fetch('https://platform.anpheros.com/fhir/R4/Observation', {
  method: 'POST', headers: { ...fhir, 'X-Anpheros-Author-Type': 'device' },
  body: JSON.stringify({
    resourceType: 'Observation', status: 'final',
    category: [{ coding: [{ system: 'http://terminology.hl7.org/CodeSystem/observation-category', code: 'vital-signs' }] }],
    code: { coding: [{ system: 'http://loinc.org', code: '40443-4', display: 'Heart rate --resting' }] },
    subject: { reference: 'Patient/<id>' },
    effectivePeriod: { start: day, end: day },
    valueQuantity: { value: readRestingHr(json), unit: '/min', system: 'http://unitsofmeasure.org', code: '/min' },
    device: { display: 'Ultrahuman Ring AIR' },
  }),
});
```

Paths, parameters and metric names (`steps`, `hr`, `hrv`, `night_rhr`) are from Ultrahuman's developer docs. The JSON layout around them is in those docs, so the two mapping functions are left for you to fill in. The Anpheros side is standard FHIR R4, so the same requests work with any FHIR server.

## Ways to get Ultrahuman data into FHIR

| Path | Status | What you need |
|---|---|---|
| Your backend reads the Ultrahuman API (OAuth), then writes FHIR to Anpheros | **Works today** | An OAuth app in Ultrahuman Vision, the `ring_data` scope (plus `cgm_data` or `profile` if you need them), the person's consent and Ultrahuman's API Agreement for Developers and Partners. Ultrahuman does not say whether new OAuth apps are reviewed |
| A personal API token → your code → Anpheros | **Works today** | Your own data, or a person who enters your data-sharing code in the Ultrahuman app (Profile → Settings → Partner ID) |
| Ultrahuman app → Apple Health → your iPhone app reads HealthKit → Anpheros | **Works today** | HealthKit permissions. Includes HRV, temperature and energy, plus glucose with the M1. See [Apple Health to FHIR](https://developers.anpheros.com/guides/apple-health-fhir) |
| Ultrahuman app → Health Connect → your Android app → Anpheros | **Works today** | Health Connect permissions; Ultrahuman does not list the types. See [Health Connect to FHIR](https://developers.anpheros.com/guides/health-connect-fhir) |
| A direct Ultrahuman connector inside Anpheros | **On our roadmap** | Not available yet. Use the button below to tell us you need it |

<!-- visual:cta-wear-ultrahuman -->

## The Ultrahuman API in short

**Access.** Sign in to the Ultrahuman Vision developer portal to create a personal API token or an OAuth app. A personal token reads your own data. It can read another person's data only if they enter your data-sharing code in the app and you pass their `email`. Ultrahuman does not say whether creating an OAuth app needs approval. The `ring_extended_data` and `workout` scopes are granted on request. Use falls under Ultrahuman's API Agreement for Developers and Partners; no price is stated.

**Auth.** OAuth 2.0 authorization code flow with refresh. Authorize at `https://auth.ultrahuman.com/authorise`, exchange the code at `https://partner.ultrahuman.com/api/partners/oauth/token` (with `client_secret` in the form body), revoke at `https://partner.ultrahuman.com/api/partners/oauth/revoke`. Each refresh returns a new refresh token. The docs give two different access token lifetimes, so read `expires_in` from the token response. Scopes: `profile`, `ring_data`, `cgm_data`, `ring_extended_data` and `workout`.

| Data | Endpoint (GET) | Auth |
|---|---|---|
| Daily ring data: `hr`, `temp`, `hrv`, `steps`, `night_rhr`, `avg_sleep_hrv`, `Sleep`, `recovery_index`, `vo2_max`… | `https://partner.ultrahuman.com/api/partners/v1/user_data/metrics?date=YYYY-MM-DD` | OAuth; extended data and CGM depend on scope |
| Profile | `https://partner.ultrahuman.com/api/partners/v1/user_data/user_info` | OAuth, `profile` |
| Daily metrics: heart rate, HRV, steps, sleep stages, SpO₂, temperature deviation… | `https://partner.ultrahuman.com/api/v1/partner/daily_metrics?date=` or `?start_epoch=&end_epoch=` (at most 7 days, optional `email`) | personal token, without `Bearer` |
| Read-only MCP server for AI assistants | `https://api.ultrahuman.com/mcp` | OAuth 2.1 with PKCE (S256) and dynamic client registration |

Ultrahuman publishes no numeric rate limits for the REST API. The MCP server limits each person by a cost budget, answers 429 with `Retry-After` when it is used up, and accepts request bodies up to 64 KB.

**Recent changes.** The docs now include the MCP server, the `ring_extended_data` and `workout` scopes, and APIs for blood test reports and PPG recordings; none of these are dated. The personal token (`/api/v1/partner/daily_metrics`) and OAuth (`/api/partners/v1/...`) generations exist side by side, with no deprecation notice.

Sources: [Ultrahuman Vision developer docs](https://vision.ultrahuman.com/developer-docs), [OAuth](https://vision.ultrahuman.com/developer-docs?type=oauth), [MCP](https://vision.ultrahuman.com/developer-docs?type=mcp), [API Agreement for Developers and Partners](https://ultrahumanapp.notion.site/API-Agreement-for-Developers-and-Partners-120755317a9180999ce3edcfc1047f58), [HRV in Apple Health](https://www.ultrahuman.com/blog/how-to-access-your-hrv-data-on-apple-health/), [Ultrahuman app on Google Play](https://play.google.com/store/apps/details?id=com.ultrahuman.android), November 2026.

## Ultrahuman data as FHIR Observations

| Ultrahuman data | LOINC | UCUM unit | Note |
|---|---|---|---|
| Steps (`steps`) | 41950-7 | `{steps}` | one per day |
| Heart rate (`hr`) | 8867-4 | `/min` | daily average, minimum and maximum rather than every sample |
| Night resting heart rate (`night_rhr`) | 40443-4 | `/min` | one per night |
| SpO₂ (`spo2`, personal-token API) | 59408-5 | `%` | category vital-signs |
| Sleep (`Sleep`, sleep stages) | 93832-4; 93831-6, 93830-8, 93829-0 | `min` | total, then deep, light, REM |
| HRV (`hrv`, `avg_sleep_hrv`) | see note | `ms` | Ultrahuman does not say whether it is SDNN; use LOINC 80404-7 only for SDNN. See [Wearable data in FHIR](https://developers.anpheros.com/guides/wearable-data-fhir) |
| Skin temperature, temperature deviation | see note | `Cel` | not a body temperature: do not file it under LOINC 8310-5; use your own code |
| Glucose metrics (`cgm_data`, M1) | see note | | CGM metrics, not blood meter readings: do not file them under LOINC 2339-0 |

## Frequently asked questions

### Does Ultrahuman have an API?
Yes. Ultrahuman Vision documents an OAuth API at `https://partner.ultrahuman.com/api/partners/v1`, a personal token API and a read-only MCP server.

### Is the Ultrahuman API free?
Ultrahuman does not state a price. Use falls under its API Agreement for Developers and Partners.

### What is the difference between a personal token and OAuth?
A personal token reads your own data, or the data of people who enter your data-sharing code in their app. OAuth is the usual flow for an app with many users: each person approves your app and the scopes it asks for.

### Does Ultrahuman have an MCP server?
Yes, at `https://api.ultrahuman.com/mcp`. It is read-only and uses OAuth 2.1 with PKCE, with per-scope consent.

### Can I get Ultrahuman data from Apple Health or Health Connect?
Yes. On iPhone, the app syncs ring data to Apple Health, including HRV and temperature (and glucose with the M1). On Android, it syncs with Health Connect.

### Does Anpheros connect to Ultrahuman directly?
Not yet. Today your code reads the Ultrahuman API (or HealthKit / Health Connect on the phone) and writes standard FHIR to Anpheros. A direct Ultrahuman connector is on our roadmap; tell us with the button on this page if you need it.

## Related

- [Wearable APIs: every brand compared](https://developers.anpheros.com/guides/wearable-apis)
- [Wearable data in FHIR (Apple Health, Health Connect)](https://developers.anpheros.com/guides/wearable-data-fhir)
- [Apple Health (HealthKit) to FHIR](https://developers.anpheros.com/guides/apple-health-fhir)
- [Health Connect to FHIR](https://developers.anpheros.com/guides/health-connect-fhir)
- [Oura API to FHIR](https://developers.anpheros.com/guides/oura-api) · [Eight Sleep API to FHIR](https://developers.anpheros.com/guides/eight-sleep-api) · [Google Health API to FHIR](https://developers.anpheros.com/guides/google-health-api)
