Skip to main content
Ritual now routes wearable integrations through a unified API under /api/wearables. Instead of each provider exposing a separate storage model, Ritual keeps a shared connection layer, canonical samples/events, and sync run history, then projects matched data back into habits and analytics. Legacy Whoop-specific routes still exist for older clients, but new integrations should use the unified wearable endpoints below. Financial integrations currently use a separate API under /api/financial. Plaid-backed spending sync is not modeled as a wearable feed. Instead, Ritual ingests connection, account, and transaction data, computes daily spending totals, and projects those totals into a managed Spending habit.

Unified wearables API

Core endpoints

MethodEndpointPurpose
GET/api/wearables/providersList provider capabilities and connection requirements
GET/api/wearables/connectionsList the current user’s wearable connections
POST/api/wearables/connections/{provider}/authorizeStart provider auth or return provider-specific guidance
POST/api/wearables/connections/{provider}/disconnectRevoke a connection in Ritual
POST/api/wearables/connections/{provider}/syncTrigger a manual sync or account refresh
GET/api/wearables/samplesQuery canonical numeric samples across providers
GET/api/wearables/eventsQuery canonical interval events such as sleep and workouts
GET/api/wearables/sync-runsInspect recent sync runs, status, and item counts
GET/api/wearables/metricsCompatibility query route that returns samples as metrics

OAuth, callback, and webhook endpoints

MethodEndpointPurpose
GET/api/wearables/oauth/{provider}/callbackOAuth callback for Whoop, Oura, and Garmin
POST/api/wearables/webhooks/garminGarmin server-to-server webhook ingest

Canonical model

ResourceWhat it stores
ConnectionProvider, auth method, status, provider user id, last sync state, tracked metrics, source count
SampleNumeric wearable values such as steps, HRV, readiness score, or resting heart rate
EventTime-bounded records such as sleep sessions and workouts
Sync runA single auth refresh, manual sync, webhook ingest, or background ingest status record
When a canonical sample or event matches a habit with the same integration_source and metric_type, Ritual automatically projects it into habit_logs and forwards the compatible record to Tinybird when enabled.

Provider matrix

ProviderAuth methodStatus in current buildSync modelNotes
Apple HealthSDKLiveiOS companion registers a device and pushes signed ingest requestsSupports import fallback; no OAuth
WhoopOAuthLiveManual/background cloud sync via /connections/whoop/syncUses provider-specific fetch logic behind the unified API
OuraOAuthLiveManual/background cloud sync via /connections/oura/syncNormalized into shared samples/events
GarminOAuthLiveOAuth account setup plus webhook-driven ingestionManual sync refreshes permissions; data delivery is webhook-based
TeslaOAuthLiveManual/background cloud sync via /api/integrations/tesla/syncUses Tesla Fleet API for odometer/mileage tracking
FitbitOAuth placeholderNot enabledNot available in this buildPresent in contracts/provider enum, but auth is disabled

Plaid (bank connections for spending tracking)

Plaid is the first financial integration in Ritual. It is used to help users track spending behavior, not to provide a full banking or budgeting product. In the current build, Ritual:
  • creates a Plaid Link token on the backend
  • exchanges the public token for an access token server-side
  • stores financial connections, accounts, and normalized transactions
  • backfills available transaction history
  • computes one positive daily spending total per day
  • projects that total into a managed Spending habit

Financial integration API

MethodEndpointPurpose
POST/api/financial/plaid/link-tokenCreate a Plaid Link token for first-time connect or update-mode reconnect
POST/api/financial/plaid/exchange-public-tokenExchange Plaid public_token, create the Ritual connection, and optionally auto-backfill history
POST/api/financial/plaid/webhookReceive Plaid webhooks for transaction and Item status changes
GET/api/financial/connectionsList the current user’s financial connections, accounts, and sync state
POST/api/financial/connections/{connection_id}/backfillImport available Plaid history and rebuild daily spending totals
POST/api/financial/connections/{connection_id}/syncPull the latest transactions and refresh daily spending totals
PUT/api/financial/connections/{connection_id}/sync-settingsUpdate auto-sync and preferred sync hour
PUT/api/financial/connections/{connection_id}/accounts/{account_id}Include or exclude an account from spending rollups
DELETE/api/financial/connections/{connection_id}Disconnect Plaid inside Ritual
POST/api/financial/sync-allInternal scheduled sync entrypoint for active Plaid connections

Current spending rules

Plaid-backed spending is intentionally narrow in scope. In the current build, Ritual counts:
  • posted outflows on depository accounts
  • positive daily spending totals only
And excludes:
  • pending transactions
  • transfers
  • loan-like and credit-card payment transactions
  • non-depository accounts from the daily spending rollup
