Integrations
betaYour users connect a provider account once; Sahha syncs their data continuously — server-side, no SDK to ship.
Introduction
Integrations pull health data straight from a provider's cloud — Garmin , Oura , WHOOP — into Sahha, with no SDK on the device . The user connects their provider account once; Sahha syncs their data continuously onto the same profile. It's the third way to get data into Sahha, alongside the SDK and REST API .
Public beta
Integrations are in public beta and are Sandbox only . We're still refining the API surface as it matures and will call out any breaking changes here as they land.
Supported providers
| Provider | Slug | Device | Connection | Status |
|---|---|---|---|---|
| Garmin | garmin | Watch | Cloud OAuth | Beta Garmin approval required |
| Oura | oura | Ring | Cloud OAuth | Beta self sign-up |
| WHOOP | whoop | Band | Cloud OAuth | Beta self sign-up |
| Samsung Health | — | Phone / watch | On-device SDK | Coming soon collected via the SDK |
The slug is the value you pass as {provider} throughout the API (see Connect a user ).
Need another provider?
Request one in the Slack Community — tell us the provider and the data you need. Demand drives our priority.
Data coverage
What you get depends on the provider, the user's device, and the scopes you enable. Sahha normalizes every provider into the same data logs , biomarkers , scores and archetypes — so once data is in, you consume it the same way regardless of source.
The matrix below is indicative . See each provider's page for the authoritative, scope-by-scope list.
| Data | Garmin | Oura | WHOOP |
|---|---|---|---|
| Steps & activity | ● | ● | — |
| Sleep & sleep stages | ● | ● | ● |
| Heart rate | ● | ● | ● |
| Heart rate variability | ● | ● | ● |
| Blood oxygen (SpO₂) | ● | ● | — |
| Respiratory rate | ● | ● | ● |
| Body temperature | ● | — | — |
| Workouts & exercise | ● | ● | ● |
| VO₂ max / fitness | ● | ● | — |
| Body composition | ● | — | ● |
| Menstrual cycle | ● | — | — |
| Blood pressure | ● | — | — |
| Demographics | ● | ● | — |
● available · — not provided. Exact availability depends on the user's device and the scopes you enable — see each provider's page.
Scores are computed from whatever you collect
Sahha Scores (Sleep, Activity, Readiness, Wellbeing, Mental) are derived from the underlying data — so a connected provider contributes to scores automatically, even if it doesn't expose a matching raw metric. More data sources generally mean more complete scores.
Data freshness & history
Every provider is webhook-driven : the provider notifies Sahha over webhooks as new data is recorded, so data usually lands within minutes of the user's device syncing to the provider's cloud. Sahha does not poll on a fixed schedule.
When a user first connects, Sahha backfills the last 30 days of available history, then syncs continuously from then on.
| Provider | Live sync | Backfill on connect |
|---|---|---|
| Garmin | Push (webhooks) | 30 days — Requires the user to grant Garmin's historical-data permission |
| Oura | Pull (webhooks) | 30 days |
| WHOOP | Pull (webhooks) | 30 days |
Latency depends on the device
End-to-end freshness is bounded by when the user's device syncs to the provider — e.g. an Oura ring that syncs once each morning delivers the night's data at that point, not in real time. Sahha forwards it within minutes of receiving it.
Garmin historical permission
If a Garmin user does not grant historical-data permission during authorization, the 30-day backfill is skipped and only data recorded after connection flows in. Going-forward sync is unaffected.
How it works
Integrations use three concepts. The same vocabulary appears in the dashboard and the API:
| Term | What it is |
|---|---|
| Provider | A data source you can connect — Garmin, Oura, WHOOP. |
| Integration | Your configured app for a provider — the OAuth credentials and scopes you set up once in the Sahha Dashboard. |
| Connection | One end-user's authorized link to a provider, created when they complete the OAuth flow. |
Setting up a provider is three steps:
- Create an app with the provider — register in the provider's developer console to obtain OAuth credentials.
- Create an integration in Sahha — add those credentials to your project in the Sahha Dashboard .
- Connect an end user — start the OAuth flow for a user via the Sahha API or SDK. Once they authorize, Sahha begins syncing automatically.
Follow the provider-specific guide above for exact console steps and scopes.
Connect a user
Once an integration is configured, you trigger the connection flow per end user. There are two ways: the API (server-driven or web flows) and the SDK (native mobile).
Before you start
You need:
- A configured integration for the provider (the three steps above).
- A profile token for the end user — this scopes the connection to that specific user. See Authentication for how tokens work and Getting Started to obtain one.
- The end user to have an account with the provider (e.g. a Garmin Connect or Oura account).
Examples use the sandbox environment ( sandbox-api.sahha.ai). Swap to api.sahha.ai for production — see Environments .
Option A — Sahha API
The connection is a standard OAuth redirect round-trip:
- You call Sahha's
authorizeendpoint with the user's profile token. Sahha returns anauthorizationUrl. - You redirect the user's browser to that
authorizationUrl(the provider's consent screen). - The user approves access on the provider's site.
- The provider redirects back to Sahha's callback; Sahha stores the connection and starts syncing.
- Sahha redirects the user to your
redirectUrlso your app can show a success state.
The optional redirectUrl must match an entry in the integration's Redirect URL Whitelist; if omitted, Sahha uses the first whitelisted URL.
curl -X GET "https://sandbox-api.sahha.ai/api/v1/integration/oauth/{provider}/authorize?redirectUrl=https://yourapp.com/integrations/callback" \ -H "Authorization: profile {your-profile-token}" curl -X GET "https://sandbox-api.sahha.ai/api/v1/integration/oauth/{provider}/authorize?redirectUrl=https://yourapp.com/integrations/callback" \
-H "Authorization: profile {your-profile-token}"
{ "authorizationUrl": "https://connect.garmin.com/oauthConfirm?..."} {
"authorizationUrl": "https://connect.garmin.com/oauthConfirm?..."
}
Replace {provider} with the provider's slug from the Supported providers table (e.g. garmin). Each provider's page has the full request and language-specific snippets.
Once a user is connected, you read their data the same way as any other Sahha data — via the REST API or Webhooks . There's nothing integration-specific about consuming it.
Handling the redirect
After the OAuth flow, Sahha redirects the user to your redirectUrl with query parameters describing the outcome — handle them however your app needs.
Success
| Parameter | Reason |
|---|---|
status=success | Authorization completed and the connection was created. |
Errors
Error redirects include status=error and an error message. This covers a user denying access on the provider's consent screen, which is returned as provider denied authorization:
error value | Reason |
|---|---|
provider denied authorization: <provider_error> | The user denied consent, or the provider returned an error. <provider_error> is the provider's own value (e.g. access_denied). |
authorization code is missing | The provider redirected back without an authorization code. |
integration not found | No integration is configured for this account and provider. |
provider not supported | The provider is not supported. |
failed to process integration credentials | The stored client credentials could not be processed. |
failed to exchange authorization code | Exchanging the authorization code for a token failed. |
failed to resolve provider user identity | The provider user could not be identified from the token. |
failed to store provider user | Persisting the provider user failed. |
failed to create connection | Creating the connection record failed. |
Parameter values are URL-encoded — e.g. error=authorization code is missing comes back as error=authorization+code+is+missing.
The user has 10 minutes to authorize after the authorizationUrl is generated; after that the session expires and they'll need a fresh authorizationUrl to try again. If the state parameter is missing, expired, or already used, the callback responds with HTTP 400 Bad Request instead of redirecting — there's no trusted redirectUrl to return to in that case.
Option B — Sahha SDK
Coming soon
SDK support for Integrations is in development. The connection flow will be initiated from the native SDK; the API above is available today.
Managing connections
A connection moves through a simple lifecycle: connected → (token expires) needs re-auth → disconnected . You can see and manage every connection in the Sahha Dashboard under Integrations → Connections .
Deleting a connection
Deleting a connection revokes a single end-user's link to a provider — Sahha stops ingesting their data immediately. A connection can be deleted in two ways:
- You , from the Sahha Dashboard under Integrations → Connections .
- The user , from their own provider account settings.
Deleting an integration
Deleting an integration removes your configured app for a provider — its OAuth credentials and scopes. Do this from the Sahha Dashboard under Integrations → Integrations .
This deletes every connection
Deleting an integration deletes every connection created under it, so their data stops syncing. If you recreate an integration with the same credentials, those users will need to reauthenticate to reconnect.
Troubleshooting
A successful connection can still fail to deliver data for a few reasons:
-
The user denied certain scopes. They approved the connection but declined specific data permissions during authorization, so those categories never sync.
-
The webhook URL is misconfigured. Check that the webhook URL from your Sahha integration is set correctly in the provider's developer console — see the provider's page.
-
A push/pull provider isn't set to push. Providers that offer both push and pull delivery (e.g. Garmin) must have their endpoints set to push — pull-mode endpoints deliver nothing.
-
Rate limiting is throttling delivery. Hitting the provider's rate limits for your app can delay or drop data; request higher limits from the provider if you need them. (Sahha will add alerts for excessive rate limiting in a future release.)
- undefined
The most common cause is a redirect URL mismatch. Make sure the Sahha callback URL is registered in your provider app's allowed redirect URIs, and that any redirectUrl you pass matches an entry in your integration's Redirect URL Whitelist.
The historical backfill window depends on the provider. See the provider page for specifics; new data flows continuously once connected.
Support
Need help? Contact support@sahha.ai or join the Slack Community . </content> </invoke>
- Previous
- Data Dictionary
- Next
- SDK