# 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.

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

**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`):

```bash
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_…`):

```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-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.

```python
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:

```js
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](https://developers.anpheros.com/guides/wearable-data-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](https://developers.anpheros.com/guides/apple-health-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](https://developers.anpheros.com/guides/health-connect-fhir) |
| A direct Polar connector inside Anpheros | **On our roadmap** | Not available yet. Use the button below to tell us you need it |

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

## 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](https://www.polar.com/accesslink-api/), [Polar Flow and Apple Health](https://support.polar.com/us-en/support/connecting_polar_flow_with_apple_health), [Polar Flow and Health Connect](https://support.polar.com/en/flow-app-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](https://developers.anpheros.com/guides/wearable-data-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](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)
- [Garmin API to FHIR](https://developers.anpheros.com/guides/garmin-api) · [Suunto API to FHIR](https://developers.anpheros.com/guides/suunto-api) · [COROS API to FHIR](https://developers.anpheros.com/guides/coros-api)
