---
title: Integrations
subtitle: Your 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](/docs/connect/sdk) and [REST API](/docs/connect/api).

{% callout title="Public beta" type="info" %}
Integrations are in public beta and ready to build with today. We're still refining the API surface as it matures and will call out any breaking changes here as they land.
{% /callout %}

---

## Supported providers

{% providers view="list" /%}

The **slug** is the value you pass as `{provider}` throughout the API (see [Connect a user](#connect-a-user)).

{% callout title="Need another provider?" %}
Request one in the [Slack Community](https://join.slack.com/t/sahhacommunity/shared_invite/zt-1w0fmfbvk-qUwQ83tJgXyjT9XSxJvKIw) — tell us the provider and the data you need. Demand drives our priority.
{% /callout %}

---

## 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](/docs/products/logs), [biomarkers](/docs/products/biomarkers), [scores](/docs/products/scores) and [archetypes](/docs/products/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.

{% providers view="coverage" /%}

{% callout title="Scores are computed from whatever you collect" %}
Sahha [Scores](/docs/products/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.
{% /callout %}

---

## Data freshness & history

Every provider is **push-based**: 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.

{% providers view="sync" /%}

{% callout title="Latency depends on the device" type="info" %}
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.
{% /callout %}

{% callout title="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.
{% /callout %}

---

## 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:

1. **Create an app with the provider** — register in the provider's developer console to obtain OAuth credentials.
2. **Create an integration in Sahha** — add those credentials to your project in the [Sahha Dashboard](https://app.sahha.ai/dashboard).
3. **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](/docs/connect/api#authentication) for how tokens work and [Getting Started](/docs/connect/api#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](/docs/connect/api#environments).

### Option A — Sahha API

The connection is a standard OAuth redirect round-trip:

1. **You** call Sahha's `authorize` endpoint with the user's profile token. Sahha returns an `authorizationUrl`.
2. **You** redirect the user's browser to that `authorizationUrl` (the provider's consent screen).
3. **The user** approves access on the provider's site.
4. **The provider** redirects back to Sahha's callback; Sahha stores the connection and starts syncing.
5. **Sahha** redirects the user to your `redirectUrl` so 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.

```shell-session title="Start a connection"
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}"
```

```json title="Response"
{
	"authorizationUrl": "https://connect.garmin.com/oauthConfirm?..."
}
```

Replace `{provider}` with the provider's slug from the [Supported providers](#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](/docs/connect/api) or [Webhooks](/docs/connect/webhooks). There's nothing integration-specific about consuming it.

### Option B — Sahha SDK

{% callout title="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.
{% /callout %}

---

## 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](https://app.sahha.ai/dashboard) under **Integrations → Connections**.

### Disconnecting a user

A connection can be revoked in any of three ways:

- From the Sahha Dashboard under **Integrations → Connections**
- By calling the disconnect endpoint below
- By the user, from their own provider account settings

Sahha stops ingesting data immediately on disconnection.

| Method                                    | Endpoint                                                    |
| ----------------------------------------- | ----------------------------------------------------------- |
| {% badge color="red" %}DELETE{% /badge %} | `/api/v1/integration/connection/{accountId}/{connectionId}` |

Disconnecting is a server-side admin action, so it uses your **account token** — not a user's profile token (see [Authentication](/docs/connect/api#authentication)). Find the `{accountId}` and `{connectionId}` in the [Sahha Dashboard](https://app.sahha.ai/dashboard) under **Integrations → Connections**.

```shell-session title="Disconnect a user"
curl -X DELETE "https://sandbox-api.sahha.ai/api/v1/integration/connection/{accountId}/{connectionId}" \
  -H "Authorization: account {your-account-token}"
```

Returns `204 No Content` on success.

{% callout title="Deleting an integration" %}
Deleting an integration from the dashboard also deletes and deregisters **every** connection under it — every user connected with those credentials is disconnected.
{% /callout %}

---

## Troubleshooting

{% faq %}

{% faq-item question="A user connected but no data is arriving" %}
Confirm the integration's scopes match the scopes enabled on your provider app — a mismatch causes the OAuth flow to fail silently or return empty data. For providers that deliver via webhooks (e.g. Garmin), also confirm the endpoints are enabled and set to **push**, not pull.
{% /faq-item %}

{% faq-item question="The OAuth flow fails immediately" %}
The most common cause is requesting a scope your provider app doesn't have access to. Deselect any scopes your app isn't approved for, then retry. Also check that the `redirectUrl` you passed matches an entry in the Redirect URL Whitelist.
{% /faq-item %}

{% faq-item question="How far back does data go when a user first connects?" %}
The historical backfill window depends on the provider. See the provider page for specifics; new data flows continuously once connected.
{% /faq-item %}

{% /faq %}

---

## Support

Need help? Contact [support@sahha.ai](mailto:support@sahha.ai) or join the [Slack Community](https://join.slack.com/t/sahhacommunity/shared_invite/zt-1w0fmfbvk-qUwQ83tJgXyjT9XSxJvKIw).
</content>
</invoke>
