Prerequisites
Before you begin, ensure you have:- Open Wearables instance running (self-hosted or cloud)
- API Key generated from the settings tab in Open Wearables Developer portal
- Your backend framework ready (examples use Python/FastAPI, but concepts apply to any language)
Environment Variables
Add these to your application’s environment:Authentication
SDK Authentication (Mobile Apps)
If you’re building a mobile app that pushes health data (e.g., Apple Health from iOS), use SDK tokens instead of API keys. SDK tokens are user-scoped JWT tokens that only authorize data push endpoints.- When to Use
- How It Works
| Authentication | Use Case |
|---|---|
| API Key | Backend-to-backend integration, fetching data, OAuth flows |
| SDK Token | Mobile apps pushing health data to Open Wearables |
Step 1: Create an Application
First, register an application to getapp_id and app_secret:
Step 2: Exchange Credentials for User Token
When a user logs into your mobile app, your backend exchanges the app credentials for a user-scoped token:Step 3: Use Token in Mobile App
The mobile app uses this token to push health data to the SDK sync endpoints:SDK tokens are only valid for
/sdk/ endpoints. All other API endpoints will return 401 for SDK tokens. Use API keys for those endpoints. The user_id in the URL must match the user the token was issued for.Integration Flow Overview
Step 1: User Registration
When a user registers in your application, create a corresponding user in Open Wearables.Create User
All fields in the create-user payload are optional - you can evenPOST an empty body and get back a valid user.
| Field | Type | Required | Notes |
|---|---|---|---|
email | string | Optional | Must be a valid email if provided. Not enforced unique - see the note below. |
first_name | string | Optional | Max 100 characters. Useful for display in the Open Wearables dashboard. |
last_name | string | Optional | Max 100 characters. Useful for display in the Open Wearables dashboard. |
Response
null.
Update Your User Model
Add a field to store the Open Wearables user ID:Open Wearables does not enforce uniqueness on
email, first_name, or last_name - calling POST /api/v1/users twice with the same email will happily create two separate user records. Your backend is the source of truth for user identity and is responsible for ensuring you only create one Open Wearables user per user in your system (e.g. by storing open_wearables_user_id on your own user row and checking it before creating).Step 2: Connect Wearable Provider
Connect users to their wearable devices via OAuth.List Available Providers
The list of providers is dynamic - which ones are enabled depends on your instance’s configuration and whether OAuth credentials are set up. Fetch it at runtime rather than hardcoding a list:| Parameter | Default | Description |
|---|---|---|
enabled_only | false | Return only providers enabled in your instance |
cloud_only | false | Return only cloud-based (OAuth) providers, excludes SDK-only providers like Apple Health |
Get Authorization URL
Response
Frontend Integration Flow
Provider redirects to Open Wearables callback
Open Wearables handles the OAuth callback automatically.
Custom Redirect URI
To redirect users back to your app after OAuth:Check Connection Status
Verify a user’s connected providers:Response
Step 3: Historical Backfill (Automatic)
You do not need to explicitly trigger a sync after OAuth completes. On the first successful provider connection, Open Wearables automatically dispatches a historical backfill:- Up to 90 days for pull-based providers (Polar, Suunto)
- Up to 30 days for Garmin (webhook-based backfill capped at 30 days from the user’s consent date - further back is not retrievable)
HISTORICAL_SYNC_ON_CONNECT flag (default: true). It’s a grace-period flag introduced in v0.4.3 - the default will flip to false in a future release and the flag will eventually be removed. Once you’re ready to control historical backfill yourself, set HISTORICAL_SYNC_ON_CONNECT=false and call POST /api/v1/providers/{provider}/users/{user_id}/sync/historical explicitly. See PR #897 for background.
Ongoing sync after the initial backfill happens automatically - webhooks push updates for providers that support them, and pull-based providers are polled on a schedule. Your integration only needs to connect the user; fetching data (next step) is the read side.
Step 4: Retrieve Health Data
All data endpoints require theX-Open-Wearables-API-Key header and return a PaginatedResponse wrapper:
cursor=<next_cursor> until has_more is false. The health-scores endpoint uses offset/limit instead of a cursor but returns the same envelope.
Activity summary
Daily aggregates: steps, distance, floors, active/total kcal, active/sedentary minutes, intensity minutes, heart-rate stats.
Sleep summary
Daily sleep: duration, efficiency, stages (awake/light/deep/rem minutes), interruptions, naps, avg HR/HRV/SpO2.
Body summary
Point-in-time body metrics grouped into
slow_changing (weight, height, BMI, body fat), averaged (resting HR, HRV over 1-7 days) and latest (temperature, blood pressure within a recency window).Timeseries
Granular samples for any
SeriesType (heart rate, steps, SpO2, etc.) with optional resolution bucketing (raw, 1min, 5min, 15min, 1hour).Workouts
Workout sessions with type, duration, calories, distance, avg/max heart rate, pace, elevation gain, and
source provider metadata.Health scores
Provider-computed scores (sleep, recovery, readiness, stress, body battery, strain) with optional
components breakdown. Filter by category or provider.Response Shapes
- ActivitySummary
- SleepSummary
- BodySummary
- TimeSeriesSample
- Workout
- HealthScore
date and source is nullable.Complete Integration Example
Here’s a complete Python client class for Open Wearables integration:Troubleshooting
Docker container can't reach Open Wearables on localhost
Docker container can't reach Open Wearables on localhost
If your app runs in Docker and Open Wearables runs on the host machine:
docker-compose.yml
401 Unauthorized even with correct API key
401 Unauthorized even with correct API key
Multiple users created for the same email
Multiple users created for the same email
email has no unique constraint in Open Wearables - calling POST /api/v1/users twice with the same email will create two separate records. Your backend is the source of truth for user identity, so store the Open Wearables id (UUID) on your own user row the first time you create it, and reuse that ID for every subsequent call:external_user_id field is still DB-unique, but it is deprecated and no data-fetching endpoint accepts it - don’t use it for deduplication.Data endpoints return empty results right after OAuth
Data endpoints return empty results right after OAuth
Historical backfill is dispatched asynchronously on connect and can take anywhere from seconds to several minutes depending on the provider and the amount of history. Poll
GET /api/v1/users/{user_id}/connections - last_synced_at flips from null to a timestamp once the first sync finishes. For Garmin’s async export, full history can take hours.If HISTORICAL_SYNC_ON_CONNECT=false in your instance, no backfill runs automatically - call POST /api/v1/providers/{provider}/users/{user_id}/sync/historical yourself.Timeseries endpoint returns empty data
Timeseries endpoint returns empty data
start_time, end_time, and types are all required. types is repeated:SeriesType you’re requesting exists for this user - check GET /api/v1/users/{user_id}/summaries/data for a breakdown of what’s been ingested.OAuth callback not redirecting to my app
OAuth callback not redirecting to my app
Pass the
redirect_uri parameter when getting the authorization URL:Next Steps
API Reference
Complete API documentation with all endpoints.
Provider Setup
Configure OAuth credentials for each provider.
Data Model
Understand the unified health data model.
GitHub
View source code and contribute.

