Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no cardYour first API call in 2 minutes →
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.
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):
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_…):
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.
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:
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 |
| Ultrahuman app → Health Connect → your Android app → Anpheros | Works today | Health Connect permissions; Ultrahuman does not list the types. See Health Connect to FHIR |
| A direct Ultrahuman connector inside Anpheros | On our roadmap | Not available yet. Use the button below to tell us you need it |
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, OAuth, MCP, API Agreement for Developers and Partners, HRV in Apple Health, Ultrahuman app on Google Play, 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 |
| 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
- Wearable data in FHIR (Apple Health, Health Connect)
- Apple Health (HealthKit) to FHIR
- Health Connect to FHIR
- Oura API to FHIR · Eight Sleep API to FHIR · Google Health API to FHIR
Ask your AI
Paste this into Claude, ChatGPT, Cursor or Claude Code. Your assistant reads this guide and adapts it to your code.
Read https://developers.anpheros.com/guides/ultrahuman-api.md and help me apply this guide to my own project. Use the Anpheros sandbox (base URL https://platform.anpheros.com) with my API key from the ANPHEROS_KEY environment variable, never written in the code. Give me complete, runnable code, the response I should expect, and how to fix the errors in https://developers.anpheros.com/guides/troubleshooting.md if a call fails.Open in ClaudeOpen in ChatGPTThis guide as MarkdownBuild the whole integration with an AI coding tool
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no cardYour first API call in 2 minutes →