Back to blog

Garmin Connect API: developer guide for activities and health metrics

Open Wearables Team · · 11 min read

Key takeaways

  • Garmin Health API requires partner program approval: full server-side access to user health data is not available as a self-serve developer credential.
  • Garmin uses push-based delivery: data is sent to your registered callback URLs when a user syncs their device. There is no polling endpoint.
  • Authentication uses OAuth 2.0 with PKCE, and connecting an account automatically kicks off historical backfill for the user.
  • Available data is unusually rich: 100+ activity types, GPS, heart rate, HRV, sleep, Body Battery, stress, VO2 max, respiration, and more.
  • python-garminconnect is unofficial: it scrapes Garmin Connect session data rather than using the Health API. Useful for personal projects, fragile for production.
  • 30-day historical backfill is available when a user first connects.
  • Open Wearables handles OAuth 2.0 authentication, push notification registration, callback processing, and normalization. You query unified endpoints instead of managing Garmin-specific infrastructure.

Introduction

Garmin occupies a specific position in the wearable market. Their devices are trusted by endurance athletes, military users, outdoor adventurers and sports scientists who prioritize battery life, GPS accuracy and sensor depth over sleek consumer aesthetics. The Garmin API reflects this heritage: it covers over 100 sport types with detailed per-activity data including running dynamics, cycling power metrics, swim stroke analysis and altitude tracking.

For developers building serious fitness or performance applications, Garmin data is uniquely rich. But the API is also one of the more technically demanding integrations in the wearable space. Data delivery is push-based, meaning Garmin sends data to your server rather than waiting for you to request it, and it uses OAuth 2.0 with PKCE for authentication. Full access requires a partnership application rather than a self-serve developer account.

This guide covers what the Garmin API provides, how its push architecture works, what authentication requires in practice, and how to handle the operational complexity of a production Garmin integration.

What Garmin exposes

Garmin's data coverage is broader than any other wearable API in terms of sport types and activity metrics. Over 100 sport types are supported with type-specific data. Running activities include not just time, distance and heart rate but also running dynamics: cadence, stride length, ground contact time, vertical oscillation, vertical ratio and ground contact time balance. These are signals that most wearable APIs do not expose at all. Cyclists get power (watts, normalized power, intensity factor, training stress score), cadence and FTP-based training load. Swimmers get stroke type, SWOLF score, strokes per length and pool length.

For health and recovery monitoring, Garmin provides: Body Battery (a proprietary 0-100 energy indicator that accounts for HRV, stress and sleep), daily stress score, resting heart rate, nightly HRV, sleep staging and score, respiration rate, SpO2, and VO2 Max estimated from running and cycling activities. Body composition is available for users with compatible Garmin scales (Garmin Index) including weight, BMI, body fat percentage, muscle mass, bone mass and body water.

Daily summaries aggregate step count, floors climbed, active calories, BMR calories, intensity minutes and stress levels throughout the day.

Push-based delivery

The fundamental architectural difference between Garmin and most other wearable APIs is that Garmin delivers data to you rather than waiting for you to fetch it. This is not a webhook notification that triggers a subsequent API call. Garmin pushes the full data payload directly to your registered callback URL when a user syncs their device.

You register separate callback URLs for each data type you want to receive: activities, daily summaries, epochs (activity-level data by minute), sleep, body composition, stress, user metrics (VO2 Max estimates), pulse oximetry, respiration and HRV. Each has its own endpoint. When a Garmin device syncs, Garmin's backend processes the data and POSTs it to the appropriate URLs for all users who have authorized your application.

The practical implications of this architecture are significant. Your callback endpoints must be publicly reachable with valid HTTPS certificates at all times. If your endpoint is down when Garmin attempts delivery, Garmin will retry, but there is no guarantee of delivery. You must design for idempotent processing because Garmin may send the same data multiple times. And you must respond to each incoming request with HTTP 200 within a few seconds, which means your handler needs to queue the actual processing asynchronously rather than doing it inline.

In practice, you register a single webhook endpoint with Garmin for all data types:

            https://<your-domain>/api/v1/garmin/webhooks/push
          

Garmin sends two kinds of webhook notifications to this endpoint. PING notifications carry callback URLs that your server then fetches to retrieve the actual data:

            {
  "sleeps": [{"userId": "garmin-uid", "callbackURL": "https://..."}],
  "dailies": ["..."],
  "activities": ["..."]
}
          

PUSH notifications, used for some data types, deliver the payload directly in the webhook body instead of a callback URL. Either way, all 16 Garmin data types are handled by the same webhook endpoint regardless of whether they're part of historical backfill.