This means the integration is optimized for tracking daily spending behavior inside Ritual rather than reproducing a full transaction ledger.

Current connect and sync behavior

BehaviorCurrent implementation
Security gateUsers must enable MFA before Plaid Link can be used
Initial connectCreates the Plaid connection, stores account metadata, and can auto-backfill history
BackfillImports available Plaid transaction history and recomputes daily totals
Incremental syncUses Plaid transaction sync plus a stored cursor
ReconnectUses Plaid update mode when an Item requires re-authentication
Account controlsUsers can include or exclude individual accounts from spending totals
Scheduled syncActive connections can be refreshed through the internal sync-all endpoint

Data Ritual stores from Plaid

Ritual stores:
  • connection status and institution metadata
  • account metadata such as name, mask, type, and subtype
  • normalized transactions including date, amount, merchant/transaction name, direction, pending state, and provider category/code metadata
  • derived daily spending habit logs and sync metadata
Plaid access tokens remain server-side. The product purpose for this data is to support spending-tracking features selected by the user.

Current scope and limitations

The current Plaid integration should be documented as:
  • Plaid-only financial connectivity
  • spending tracking, not budgeting or accounting
  • daily rollups into a Spending habit
  • best suited for supported Plaid institutions and available transaction history
If the production Plaid rollout is still pending approval, present this section as beta or coming soon rather than as a generally available banking feature.

Apple Health (HealthKit via iOS Companion)

Apple Health uses the Ritual iOS companion app, not OAuth. The device registers once, stores a device secret in Keychain, and signs every ingest request with HMAC-SHA256. The backend enforces idempotency with client_event_id.

Apple Health endpoints

MethodEndpointPurpose
POST/api/wearables/apple/register_deviceCreate device_id and device_secret for the iOS companion
GET/api/wearables/apple/devicesList registered Apple Health devices
DELETE/api/wearables/apple/devices/{device_id}Deactivate a device
GET/api/wearables/apple/tracked_metricsReturn the Apple-linked habit metric types the client should sync
POST/api/wearables/apple/ingestLegacy signed ingest endpoint
POST/api/wearables/apple/ingest/v2Incremental ingest with added, deleted, modified, and anchor confirmation
GET/api/wearables/apple/devices/{device_id}/statusPer-device sync health
GET/api/wearables/apple/sync-statusSync health for all Apple devices

Incremental sync behavior

/api/wearables/apple/ingest/v2 is the current path for HealthKit sync. The client sends:
FieldMeaning
addedNew HealthKit samples since the last anchor
modifiedExisting HealthKit samples whose values changed
deletedHealthKit UUIDs that should be soft-deleted in Ritual
anchorsPer-metric anchor tokens that are only committed client-side after server confirmation

Apple Health metric mapping

The iOS app syncs provider metric types such as steps, hr, hrv, sleep_session, and workout. Ritual stores provider-neutral canonical names where possible.
Apple metric typeStored as
stepssteps
active_energyactive_energy
basal_energybasal_energy
distancedistance
flights_climbedflights_climbed
exercise_timeexercise_time
stand_timestand_time
hrheart_rate
hrvhrv
resting_hrresting_heart_rate
walking_hrwalking_heart_rate
respiratory_raterespiratory_rate
oxygen_saturationoxygen_saturation
sleep_sessionsleep_total
sleep_asleepsleep_asleep
sleep_awakesleep_awake
sleep_remsleep_rem
sleep_deepsleep_deep
sleep_coresleep_light
workoutworkout
mindful_minutesmindful_minutes

Whoop

Whoop is connected through the unified wearables connection flow, but the actual sync still uses the provider-specific Whoop service under the hood.

OAuth scopes

offline read:recovery read:sleep read:workout read:cycles read:profile

Whoop endpoints Ritual calls

MethodEndpointPurpose
GEThttps://api.prod.whoop.com/oauth/oauth2/authOAuth authorization
POSThttps://api.prod.whoop.com/oauth/oauth2/tokenToken exchange and refresh
GET/developer/v1/user/profile/basicResolve the Whoop user id after OAuth
GET/developer/v1/recoveryRecovery data with pagination
GET/developer/v1/cycleCycle/day records with pagination
GET/developer/v2/cycle/{cycleId}/sleepSleep session for a cycle
GET/developer/v1/activity/workoutWorkout data with pagination

Whoop sync behavior

BehaviorCurrent implementation
First syncPulls the last 30 days
Incremental syncPulls from last sync time with a 2-day overlap
Token refreshRefreshes when expiry is within 5 minutes
Metric gatingRecovery and workout fetches are skipped if the user has no matching Whoop-linked habits

Canonical Whoop data Ritual stores

