Documentation source
Documentation source
Documentation source
Tenant-scoped, read-only Oura health ingestion with OAuth, incremental cursors, redacted source capture, and private health entities.
## Overview
The Oura connector imports daily readiness, sleep, activity, and heart-rate
records into the Sprinter tenant. It is read-only: every provider request is a
`GET`, there are no provider operations or webhook subscriptions, and synced
records are never exposed through external API-key or MCP entity readers.
The connector is a declarative `ConnectorSpec` on the
[Integration Substrate](/docs/integrations/integration-substrate). Provider
objects are provenance-stamped in the integration ledger before their mapped
entities are upserted idempotently.
| Oura resource | Amble entity type | Window |
| ----------------- | ----------------- | --------------------------------- |
| `daily_readiness` | `oura-readiness` | `start_date` / `end_date` |
| `daily_sleep` | `oura-sleep` | `start_date` / `end_date` |
| `daily_activity` | `oura-activity` | `start_date` / `end_date` |
| `heartrate` | `oura-heartrate` | `start_datetime` / `end_datetime` |
All four entity types are private, hidden from normal data navigation, and use
explicit entity shares. The integration ledger stores identifiers and timing
context while biometric values are hashed or excluded according to each
resource's capture policy.
---
## Authentication
Oura connections use the generic OAuth 2 connection flow and the `oura`
connection preset. Do not create a static bearer-token or Personal Access Token
path. Access and refresh tokens live only in
`agent_connections.encrypted_credentials`.
Before every pull, the substrate refreshes an OAuth connection when necessary.
The refreshed row is then used to build the request headers. This supports
Oura's rotating refresh tokens without putting credentials in tenant
declarations, logs, or entity content.
Deployment environment names:
| Variable | Purpose |
| --------------------------------- | --------------------------------------- |
| `OURA_CLIENT_ID` | Oura OAuth application client ID |
| `OURA_CLIENT_SECRET` | Oura OAuth application client secret |
| `AGENT_CONNECTION_ENCRYPTION_KEY` | Encrypts connection credentials at rest |
No secret values belong in source control.
---
## Incremental sync
Oura collection responses expose `next_token`. Each resource has an independent
cursor stored in the tenant-scoped connection config:
- `ouraDailyReadinessNextToken`
- `ouraDailySleepNextToken`
- `ouraDailyActivityNextToken`
- `ouraHeartrateNextToken`
The request sends the stored value as `next_token`. A scheduled apply persists
the returned cursor only after the entire run completes with zero failures. A
mapping or write failure leaves the prior cursor intact so the next run can
replay safely. Entity upserts remain idempotent by provider resource and
external ID.
`dry_run` is bounded to the requested sample limit and does not write raw
objects, entities, links, or cursors.
---
## Sensitive-data posture
- The connector declaration ships with `enabled: false`.
- Provider payloads use `store: "redacted"` capture policies.
- Raw readiness, sleep, activity, temperature, movement, and heart-rate values
are hash-only or excluded in `integration_objects`.
- Mapped health entities are private and tenant-fenced.
- External API-key routes, MCP resources, and MCP entity tools treat private
health types and their records as not found.
- There is no write-back operation and no webhook subscription code.
This design deliberately keeps useful mapped health records inside the
authenticated product while preventing verbatim provider payloads from becoming
an external integration surface.
---
## Tyler enablement gate
Production ingestion must remain disabled until Tyler completes and records all
of the following:
- [ ] Register the production Oura OAuth application and exact callback URL.
- [ ] Configure `OURA_CLIENT_ID` and `OURA_CLIENT_SECRET` in the deployment.
- [ ] Connect the intended real Oura account through Amble OAuth.
- [ ] Run a mock-backed or bounded dry run (`limit <= 5`) and review every
resource mapping.
- [ ] Verify the raw-ledger sample contains hash wrappers/exclusions and no
verbatim biometric fixture values.
- [ ] Enable the connector schedule only after the privacy review passes.
- [ ] Observe the first production run, confirm tenant ownership and cursor
advancement, then record the result without copying health payloads into
logs or tickets.
No live Oura health sync was performed while implementing this connector.
---
## Follow-up
Oura's subscription webhook API is intentionally deferred. Any future webhook
lane must separately prove signature validation, replay protection, tenant-safe
routing, deduplication, backfill, redaction, and a production kill switch.