Authentication: OAuth 2.0 with PKCE

Garmin uses OAuth 2.0 with PKCE (Proof Key for Code Exchange). The flow is standard for anyone who has implemented OAuth 2.0 before: your frontend redirects the user to an authorize endpoint, the user grants permissions on Garmin's site, and Garmin redirects back to a callback endpoint that exchanges the authorization code for tokens.

The flow through Open Wearables:

            GET /api/v1/oauth/{provider}/authorize
          

The frontend redirects the user here. After the user grants permissions on Garmin's site, Garmin redirects back to:

            GET /api/v1/oauth/{provider}/callback
          

The callback handler creates or updates the user's connection record, dispatches an initial sync task, and for Garmin specifically, kicks off the historical backfill automatically. There is no manual "Sync Now" step for Garmin: connecting the account starts the backfill.

One Garmin-specific detail to know upfront: if the user does not grant the HISTORICAL_DATA_EXPORT permission during authorization, all backfill requests will return 403 and all 5 backfill data types fail together.

Access requirements

Garmin's Health API is not available as a self-serve developer credential. Full server-side access to user health data through the push notification system requires applying to Garmin's Health API partner program. The application asks about your use case, your company, your data handling practices and your integration plans.

Garmin offers different access tiers. Consumer-facing applications can apply through one channel. Research and clinical applications have a separate pathway. The approval process typically takes days to weeks depending on the completeness of your application and Garmin's current review queue.

For prototyping and development purposes, Garmin provides a health API sandbox that allows testing without full partner approval. The sandbox generates synthetic data that mirrors the structure of real device data, which lets you build and validate your push handler logic before real user data arrives.

Once your evaluation app is approved and created in the Garmin Developer Portal, configure Open Wearables with the resulting credentials:

            # Garmin OAuth Credentials
GARMIN_CLIENT_ID=your_client_id_here
GARMIN_CLIENT_SECRET=your_client_secret_here
GARMIN_REDIRECT_URI=https://yourdomain.com/api/v1/oauth/garmin/callback
          

The unofficial alternative: python-garminconnect

If you search for "garmin api" on GitHub, the most popular result is python-garminconnect. It is an unofficial library that works by authenticating to Garmin Connect as a user would through a browser, then scraping session data.

For personal projects and data exploration, it works. For production applications with real users, it has significant limitations: it depends on undocumented internal endpoints that Garmin can change without notice, it requires users to provide their Garmin Connect credentials directly to your application rather than through OAuth, and it is not a supported integration path that Garmin acknowledges or maintains compatibility with.

If your use case is a personal health dashboard or a one-off data export, python-garminconnect is a reasonable tool. If you are building a product with users who are not you, the official Health API with proper OAuth is the right path. The access requirements exist precisely because Garmin wants to know who is handling their users' data.

Backfill data types and endpoints

Of Garmin's 16 total data types, only 5 are actively requested during historical backfill when a user first connects:

  • sleeps — /wellness-api/rest/backfill/sleeps — sleep sessions with stages
  • dailies — /wellness-api/rest/backfill/dailies — daily summaries (steps, calories, heart rate)
  • activities — /wellness-api/rest/backfill/activities — activity/workout summaries
  • activityDetails — /wellness-api/rest/backfill/activityDetails — detailed activity data (laps, samples)
  • hrv — /wellness-api/rest/backfill/hrv — heart rate variability

The remaining 11 data types are not requested during backfill, but are accepted whenever Garmin pushes them via webhook: epochs, bodyComps, stressDetails, allDayRespiration, pulseox, bloodPressures, userMetrics, skinTemp, healthSnapshot, moveIQActivities, and mct.

Backfill covers a single 30-day window, the maximum range Garmin allows before the user connected your app. Each data type can typically be backfilled only once. Garmin's API allows 100 requests per minute; Open Wearables reserves 30% of that budget for backfill, which works out to a 2-second delay between type requests.

You can check backfill progress directly:

            GET /api/v1/providers/garmin/users/{user_id}/backfill/status
          

Response:

            {
  "overall_status": "in_progress",
  "current_window": 0,
  "total_windows": 1,
  "windows": {
    "0": {"sleeps": "done", "dailies": "done", "activities": "timed_out", "activityDetails": "done", "hrv": "pending"}
  },
  "summary": {
    "sleeps": {"done": 1, "timed_out": 0, "failed": 0},
    "dailies": {"done": 1, "timed_out": 0, "failed": 0},
    "activities": {"done": 0, "timed_out": 1, "failed": 0},
    "activityDetails": {"done": 1, "timed_out": 0, "failed": 0},
    "hrv": {"done": 0, "timed_out": 0, "failed": 0}
  },
  "in_progress": true,
  "retry_phase": false,
  "retry_type": null,
  "retry_window": null,
  "attempt_count": 0,
  "max_attempts": 3,
  "permanently_failed": false
}
          

