# Latido API > One API for every health and wearable platform (Garmin, Strava, Polar, Suunto, COROS, Oura, WHOOP, Withings, Fitbit / Google Health, Wahoo, Dexcom, Huawei, Apple Health, Health Connect). A developer connects their users ("members") once through a hosted connect page, then reads normalized workouts, daily summaries, sleep, body measurements, heart rate and glucose through REST (`/v1`), signed webhooks, the TypeScript SDK `@latido/sdk`, or MCP (`/mcp`) for agents. Key facts for agents: - Base URL: `https://api.getlatido.com`. Dashboard and hosted connect page: `https://app.getlatido.com` (sign up at https://app.getlatido.com/sign-up for a test key). All responses are JSON `{ data, meta? }`; errors are `{ errorCode, message, details? }`. - Auth: `Authorization: Bearer lat_test_…` (test mode: only the demo provider `latido_demo` and test members) or `lat_live_…` (real providers, never the demo). The key alone decides project and mode. 401 has no `WWW-Authenticate`. - Units are fixed: meters, seconds, kg, kcal, bpm, watts, m/s, HRV in ms (RMSSD), glucose mg/dL, °C, percentages 0-100. Absent field = unknown (never 0). Instants ISO 8601 UTC + `utcOffsetMinutes`; `date` = member's local day (sleep: wake-up day). - Lists: newest first, `limit` 1-200 (default 50), `cursor` = previous `meta.nextCursor` (absent on the last page). Records: `from` inclusive / `to` exclusive (ISO date or instant), `provider`, `include=raw`. - Connect flow: `POST /v1/connect/sessions { externalUserId, redirectUrl, providers?, metadata? }` → `{ url, token, expiresAt, memberId }` (1 hour). The member returns to `redirectUrl?status=connected&provider&connectionId` | `status=error&provider&reason` (access_denied, provider_error, provider_unavailable, plan_limit_reached, session_expired) | `status=cancelled`. `redirectUrl` origin must be allowed by the project (test keys: localhost too). - Webhooks: `Latido-Signature: t=,v1=.")>`, plus `Latido-Event-Id`, `Latido-Event-Type`. Tolerance 300 s. Answer 2xx within 10 s; 8 attempts over ~23 h (1m, 5m, 30m, 1h, 3h, 6h, 12h); endpoint disabled after 3 days of failures. Deduplicate on event `id`. - Events: connection.created/updated/revoked/error, backfill.completed, workout.created/updated/deleted, daily_summary.updated, sleep_session.created/updated, body_measurement.created, heart_rate_sample.created, glucose_sample.created, planned_workout.pushed/failed, webhook.test. - Limits: monthly request quota per plan (429 PLAN_LIMIT_REACHED, not transient); resync once per connection per 5 min (429 RESYNC_RATE_LIMITED); no per-second limit today. Plan resource limits → 403 PLAN_LIMIT_REACHED with `details.limit`. - AI restriction: Strava and Oura records are never returned through MCP (counted in `meta.withheld`); REST returns them. - Planned workouts (`POST /v1/members/{id}/planned-workouts`) are async and not idempotent: never retry after a 5xx. ## Docs - [Quickstart](https://getlatido.com/docs/api/quickstart): test key → connect session → demo provider → read workouts → webhook - [Authentication](https://getlatido.com/docs/api/authentication): API keys (test/live), MCP tokens, dashboard sessions, webhook secrets - [Connect flow](https://getlatido.com/docs/api/connect-flow): hosted page, redirect parameters and reasons, connection statuses - [Data model](https://getlatido.com/docs/api/data-model): every record family, field, type and unit; providers; sports - [Webhooks](https://getlatido.com/docs/api/webhooks): events, payloads, signature verification (TypeScript, Node, Python), retries - [MCP](https://getlatido.com/docs/api/mcp): connecting Claude Code / Cursor, the tools, the Strava/Oura exclusion - [Mobile ingest](https://getlatido.com/docs/api/mobile-ingest): uploading Apple Health / Health Connect records - [Errors and limits](https://getlatido.com/docs/api/errors-and-limits): error codes, plan limits, rate limits, safe retries - [TypeScript SDK](https://getlatido.com/docs/sdk): `@latido/sdk` - [Provider guides](https://getlatido.com/docs/providers): registering your own app with each health platform (Garmin, Strava, Polar, Suunto, COROS, Oura, WHOOP, Withings, Google Health, Wahoo, Dexcom, Huawei, Apple Health, Health Connect) - [Privacy policy](https://getlatido.com/privacy) and [Terms of service](https://getlatido.com/terms), including the Data Processing Addendum ## Endpoints (API key) - GET /v1/providers — providers of the key's mode, `available` = connectable now - POST /v1/connect/sessions — hosted connect link - GET /v1/members — `externalUserId?` (exact), `search?` (prefix), `limit`, `cursor` - POST /v1/members — idempotent upsert by `externalUserId` (`meta.created`) - GET /v1/members/{memberId} — with `connections` and `recordCounts` - DELETE /v1/members/{memberId} — GDPR erasure: revokes connections, deletes all data - GET /v1/members/{memberId}/connections - GET /v1/members/{memberId}/{workouts|sleep-sessions|daily-summaries|body-measurements|heart-rate|glucose} - POST /v1/members/{memberId}/ingest — `{ provider: apple_health|health_connect, records: [≤1000 normalized records] }`, live keys only - POST /v1/members/{memberId}/planned-workouts — `{ provider, workout }` → `queued` - GET /v1/planned-workouts/{plannedWorkoutId} - GET /v1/records/{recordId} — `include=raw` - GET /v1/connections/{connectionId} - DELETE /v1/connections/{connectionId} — revoke (records stay) - POST /v1/connections/{connectionId}/sync — `{ days? }` (default 7) ## MCP tools (project API key on /mcp) list_providers, list_members, get_member, create_connect_link, list_workouts, get_workout, list_sleep_sessions, list_daily_summaries, list_body_measurements, get_trends, push_planned_workout. Defaults: last 30 days, 25 per page (max 100). Connect: `claude mcp add --transport http latido https://api.getlatido.com/mcp --header "Authorization: Bearer lat_test_..."`. ## SDK ```ts import { Latido } from "@latido/sdk"; const latido = new Latido({ apiKey: process.env.LATIDO_API_KEY }); const { data: session } = await latido.connect.sessions.create({ externalUserId: "user-42", redirectUrl: "http://localhost:3000/done" }); for await (const w of latido.members.workouts.iterate(session.memberId, { from: "2026-10-01" })) console.log(w.sport, w.distanceMeters); const event = await Latido.webhooks.verify(rawBody, request.headers.get("Latido-Signature"), secret); ```