AnpherosAnpheros PlatformDevelopers

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

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.

Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no cardYour first API call in 2 minutes →

Product updates by email

New features, guides and the end of the beta. One email a month at most.

Send me occasional Anpheros Platform updates by email (new features, API changes, guides). I'll confirm by email and can unsubscribe in one click from any email. Privacy