Two more endpoints let you manage an in-progress backfill: POST .../backfill/cancel requests a graceful cancellation (returns 409 if no backfill is in progress), and POST .../backfill/{type_name}/retry retries a specific timed-out type.

Common issues when building with the Garmin API

Webhook endpoint must be publicly reachable

Garmin cannot push data to localhost. During development, you need a publicly accessible HTTPS endpoint. Tools like ngrok or a deployed staging environment work. Build gap detection into your sync logic: if your endpoint is down when Garmin pushes, you will miss that data window.

OAuth callback and backfill permission errors

If backfill requests return 403 for all 5 backfill data types at once, the user did not grant the HISTORICAL_DATA_EXPORT permission during authorization. This scope is off by default on Garmin's consent screen and must be explicitly enabled by the user; there is no way to request backfill data without it.

Data arrives per data type, not per activity

Garmin sends separate callbacks for activities, sleep, daily summaries, HRV, and epochs. A single device sync triggers multiple separate payloads to multiple callback URLs. Design your data model and processing logic to handle these as independent streams that you join on user ID and timestamp, not as a single combined event.

Idempotent processing is required

Garmin retries failed deliveries. If your callback returns anything other than HTTP 200, Garmin will attempt redelivery. Use activity IDs and summary IDs as natural keys with upsert logic to handle duplicate deliveries without corrupting your data.

Body Battery

Body Battery is Garmin's proprietary energy level indicator, scored from 0 to 100. It combines HRV analysis, stress detection and sleep quality into a running estimate of the user's available energy reserve. Body Battery depletes during the day as activity and stress accumulate, and recharges during sleep.

Body Battery is available in daily summaries, including the peak value for the day and the low value. It is one of Garmin's most user-loved features and a differentiator compared to most competitors. If your app targets Garmin users, surfacing Body Battery prominently is worth doing.

Open Wearables and Garmin

Open Wearables handles Garmin's OAuth 2.0 authentication, push notification endpoint registration, callback processing and data normalization. Instead of building and maintaining OAuth infrastructure and individual callback handlers for every Garmin data type, you configure your Open Wearables instance with Garmin credentials and receive normalized activity and health data through a simple query API.

The platform abstracts Garmin's push model behind a consistent interface. You query Open Wearables for a user's activity data the same way you query for Strava or Polar data, regardless of the underlying delivery mechanism each provider uses.

Faq

Does connecting Garmin start syncing data automatically?

Yes. The OAuth callback both creates the user connection and dispatches the historical backfill task automatically. There is no separate manual sync step for Garmin, unlike some other providers.

Do i need a physical Garmin device to develop against the API?

For testing with the push sandbox, no. The sandbox generates synthetic data that mirrors real device payloads. For testing with real data including all activity types and device-specific metrics, a physical Garmin device is necessary.

How quickly does Garmin push data after a device sync?

Typically within one to five minutes of device sync. Delivery speed depends on Garmin's backend processing load. There is no real-time delivery guarantee.

How do i handle idempotent processing of Garmin push events?

Use Garmin's activity IDs and summary IDs as natural keys in your database with upsert operations. A duplicate delivery of the same activity should update the existing record rather than creating a duplicate. Design your processing to be safe to run multiple times on the same payload.

Does Open Wearables support all Garmin data types?

Open Wearables normalizes the core data types: activities, daily summaries, sleep, HRV and health metrics. Garmin-specific metrics like running dynamics are passed through where available in the activity payload.

Open Wearables

Open Wearables is an open-source platform that connects your application to wearable and health data providers through a single API. One normalized data model, multi-provider support in a single self-hosted deployment, no per-user fees, MIT licensed, and health intelligence built in: normalized recovery, sleep, activity and biometric data ready for your product layer.

We offer custom deployment and integration support through Momentum. If your team needs help getting to production faster, we can set up and configure Open Wearables as part of a managed engagement. Let's talk.

Book a demo to see how Open Wearables fits your use case.

Garmin integration

View the full Garmin integration documentation on Open Wearables.

See related articles

Garmin API Push Notifications: How Callback Sync Works

Strava API Developer Guide: Activities, Heart Rate and GPS Data

Polar API: Training, HRV and Nightly Recharge Data

Never miss an update

Stay updated with the latest in open wearables, developer tools, and health data integration.

Join our Community. No spam ever.