Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no cardYour first API call in 2 minutes →
Polar AccessLink API to FHIR: sleep, heart rate and steps (with code)
Read Polar AccessLink v3 sleep, heart rate and steps and store them as FHIR R4 Observations, with user registration, rate limits and phone sync.
The Polar AccessLink API v3 gives your app a person's daily activity and steps, continuous heart rate, sleep, Nightly Recharge, exercises and biosensing data such as SpO₂ and skin temperature after they approve your OAuth client. Anyone with a Polar Flow account can register a client under Polar's AccessLink licence agreement. You can store each reading as a LOINC-coded FHIR R4 Observation with one standard API call. Anpheros does not connect to Polar's cloud itself: your code reads Polar, and Anpheros keeps the record with the person's consent. On phones, Polar Flow writes sleep, steps and workouts to Apple Health, and heart rate, SpO₂, sleep stages and steps to Health Connect.
Read Polar data and store it in FHIR
First, the person's daily activity from Polar AccessLink (an access token from your AccessLink client with the accesslink.read_all scope, after you have registered the person with POST /v3/users):
curl -X GET https://www.polaraccesslink.com/v3/users/activities \
-H 'Accept: application/json' \
-H "Authorization: Bearer $POLAR_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-02T00:00:00+01:00","end":"2026-11-02T23:59:59+01:00"},
"valueQuantity":{"value":9640,"unit":"{steps}","system":"http://unitsofmeasure.org","code":"{steps}"},
"device":{"display":"Polar watch (Polar Flow)"}}'
The same in Python: every night of sleep 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"}
# Nights your backend already read from GET /v3/users/sleep; map Polar's fields
# (listed in the AccessLink reference) to start, end and minutes asleep.
sleep_by_night = [
{"start": "2026-11-01T23:15:00+01:00", "end": "2026-11-02T06:58:00+01:00", "minutes": 432},
{"start": "2026-11-02T23:40:00+01:00", "end": "2026-11-03T07:05:00+01:00", "minutes": 409},
]
entries = [{
"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": "93832-4", "display": "Sleep duration"}]},
"subject": {"reference": "Patient/<id>"},
"effectivePeriod": {"start": n["start"], "end": n["end"]},
"valueQuantity": {"value": n["minutes"], "unit": "min", "system": "http://unitsofmeasure.org", "code": "min"},
"device": {"display": "Polar watch (Polar Flow)"},
},
} for n in sleep_by_night]
r = requests.post(FHIR, headers=fhir, json={"resourceType": "Bundle", "type": "transaction", "entry": entries})
print(r.status_code, len(entries), "nights saved")
And in JavaScript (Node 18+), one day's heart rate summarised from continuous heart rate:
const fhir = { Authorization: `Bearer ${process.env.ANPHEROS_KEY}`, 'Content-Type': 'application/fhir+json' };
// From GET /v3/users/continuous-heart-rate/{date}: your code works out the day's average, minimum and maximum.
const heartRateForDay = { day: '2026-11-02', avg: 66, min: 47, max: 152 };
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: `${heartRateForDay.day}T00:00:00+01:00`, end: `${heartRateForDay.day}T23:59:59+01:00` },
valueQuantity: bpm(heartRateForDay.avg),
component: [
{ code: { text: 'minimum' }, valueQuantity: bpm(heartRateForDay.min) },
{ code: { text: 'maximum' }, valueQuantity: bpm(heartRateForDay.max) },
],
device: { display: 'Polar watch (Polar Flow)' },
}),
});
Polar's response field names are in the AccessLink 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 Polar data into FHIR
| Path | Status | What you need |
|---|---|---|
| Your backend reads the Polar AccessLink API, then writes FHIR to Anpheros | Works today | An AccessLink client (Polar Flow account, licence agreement) and the person's consent to all mandatory consents |
| Polar Flow → Apple Health → your iPhone app reads HealthKit → Anpheros | Works today | HealthKit permissions. One way: sleep, steps, workouts, workout heart rate, weight; no continuous heart rate. See Apple Health to FHIR |
| Polar Flow → Health Connect → your Android app → Anpheros | Works today | Health Connect permissions. Includes heart rate, resting heart rate, SpO₂, sleep stages and steps. See Health Connect to FHIR |
| A direct Polar connector inside Anpheros | On our roadmap | Not available yet. Use the button below to tell us you need it |
The Polar AccessLink API in short
Access. Register a client at admin.polaraccesslink.com with a Polar Flow account; use is governed by the AccessLink Limited License Agreement. Polar does not state a price. Each person must accept every mandatory consent, or the API answers 403. You only get data that reached Polar Flow after the person registered with your client, so there is no backfill of older history.
Auth. OAuth 2.0 authorization code flow. Send the person to https://flow.polar.com/oauth2/authorization?response_type=code&client_id=…, then exchange the code at POST https://polarremote.com/v2/oauth2/token. The code is valid for 10 minutes and works once. The scope is accesslink.read_all. After authorization, register the person with POST /v3/users (the body includes a member-id).
| Data | Endpoint (GET, base https://www.polaraccesslink.com) |
Fields |
|---|---|---|
| Sleep | /v3/users/sleep, /v3/users/sleep/{date}, /v3/users/sleep/available |
nights of sleep |
| Nightly Recharge (ANS, HRV) | /v3/users/nightly-recharge, /v3/users/nightly-recharge/{date} |
overnight recovery |
| Heart rate | /v3/users/continuous-heart-rate/{date}, /v3/users/continuous-heart-rate?from=&to= |
continuous samples |
| Steps and activity | /v3/users/activities, /v3/users/activities/{date}, /v3/users/activities/samples |
daily activity, samples |
| SpO₂ and biosensing | /v3/users/biosensing/spo2, /ecg, /skintemperature, /bodytemperature |
Elixir biosensing data |
| Also | /v3/exercises (with FIT, TCX, GPX), /v3/users/cardio-load, /v3/users/physical-info |
Rate limits grow with your user count: in each 15-minute window, 500 + 20 × users requests; in each 24 hours, 5,000 + 100 × users. A 429 comes with RateLimit-Usage, RateLimit-Limit and RateLimit-Reset headers. Webhooks live under /v3/webhooks (create, activate, deactivate, update, delete), and GET /v3/notifications offers pull notifications with client credentials. Polar has deprecated the transaction-based physical info, daily activity and exercise resources in favour of the non-transactional ones above; the AccessLink changelog runs to January 2026.
Sources: Polar AccessLink API v3 documentation, Polar Flow and Apple Health, Polar Flow and Health Connect, November 2026.
Polar data as FHIR Observations
| Polar data | LOINC | UCUM unit | Note |
|---|---|---|---|
| Sleep duration | 93832-4 | min |
one per night |
| Steps (daily activity) | 41950-7 | {steps} |
one per day |
| Heart rate (continuous) | 8867-4 | /min |
daily average, with minimum and maximum as components rather than every sample |
| SpO₂ (biosensing) | 59408-5 | % |
|
| Body temperature (biosensing) | 8310-5 | Cel |
skin temperature is a different measurement; give it its own code |
| Body weight (physical info) | 29463-7 | kg |
|
| HRV (Nightly Recharge) | see note | ms |
check which statistic Polar reports; do not file it under LOINC 80404-7 unless it is SDNN. See Wearable data in FHIR |
| Nightly Recharge, cardio load | none | Polar scores with no LOINC code; keep them under your own code system or leave them out |
Frequently asked questions
Is the Polar AccessLink API free?
Polar does not state a price. You register a client with a Polar Flow account and accept the AccessLink Limited License Agreement.
How do I get access to the Polar AccessLink API?
Register a client at admin.polaraccesslink.com, send people through the OAuth flow, then register each one with POST /v3/users before you read their data.
What is the Polar AccessLink rate limit?
It scales with your users: 500 + 20 × users requests per 15 minutes and 5,000 + 100 × users per 24 hours. Watch the RateLimit-* headers.
Why does Polar AccessLink return 403?
Polar documents one cause: the person has not accepted all the mandatory consents. Each end user must accept them before their data comes through.
Can I read Polar data from before the person connected?
No. AccessLink returns only data uploaded to Polar Flow after the person registered with your client.
Does Anpheros connect to Polar directly?
Not yet. Today your code reads the Polar AccessLink API (or HealthKit / Health Connect on the phone) and writes standard FHIR to Anpheros. A direct Polar 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
- Garmin API to FHIR · Suunto API to FHIR · COROS 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/polar-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 →