Skip to main content

Documentation Index

Fetch the complete documentation index at: https://openwearables.io/docs/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Each wearable provider has different requirements and parameters for syncing data. This guide covers the specifics for each supported provider.
Provider names in API paths must be lowercase: garmin, polar, suunto, whoop, apple

Garmin

Garmin uses a webhook-only delivery model — there is no REST polling path. It implements two capability flags:
  • webhook_stream — Garmin pushes the complete data payload to your webhook endpoint in real time as the user syncs their device.
  • webhook_callback — For historical backfill, a backfill task is dispatched asynchronously; Garmin delivers the results to your webhook callback URL.
Because Garmin has no rest_pull capability, live_sync_configurable is false and live_sync_mode is fixed at "webhook".

Historical backfill

To trigger a historical backfill (up to 30 days), call the dedicated endpoint:
curl -X POST "http://localhost:8000/api/v1/providers/garmin/users/{user_id}/sync/historical" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"
The server enqueues the backfill task and Garmin delivers the data asynchronously to your registered webhook endpoint — no time-range parameters are accepted or required.
Do not use the generic /sync REST endpoint for Garmin — Garmin has no server-side REST pull path. All data arrives via webhook push.

Polar

Polar uses the AccessLink API with simpler sync requirements.

Sync Parameters

ParameterDefaultDescription
samplesfalseInclude detailed sample data (HR samples, etc.)
zonesfalseInclude heart rate zone information
routefalseInclude GPS route data

Example

# Basic sync
curl -X POST "http://localhost:8000/api/v1/providers/polar/users/{user_id}/sync" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"

# With additional data
curl -X POST "http://localhost:8000/api/v1/providers/polar/users/{user_id}/sync?samples=true&zones=true&route=true" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"
Enabling samples, zones, and route increases sync time but provides more detailed workout data.

Suunto

Suunto supports both workouts and 24/7 data (sleep, recovery, activity samples).

Sync Parameters

ParameterDefaultDescription
since0Unix timestamp to sync from (0 = all available)
limit50Items per request (max: 100)
offset0Pagination offset
filter_by_modification_timetrueFilter by modification vs creation time

Data Types

ValueDescription
workoutsWorkout/exercise sessions
24724/7 data: sleep, recovery, activity samples
allBoth workouts and 24/7 data

Example

# Sync all data from last 30 days
THIRTY_DAYS_AGO=$(date -v-30d +%s)
curl -X POST "http://localhost:8000/api/v1/providers/suunto/users/{user_id}/sync?data_type=all&since=${THIRTY_DAYS_AGO}&limit=100" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"

# Sync only workouts
curl -X POST "http://localhost:8000/api/v1/providers/suunto/users/{user_id}/sync?data_type=workouts" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"

Whoop

Whoop uses OAuth 2.0 and supports both workouts and 24/7 data (sleep, recovery, body measurements).

Setup

  1. Create an application at developer.whoop.com
  2. Set your redirect URI to http://localhost:8000/api/v1/oauth/whoop/callback
  3. Configure environment variables:
WHOOP_CLIENT_ID=your-client-id
WHOOP_CLIENT_SECRET=your-client-secret
WHOOP_REDIRECT_URI=http://localhost:8000/api/v1/oauth/whoop/callback
WHOOP_DEFAULT_SCOPE=offline read:cycles read:sleep read:recovery read:workout

Sync Parameters

Whoop does not require provider-specific query parameters. Use the standard data_type parameter to control what gets synced.
data_type ValueDescription
workoutsWorkout/exercise sessions
247Sleep sessions, recovery metrics, body measurements
allBoth workouts and 24/7 data
When no date range is specified, Whoop defaults to syncing the last 30 days of data.

Data Collected

Workouts: heart rate (avg/max), energy burned, distance, elevation gain, duration. Sleep (247): total duration, time in bed, efficiency score, sleep stages (deep, light, REM, awake), nap detection. Recovery (247): recovery score, resting heart rate, HRV (RMSSD), SpO2 percentage, skin temperature. Body measurements (247): height, weight.

Example

# Sync all Whoop data
curl -X POST "http://localhost:8000/api/v1/providers/whoop/users/{user_id}/sync?data_type=all" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"

# Sync only workouts
curl -X POST "http://localhost:8000/api/v1/providers/whoop/users/{user_id}/sync?data_type=workouts" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"

# Sync only sleep & recovery data
curl -X POST "http://localhost:8000/api/v1/providers/whoop/users/{user_id}/sync?data_type=247" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"

Apple Health

Apple Health data is imported via the mobile SDK rather than cloud API sync.
Apple Health requires the Open Wearables mobile SDK. Cloud sync is not available for Apple Health.

Checking Connection Status

Before syncing, verify the user has an active connection:
curl -X GET "http://localhost:8000/api/v1/users/{user_id}/connections" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"
Response:
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "user_id": "user-uuid",
    "provider": "garmin",
    "status": "active",
    "last_synced_at": "2025-01-15T12:00:00Z",
    "created_at": "2025-01-15T10:00:00Z",
    "updated_at": "2025-01-15T12:00:00Z"
  }
]
Connection status can be: active, revoked, or expired. If no connection exists for a provider, the user needs to complete OAuth first.

Available Providers

Check which providers are enabled in your instance:
curl -X GET "http://localhost:8000/api/v1/oauth/providers?enabled_only=true" \
  -H "X-Open-Wearables-API-Key: YOUR_API_KEY"
Response:
[
  {
    "provider": "garmin",
    "name": "Garmin",
    "has_cloud_api": true,
    "is_enabled": true,
    "icon_url": "/static/provider-icons/garmin.svg",
    "live_sync_mode": "webhook",
    "live_sync_configurable": false
  }
]
icon_url is a relative URL (e.g., /static/provider-icons/garmin.svg). Resolve it against your API base URL to get the full path - for example, https://your-api.example.com/static/provider-icons/garmin.svg.