Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no cardYour first API call in 2 minutes →
Withings API to FHIR: heart rate, SpO₂, sleep and weight (with code)
Read the Withings Public API and store measures, sleep and activity as FHIR R4 Observations, with OAuth, the 120/min limit and LOINC mapping.
The Withings Public API gives your app a person's measures (weight and body composition, blood pressure, heart rate, SpO₂, temperature), activity and steps, sleep and ECG after they approve your OAuth app. Individuals and companies can use it without a formal contract; Withings offers paid plans for higher volume. You can store each reading as a LOINC-coded FHIR R4 Observation with one standard API call. Anpheros does not connect to Withings' cloud itself: your code reads Withings, and Anpheros keeps the record with the person's consent. On Android, the Withings app shares data with Health Connect in both directions.
Read Withings data and store it in FHIR
First, heart rate and SpO₂ measures from Withings (an access token from your Withings OAuth app with the user.metrics scope; every Withings call is a POST with an action):
curl -X POST -H "Authorization: Bearer $WITHINGS_TOKEN" \
"https://wbsapi.withings.net/measure?action=getmeas&meastypes=11,54&category=1&startdate=1793664000&enddate=1793750400"
Then one SpO₂ reading 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":"vital-signs"}]}],
"code":{"coding":[{"system":"http://loinc.org","code":"59408-5","display":"Oxygen saturation in Arterial blood by Pulse oximetry"}]},
"subject":{"reference":"Patient/<id>"},
"effectiveDateTime":"2026-11-03T07:14:00+01:00",
"valueQuantity":{"value":96,"unit":"%","system":"http://unitsofmeasure.org","code":"%"},
"device":{"display":"Withings device (Withings app)"}}'
The same in Python: every SpO₂ reading becomes one Observation, sent together in one transaction Bundle.
import os, requests
FHIR = "https://platform.anpheros.com/fhir/R4"
fhir = {"Authorization": f"Bearer {os.environ['ANPHEROS_KEY']}", "Content-Type": "application/fhir+json",
"X-Anpheros-Author-Type": "device"}
# SpO₂ readings your backend already read with getmeas (measure type 54);
# parse the response as Withings' API reference describes.
spo2_readings = [("2026-11-02T07:20:00+01:00", 97), ("2026-11-03T07:14:00+01:00", 96)]
entries = [{
"request": {"method": "POST", "url": "Observation"},
"resource": {
"resourceType": "Observation", "status": "final",
"category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "vital-signs"}]}],
"code": {"coding": [{"system": "http://loinc.org", "code": "59408-5",
"display": "Oxygen saturation in Arterial blood by Pulse oximetry"}]},
"subject": {"reference": "Patient/<id>"},
"effectiveDateTime": when,
"valueQuantity": {"value": pct, "unit": "%", "system": "http://unitsofmeasure.org", "code": "%"},
"device": {"display": "Withings device (Withings app)"},
},
} for when, pct in spo2_readings]
r = requests.post(FHIR, headers=fhir, json={"resourceType": "Bundle", "type": "transaction", "entry": entries})
print(r.status_code, len(entries), "readings saved")
And in JavaScript (Node 18+), the night's lowest and highest heart rate from the sleep summary:
const fhir = { Authorization: `Bearer ${process.env.ANPHEROS_KEY}`, 'Content-Type': 'application/fhir+json' };
// From POST /v2/sleep with action=getsummary and data_fields=hr_min,hr_max (scope user.sleepevents).
const night = { start: '2026-11-02T23:10:00+01:00', end: '2026-11-03T06:50:00+01:00', hrMin: 51, hrMax: 78 };
const bpm = (value) => ({ value, unit: '/min', system: 'http://unitsofmeasure.org', code: '/min' });
await fetch('https://platform.anpheros.com/fhir/R4/Observation', {
method: 'POST', headers: fhir,
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: '8867-4', display: 'Heart rate' }] },
subject: { reference: 'Patient/<id>' },
effectivePeriod: { start: night.start, end: night.end },
component: [
{ code: { text: 'minimum' }, valueQuantity: bpm(night.hrMin) },
{ code: { text: 'maximum' }, valueQuantity: bpm(night.hrMax) },
],
device: { display: 'Withings device (Withings app)' },
}),
});
Request names (getmeas, meastypes, getsummary, hr_min, hr_max) are from Withings' OpenAPI specification; the response layout is in its API reference, so the examples start from values your code has already read. The Anpheros side is standard FHIR R4, so the same requests work with any FHIR server. To avoid copies when a day is read again, give each Observation a stable identifier, as shown in Wearable data in FHIR.
Ways to get Withings data into FHIR
| Path | Status | What you need |
|---|---|---|
| Your backend reads the Withings Public API, then writes FHIR to Anpheros | Works today | A Withings developer app and the person's OAuth consent. No contract for the Public API; paid plans for higher volume |
| Withings app → Health Connect → your Android app → Anpheros | Works today | Health Connect permissions. The person chooses the export categories in the Withings app. See Health Connect to FHIR |
| Withings app → Apple Health → your iPhone app → Anpheros | Works today | Withings Health Mate writes to Apple Health when the person turns it on; Withings does not publish the full list of types. See Apple Health to FHIR |
| A direct Withings connector inside Anpheros | On our roadmap | Not available yet. Use the button below to tell us you need it |
The Withings API in short
Access. The Public API is meant for individuals and partners without a formal contract. Withings also lists higher-volume plans, an Enterprise plan and Withings Pro products; prices are not shown on the public page. A few services, such as oauth2-listusers, are only available under contract.
Auth. OAuth 2.0 authorization code flow. Send the person to https://account.withings.com/oauth2_user/authorize2 with response_type=code, client_id, scope, redirect_uri and state (mode=demo gives demo data). The code is valid for only 30 seconds. Exchange it with POST https://wbsapi.withings.net/v2/oauth2, action=requesttoken, plus a nonce and a signature computed with your client secret. Access tokens last 3 hours and refresh tokens 1 year; the old refresh token stays valid for 8 hours after a new one is issued, or until the new access token is used. Scopes, comma-separated: user.info, user.metrics, user.activity, user.sleepevents.
| Data | Endpoint (POST, base https://wbsapi.withings.net) |
Fields |
|---|---|---|
| Measures | /measure, action=getmeas |
meastype or meastypes, category, startdate, enddate, lastupdate; types include 11 heart pulse, 54 SpO₂, 9 diastolic blood pressure, 73 skin temperature, 123 VO₂ max |
| Activity and steps | /v2/measure, action=getactivity (daily) or getintradayactivity |
intraday can include heart rate, SpO₂, rmssd, sdnn1, hrv_quality |
| Sleep | /v2/sleep, action=get or getsummary |
get: hr, rr, snoring, sdnn_1, rmssd; getsummary: startdateymd, enddateymd, data_fields such as hr_min, hr_max, rmssd_start_avg |
| ECG | /v2/heart, action=list or get |
|
| Webhooks | /notify, action=subscribe, list, get, update, revoke |
The standard API allows 120 requests per minute per application, and the Enterprise plan raises that. Use webhooks (notify) to learn when new data arrives instead of polling. Withings has reorganised its developer docs into a v3 guide covering the Public API, the Advanced Health Data API and the Research API.
Sources: Withings Public API overview, authorization URL, access and refresh tokens, OpenAPI specification, keeping data up to date, Withings and Health Connect, November 2026.
Withings data as FHIR Observations
| Withings data | LOINC | UCUM unit | Note |
|---|---|---|---|
| Heart pulse (type 11) | 8867-4 | /min |
|
| SpO₂ (type 54) | 59408-5 | % |
|
| Blood pressure | 85354-9 with 8480-6 and 8462-4 | mm[Hg] |
one Observation, systolic and diastolic as components |
| Body weight | 29463-7 | kg |
|
Steps (getactivity) |
41950-7 | {steps} |
one per day |
| Sleep duration | 93832-4 | min |
one per night |
HRV (rmssd, sdnn_1) |
see note | ms |
Withings returns both. Only an SDNN value may use LOINC 80404-7; never file rmssd under it. See Wearable data in FHIR |
Respiratory rate in sleep (rr) |
9279-1 | /min |
Frequently asked questions
Is the Withings API free?
The Withings Public API needs no formal contract. Withings sells plans for higher volume and enterprise use, but the prices are not on its public page.
What is the Withings API rate limit?
120 requests per minute per application on the standard API. The Enterprise plan has higher limits.
Why does my Withings authorization code stop working?
The code from the authorization URL is valid for only 30 seconds. Exchange it for tokens straight away on your server.
How long do Withings access tokens last?
Access tokens last 3 hours and refresh tokens 1 year. After a refresh, the old refresh token stays valid for 8 hours or until you use the new access token.
Which Withings HRV value goes under LOINC 80404-7?
Only an SDNN value, such as sdnn_1 from the sleep data. rmssd is a different statistic and needs its own code.
Does Anpheros connect to Withings directly?
Not yet. Today your code reads the Withings API (or Health Connect on the phone) and writes standard FHIR to Anpheros. A direct Withings 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 · Garmin API to FHIR · Dexcom 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/withings-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 →