Skip to main content

What a Provider is

A Provider is a pluggable adapter that pulls raw data from an external source — a wearable API, a mobile health platform, a database — and normalizes it into Mirobody’s StandardPulseData schema. Each provider lives in its own directory under mirobody/pulse/ (or under providers/ for custom ones) and is auto-discovered at boot. Providers in the health vertical fall into three groups:
  • Theta platform (mirobody/pulse/theta/) — direct OAuth/credential integrations Mirobody maintains itself: Garmin, Whoop, Oura, Renpho, Vital, PostgreSQL.
  • Apple (mirobody/pulse/apple/) — iOS Health export plus CDA (Clinical Document Architecture) for medical records.
  • Vital (under the Theta platform) — an umbrella aggregator that fans out to 300+ wearable and EHR endpoints behind a single OAuth flow. EHR coverage spans roughly 90% of US records.
All providers write to the same normalized tables (th_series_data, th_event_data), so downstream tools, agents, and MCP clients see one unified data model regardless of source.

Provider matrix

ProviderModuleDataAuthConfig keysCredentials
Garminmirobody/pulse/theta/mirobody_garmin_connect/Activity, sleep, heart rate, HRV, stress, body composition, workoutsOAuth 1.0aGARMIN_CLIENT_ID, GARMIN_CLIENT_SECRET, GARMIN_REDIRECT_URLGarmin Developer Portal
Whoopmirobody/pulse/theta/mirobody_whoop/Recovery, sleep, strain, workouts, cyclesOAuth 2.0WHOOP_CLIENT_ID, WHOOP_CLIENT_SECRET, WHOOP_REDIRECT_URLWhoop Developer Portal
Ouramirobody/pulse/theta/mirobody_oura/Sleep, readiness, activity, HRVOAuth 2.0OURA_CLIENT_ID, OURA_CLIENT_SECRET, OURA_REDIRECT_URLcloud.ouraring.com
Renphomirobody/pulse/theta/mirobody_renpho/Weight, body fat, BMI, muscle mass, waterEmail + passwordRENPHO_* (user-supplied per link)Renpho mobile app account
Vitalmirobody/pulse/theta/mirobody_vital/300+ wearables and EHR endpoints (Fitbit, Polar, Withings, Dexcom, Epic, Cerner, …)OAuth via VitalVITAL_API_KEY, VITAL_ENVIRONMENT, VITAL_REDIRECT_URLtryvital.io
PostgreSQLmirobody/pulse/theta/mirobody_pgsql/Any rows from a user-owned Postgres databaseConnection stringper-link host, port, database, user, passwordYour own DB
Apple Healthmirobody/pulse/apple/iOS Health export, CDA medical recordsiOS app + Apple OAuthAPPLE_CLIENT_ID, APPLE_TEAM_ID, APPLE_KEY_ID, APPLE_PRIVATE_KEYApple Developer Portal
Google Healthvia VitalAndroid Health Connect, Google FitOAuth via Vital(configured under Vital)Google Cloud Console
See Configuration for where to put these keys and how the Fernet encryption works on first load.

How to connect a provider

1

Set OAuth credentials in config

Register your application with the vendor’s developer portal (link in the matrix above), then add the keys to config.{env}.yaml. For Garmin:
config.localdb.yaml
GARMIN_CLIENT_ID: 'your_consumer_key'
GARMIN_CLIENT_SECRET: 'your_consumer_secret'
GARMIN_REDIRECT_URL: 'http://localhost:18080/api/v1/pulse/theta/theta_garmin/callback'
Restart Mirobody so the encrypted values are reloaded. Full key list in Configuration.
2

Open the web UI

Sign in at localhost:18080 and open Drive → Providers. Every provider whose credentials are present in the config is listed; the rest are greyed out with a tooltip pointing back here.
3

Click Connect

The button opens the vendor’s OAuth consent screen in a new tab. Approve access; the vendor redirects to the callback URL configured above and Mirobody stores the refresh token (encrypted) in the user’s row.For password-based providers (Renpho) and DSN-based ones (PostgreSQL), a small form is shown instead of an OAuth redirect.
4

Verify

The provider card flips to Connected with a last-sync timestamp. You can also confirm via API:
curl "http://localhost:18080/api/v1/pulse/providers?user_id=YOUR_USER_ID"
The provider entry shows "status": "connected" and a non-null last_sync.

Pull cadence and sync

Once a provider is linked, a per-user pull task is scheduled by mirobody/pulse/theta/platform/pull_task.py:
  • Initial backfill runs immediately. Window depends on the vendor — Garmin and Whoop default to 30 days, Oura to 90, Vital to whatever the upstream API allows.
  • Incremental pulls run on a fixed cadence (hourly for most, daily for body-composition-only providers). Each pull is windowed by last_sync and deduplicated by msg_id.
  • Token refresh is automatic for OAuth 2.0 providers; OAuth 1.0a tokens (Garmin) do not expire.
  • Failures are logged with the user/provider pair and retried on the next tick — they do not block other providers.
Manual sync:
curl -X POST "http://localhost:18080/api/v1/pulse/theta/theta_garmin/pull" \
  -H "Content-Type: application/json" \
  -d '{"user_id": "YOUR_USER_ID"}'
To disconnect:
curl -X POST "http://localhost:18080/api/v1/pulse/theta/theta_garmin/unlink" \
  -H "Content-Type: application/json" \
  -d '{"user_id": "YOUR_USER_ID"}'

Bring your own provider

If the device or data source you need isn’t in the matrix, write your own. Drop a mirobody_<slug>/ directory into the top-level providers/ folder, inherit from BaseThetaProvider, implement info, the credential validator, and (optionally) pull_from_vendor_api. Mirobody picks it up on the next boot.

Provider Integration Guide

Full walkthrough: directory layout, base class, OAuth patterns, data mapping, testing.

Next steps

Configuration

All provider config keys and where to put them

OAuth Implementation

OAuth 1.0a and 2.0 patterns used by Theta providers

Data Mapping

Vendor payload to StandardPulseData

Provider Testing

Test link, callback, pull, and unlink end-to-end