Skip to main content

python-polsen

An asynchronous Python client for the Polsen Health API (v1), the service exposing physiological and contextual data collected by Polsen devices and processed by the Polsen App for scientific and research use.

The client wraps the endpoints described in the official OpenAPI specification. Every request is authenticated with an X-API-KEY header, and responses are decoded to plain Python objects.

Requires Python 3.14 or newer.

Getting an API key

Access is gated by groups and user-controlled sharing, both managed in the Polsen Health Together Dashboard. In short:

  1. Create an account.
  2. Enable data sharing in your account settings.
  3. Create a group.
  4. Generate an API key linked to that group.

See the Data sharing & access guide for the full details, including how to request access to another user's data.

Quickstart

import asyncio

from python_polsen.polsen import PolsenClient
from python_polsen.types import TimeseriesType


async def main() -> None:
    async with PolsenClient(api_key="YOUR_API_KEY") as client:
        user_ids = await client.get_user_ids()

        user = await client.get_user(user_ids[0])

        heart_rate = await client.get_timeseries(
            user_ids[0],
            TimeseriesType.HEART_RATE,
            start_date="2026-10-17",
            end_date="2026-10-17",
        )
        print(user, heart_rate)


asyncio.run(main())

PolsenClient is an async context manager, so the underlying aiohttp session is always closed on exit. You may also inject your own session via the session argument and call await client.close() manually.

Endpoints

Method Endpoint Returns
get_user_ids() GET /v1/keys/users User ids (uid_...) reachable by the key
get_user(user_id) GET /v1/user/{user_id} User profile
get_timeseries(user_id, timeseries_type, *, start_date, end_date, days=None, cursor=None) GET /v1/timeline/timeseries/{user_id}/{mtype} Columnar MeasurementJSONPage
get_sleep(user_id, *, start_date, end_date, days=None, cursor=None) GET /v1/timeline/events/sleep/{user_id} Page[Sleep]
get_activities(user_id, *, start_date, end_date, days=None, cursor=None) GET /v1/timeline/events/activities/{user_id} Page[ActivityModel]
get_checkins(user_id, *, start_date, end_date, days=None, cursor=None) GET /v1/timeline/events/checkins/{user_id} Page[CheckinModel]
get_timezone(user_id, *, start_date, end_date, days=None, cursor=None) GET /v1/timeline/events/timezones/{user_id} Page[TimezoneResponse]
get_crown_presses(user_id, *, start_date, end_date, days=None, cursor=None) GET /v1/timeline/events/crown_presses/{user_id} Page[CrownPressResponse]
get_overview(user_id, overview_metric, *, start_date, end_date) GET /v1/overview/{user_id}/{stype} List of per-day metrics
get_feelings(user_id, feeling_type, *, start_date, end_date, days=None, cursor=None) GET /v1/feelings/{user_id}/{ftype} Page[FeelingsModel]

Enums

Request parameters that select a metric or category are exposed as StrEnum members in python_polsen.types:

Enum Used by
TimeseriesType get_timeseries (HEART_RATE, STEPS, MOTION, ...)
OverviewMetric get_overview (HRV, RHR, SLEEP_DURATION, ...)
FeelingType get_feelings (DAY, SLEEP)

Pagination

Event and feelings endpoints return a { "data": [...], "next_cursor": ... } envelope. The start_date and end_date range is required; pass it as keyword arguments:

page = await client.get_sleep(
    user_id,
    start_date="2026-10-01",
    end_date="2026-10-07",
)

while page.get("next_cursor"):
    page = await client.get_sleep(
        user_id,
        start_date="2026-10-01",
        end_date="2026-10-07",
        cursor=page["next_cursor"],
    )

Time-series responses use a columnar MeasurementJSONPage ({"data": {"datetime": [...], "value": [...]}, "next_cursor": ...}) rather than a list of rows.

Error handling

Non-2xx responses are raised as exceptions derived from PolsenError:

Exception HTTP status
AuthenticationError 401 / 403
NotFoundError 404
ValidationError 422
RateLimitError 429
APIError any other non-2xx

Each exception carries the RFC 7807 problem members (title, detail, code, request_id, ...) as attributes. RateLimitError also exposes retry_after; requests are retried automatically up to _max_retries (default 3) before the error propagates.

from python_polsen.exceptions import NotFoundError

try:
    user = await client.get_user("uid_unknown")
except NotFoundError as exc:
    print(exc.code, exc.request_id)

Metadata

Release files for python-polsen 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-polsen 0.2.0
File Size Uploaded
python_polsen-0.2.0.tar.gz 10.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-polsen 0.2.0
File Interpreter ABI Platform
python_polsen-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 24.5 kB

Release files / python_polsen-0.2.0.tar.gz

Download URL python_polsen-0.2.0.tar.gz
Size 10.5 kB
Tags Source
SHA-256 checksum
How to use checksums
03897c601df9df201206f2743b515823ad7b7f13ce4c5c909dfe0139d4e09526
BLAKE2b-256 checksum
How to use checksums
002c8ddec0faab4fbc512798e8257ee52744751697e92b608cd7c6298f2b2033
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release files / python_polsen-0.2.0-py3-none-any.whl

Download URL python_polsen-0.2.0-py3-none-any.whl
Size 14.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8019565164abfc96bbafe00c75bfc5ffec7a90b929d1585d942d7765345398c1
BLAKE2b-256 checksum
How to use checksums
754f299ae71c92195fabfab27b409b6555858b744d0a026fa8f1b1e4c9b63e05
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page