KindStored asSource fields
Samplerecovery_scoreRecovery score
Samplehrvhrv_rmssd_milli
Sampleresting_heart_rateResting heart rate
Sampleoxygen_saturationSpO2 percentage
Sampletemperature_deltaSkin temperature delta
Eventsleep_totalSleep session with stage summary details
EventworkoutWorkout window with strain, distance, and HR details

Oura Ring

Oura is now part of the unified cloud wearable flow. Ritual exchanges OAuth tokens, refreshes them automatically, fetches recent collections, and normalizes the results into shared samples and events.

OAuth scopes

email personal daily heartrate session workout tag

Oura endpoints Ritual calls

MethodEndpointPurpose
GEThttps://cloud.ouraring.com/oauth/authorizeOAuth authorization
POSThttps://api.ouraring.com/oauth/tokenToken exchange and refresh
GET/v2/usercollection/personal_infoResolve the Oura identity/profile
GET/v2/usercollection/daily_sleepDaily sleep summary
GET/v2/usercollection/sleepSleep sessions
GET/v2/usercollection/daily_readinessReadiness summary
GET/v2/usercollection/daily_activityActivity summary
GET/v2/usercollection/workoutWorkout sessions
GET/v2/usercollection/heartrateHeart-rate series when available for the token/scope

Oura sync behavior

BehaviorCurrent implementation
First syncPulls the last 30 days
Incremental syncUses last sync time with a minimum 2-day overlap and maximum 30-day lookback
Scope tolerance403 and 404 collection responses are treated as unavailable scope/data, not fatal

Canonical Oura data Ritual stores

KindStored as
Samplesteps, active_energy, distance, activity_score
Samplereadiness_score, temperature_delta
Samplesleep_score, sleep_deep, sleep_rem, sleep_light
Samplehrv, resting_heart_rate, heart_rate
Eventsleep_total
Eventworkout

Garmin

Garmin is connected through unified OAuth plus a webhook ingest path. The manual sync endpoint is mainly an account refresh step that loads the provider user id and permissions; actual activity data is expected to arrive through Garmin webhooks.

OAuth and webhook flow

StepCurrent implementation
AuthorizationPKCE OAuth via /api/wearables/connections/garmin/authorize
Callback/api/wearables/oauth/garmin/callback validates state, exchanges code, stores tokens, and records permissions
Manual sync/api/wearables/connections/garmin/sync refreshes account metadata and permissions
Webhook ingest/api/wearables/webhooks/garmin accepts Garmin payloads and maps them to the linked Ritual user
If GARMIN_WEBHOOK_SECRET is configured, the webhook requires the x-garmin-webhook-secret header.

Canonical Garmin data Ritual stores

KindStored as
Samplesteps, distance, active_energy, resting_heart_rate
Samplestress_score, body_battery
Eventsleep_total
Eventworkout

Tesla

Tesla is connected through OAuth via the Tesla Fleet API. Ritual tracks odometer readings and calculates daily miles driven, projecting them into a managed habit.

Tesla integration API

MethodEndpointPurpose
POST/api/integrations/tesla/callbackOAuth token exchange
GET/api/integrations/tesla/statusConnection status, last sync time, and vehicle list
POST/api/integrations/tesla/syncManual odometer sync
POST/api/integrations/tesla/backfill-odometerBackfill historical mileage across a date range
POST/api/integrations/tesla/disconnectRevoke the Tesla connection

What Ritual tracks from Tesla

DataHow it’s stored
Odometer readingsRaw odometer value per vehicle per sync
Miles drivenDaily delta calculated from consecutive odometer readings, projected into a managed “Miles Driven” habit
Vehicle metadataDisplay name and vehicle IDs

Tesla sync behavior

BehaviorCurrent implementation
AuthOAuth 2.0 with automatic token refresh when expiry is within 5 minutes
Token storageEncrypted access and refresh tokens stored server-side
Multi-vehicleSupports multiple vehicles per account with per-vehicle odometer tracking
BackfillDistributes historical miles evenly across days with idempotent log creation
Scheduled syncActive connections are refreshed through a Trigger.dev background task
DeduplicationSkips logging if the odometer delta is zero or a log already exists for that date

Desktop context

Ritual Watcher and Ritual Recorder are separate from the unified wearables API. They are first-party desktop context features, not third-party integrations. For detailed docs on computer tracking, OCR capture, memory indexing, and hybrid search, see Context Understanding.

Weather

Weather context is also outside the unified wearables API. Ritual attaches local conditions and temperature context to logs automatically where location support is available.

Not yet enabled

IntegrationCurrent state
FitbitIncluded in provider enums/contracts, but auth is disabled in this build. Data can be imported via the bulk import system.
Apple Screen Time cloud ingestMetric types exist in shared Apple schemas, but there is no live unified provider flow yet
Google CalendarStill planned