{
  "openapi": "3.1.0",
  "info": {
    "title": "TeraRx API",
    "version": "1.0.0-draft",
    "summary": "GLP-1 coaching for telehealth brands, their patients and their prescribers.",
    "description": "TeraRx is the coaching layer for patients on GLP-1 therapy. Telehealth brands switch it on for their patients: an **AI Coach** on every plan; a health coach and a fitness coach on the coached plan; protocols, meal plans and workout plans built from the brand's own rule matrix; and **clinical flags** back to the brand's prescriber. TeraRx never prescribes: it mirrors the dose the brand sends and coaches against it.\n\nThis contract is a **draft for partner review**. Every example uses synthetic data.\n\n| You are | You use | Start with |\n| --- | --- | --- |\n| A brand's server | Client credentials | [Auth](#tag/Auth), then `POST /v1/enrollments` |\n| A platform partner, for several brands | One client for all your brands, a `tenant_id` on every token | [Platform partners](#tag/Tenants) |\n| A brand's app | Patient tokens from token exchange | `GET /v1/patient` |\n| A prescriber system | A clinical client | `GET /v1/clinical-flags` |\n| Receiving events | Webhooks | [Webhooks](#tag/Webhooks) |\n\n## Try it\n\n* **Sandbox:** every operation answers with the examples on this page at the sandbox server. It checks that a token is present but not its signature, validates request bodies and stores nothing.\n* **Postman:** import the [collection](postman/terarx-v1.postman_collection.json) and the [sandbox environment](postman/terarx-sandbox.postman_environment.json). A pre-request script gets each caller its token.\n* **Guides and samples:** quickstart, guides and Node and Python code for signing the patient assertion, verifying webhook signatures and enrolling a patient, on the docs site at [docs.tera.health](https://docs.tera.health).\n\n# Conventions\n\n## Base URL and versioning\n\nAll paths start with the major version, `/v1`. Within a version, changes are additive only: new endpoints, new optional request fields, new response fields, new enum values and new event types. Build clients that ignore fields and values they do not know.\n\nA breaking change means a new version (`/v2`), announced at least **6 months** ahead. During that time the old version's responses carry `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) headers with the dates, and both versions run side by side.\n\n## Formats\n\n* JSON in and out (`application/json`; `application/merge-patch+json` for `PATCH`). UTF-8.\n* Ids are UUID strings. Treat them as opaque.\n* Timestamps are ISO 8601 in UTC (`2026-10-26T14:05:00Z`). Log dates (`log_date`) are calendar dates in the patient's time zone.\n* Measurements are always metric (kg, cm, ml, g, kcal). `units` on the patient is a display preference only.\n* Field names are `snake_case`. Absent and `null` both mean \"no value\".\n\n## Request ids\n\nEvery response has an `X-Request-Id` header, errors included. Ours are `req_` followed by a UUIDv7. Send your own `X-Request-Id` to have it echoed, which makes logs easy to join: a UUID, or `req_` followed by up to 60 letters, digits, `_` or `-`. Any other value is replaced with a new id. Quote it when you contact TeraRx.\n\n## Errors\n\nEvery 4xx and 5xx response is RFC 9457 problem details (`application/problem+json`):\n\n```json\n{\n  \"type\": \"about:blank\",\n  \"title\": \"Unprocessable Content\",\n  \"status\": 422,\n  \"detail\": \"1 field is invalid.\",\n  \"code\": \"validation_failed\",\n  \"request_id\": \"req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b\",\n  \"errors\": [{ \"pointer\": \"/patient/state_code\", \"code\": \"invalid_format\", \"detail\": \"Must be a two-letter USPS state code.\" }]\n}\n```\n\nBranch on `code`, which is stable; `title` and `detail` may change. Errors never contain patient data: no names, no values you sent, no free text. A resource from another brand or another patient returns `404` exactly like one that does not exist.\n\n| Status | Common `code` values |\n| --- | --- |\n| 400 | `malformed_request`, `idempotency_key_missing` |\n| 401 | `token_missing`, `token_expired`, `token_invalid`, `client_revoked` |\n| 403 | `wrong_caller_type` (a token of another kind, such as a patient token on a brand server endpoint), `insufficient_scope`, `plan_not_eligible` (a coached-plan endpoint on `ai_only`), `treatment_managed_by_brand` |\n| 404 | `<resource>_not_found`, for example `enrollment_not_found` |\n| 409 | `invalid_status_transition`, `idempotency_key_in_use`, `enrollment_exists`, `external_order_exists`, `flag_closed`, `ai_paused` |\n| 410 | `export_expired`, `event_too_old` |\n| 422 | `validation_failed`, `idempotency_key_reused`, `plan_not_offered`, `unknown_medication`, `unknown_legal_document` |\n| 429 | `rate_limited`, `daily_message_cap_reached` |\n| 503 | `ai_unavailable`, `service_unavailable` |\n\nEach operation lists the codes specific to it.\n\n## Idempotency\n\nEvery `POST` that creates something requires an `Idempotency-Key` header (a UUID is a good choice); without it the request is refused with `400 idempotency_key_missing`. Other `POST` actions accept one.\n\n* The same key and the same body within **24 hours** returns the first response, with `Idempotent-Replayed: true`, and creates nothing new.\n* The same key with a different body is refused with `422 idempotency_key_reused`.\n* While the first request with a key is still running, a second one gets `409 idempotency_key_in_use`; retry shortly.\n\nKeys are scoped to your client. Logs your server sends also carry your own `external_id`, which dedupes them permanently.\n\n## Pagination\n\nLists that can grow are cursor-paginated: `?limit=` (1 to 100, default 25) and `?cursor=`. The response is `{ \"data\": [...], \"next_cursor\": \"...\" }`; pass `next_cursor` back as `cursor` until it is `null`. Cursors are opaque and expire after 24 hours. Short, bounded lists return `{ \"data\": [...] }` without a cursor.\n\n## Rate limits\n\nLimits are per client (600 requests per minute by default, set per contract) and, for patient tokens, per patient. Every response carries:\n\n| Header | Meaning |\n| --- | --- |\n| `RateLimit-Limit` | Requests allowed per window |\n| `RateLimit-Remaining` | Requests left |\n| `RateLimit-Reset` | Seconds until the window resets |\n\nOver the limit you get `429` with `Retry-After` in seconds. The AI Coach also has a daily message cap per patient, set on the brand's plan (`429 daily_message_cap_reached`).\n\n## Plans\n\nPatient endpoints say which plans they work on (the `x-plans` extension, and \"Plans\" at the end of each description). `ai_health_fitness` is the coached plan; `ai_only` has the AI Coach and no coaches, and its escalations go to the brand's prescriber as clinical flags. Calling a coached-plan endpoint for an `ai_only` patient returns `403 plan_not_eligible`.\n\n## Privacy\n\n* A patient's records belong to one brand. Nothing is shared, matched or merged across brands.\n* Brand servers read status and ids, never clinical content. Reports are aggregates with groups under 10 patients suppressed.\n* Webhooks carry ids only. Fetch content through the API.\n* Files are uploaded and downloaded through short-lived pre-signed URLs. Never store those URLs.\n* Every read or change of a coaching record is audit-logged.\n\n## Emergencies\n\nCoaching is not emergency care. Wherever a patient can type (care messages, the AI Coach, symptom logging), show this guidance: **in an emergency call 911; in a mental health crisis call or text 988.** When a symptom log comes back with `is_red_flag: true`, or an AI Coach reply with `show_emergency_guidance: true`, show it before anything else.\n\n## Environments\n\n| Environment | Base URL | Data |\n| --- | --- | --- |\n| Local mock | `http://localhost:4010` | The examples in this spec |\n| Sandbox (integration) | `https://sandbox.rx.tera.health` | Synthetic only. Until the API is live it is this mock: the examples, no webhooks. Then flags and webhooks fire; nothing is billed |\n| Production | `https://api.rx.tera.health` | Real patients |\n\nEach environment has its own clients, keys and webhook secret.\n",
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "http://localhost:4010",
      "description": "Local mock (Prism on the bundled spec), answers with the examples in this spec"
    },
    {
      "url": "https://sandbox.{domain}",
      "description": "Partner sandbox, synthetic data only",
      "variables": {
        "domain": {
          "default": "rx.tera.health",
          "description": "The TeraRx domain."
        }
      }
    },
    {
      "url": "https://api.{domain}",
      "description": "Production",
      "variables": {
        "domain": {
          "default": "rx.tera.health",
          "description": "The TeraRx domain."
        }
      }
    }
  ],
  "tags": [
    {
      "name": "Auth",
      "description": "Three kinds of caller use this API, each with its own token. The tokens are not interchangeable: a brand server token cannot call patient endpoints, and a patient token cannot call brand server or clinical endpoints. Coaches use the TeraRx portal, which is not part of this contract.\n\n| Caller | Security scheme | How it gets a token | Lifetime |\n| --- | --- | --- | --- |\n| Brand server | `brandServer` | Client credentials with its own `client_id` and secret | 1 hour |\n| Patient (brand app, or our own app's backend as TeraRx Direct) | `patientToken` | Token exchange of an assertion the brand's server signed | 15 minutes |\n| Prescriber system (brand clinician tool or Beluga) | `clinicalClient` | Client credentials with a separate clinical client | 1 hour |\n\nEach operation lists the scheme and the scope it needs. All tokens go in `Authorization: Bearer <token>`.\n\nA platform partner that hosts several brands holds one client for all of them and names the brand on every token request, so each token is still for one brand. See [Platform partners](#tag/Tenants).\n\n## Brand servers: client credentials\n\nTeraRx issues one OAuth client per brand and environment (integration, production). The secret is shown once; TeraRx keeps only its hash. Keep it on your server, never in an app. The integration client works against the sandbox and test environments only; the production API answers it with `unauthorized_client`.\n\n| Problem | `code` | HTTP |\n| --- | --- | --- |\n| Unknown client or wrong secret (the same answer for both) | `invalid_client` | 401 |\n| The client was revoked | `client_revoked` | 401, also for tokens it already holds, within a minute |\n| A `scope` the client does not hold | `invalid_scope` | 400 |\n| The integration client on the production API | `unauthorized_client` | 400 |\n| A partner client sent no `tenant_id` | `tenant_required` | 400 |\n| A `tenant_id` this client may not act for, or a brand that is not live | `tenant_not_permitted` | 400 |\n\n```http\nPOST /v1/oauth/token\nAuthorization: Basic base64(client_id:client_secret)\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=client_credentials&scope=enrollments:read%20enrollments:write%20logs:write\n```\n\n| Scope | Allows |\n| --- | --- |\n| `enrollments:read` | Read enrollment status, the treatment mirror and consent records |\n| `enrollments:write` | Enroll, change plan, pause, resume, cancel, update the treatment mirror, record consent proof |\n| `logs:write` | Send logs your app already recorded |\n| `events:read` | Replay events |\n| `reports:read` | The aggregate brand report |\n| `data_requests:read`, `data_requests:write` | Read and create data requests; decide amendments |\n| `patients:token_exchange` | Your signing keys may mint patient tokens (see below) |\n| `tenants:read` | List the brands your client may act for |\n\nA brand server reads status and ids only. It never reads clinical content: messages, form answers, protocol text and log values stay with the patient and the care team.\n\n## Patients: token exchange\n\nThere are no patient passwords in the API. Your server vouches for the patient by signing a short-lived JWT with **your own private key**; TeraRx checks it against the public keys you registered (a JWKS URL or a JWKS document) and returns a patient token. TeraRx never holds a key that can mint patient sessions, and you can rotate keys yourself by publishing a new key in your JWKS.\n\n1. Your app signs the patient in with your own login.\n2. Your server signs a patient assertion (below) and hands it to the app.\n3. The app (or your server) exchanges it:\n\n```http\nPOST /v1/oauth/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=urn:ietf:params:oauth:grant-type:token-exchange\n&subject_token=<assertion>\n&subject_token_type=urn:ietf:params:oauth:token-type:jwt\n```\n\n4. The response's `access_token` is valid for 15 minutes for that one patient and enrollment. There is no refresh token: sign a new assertion when it expires.\n\n### Patient assertion\n\nA JWT (RFC 7519) signed with `ES256`, `RS256` or `EdDSA`. The header names the key with `kid`, which must be in your registered JWKS.\n\n| Claim | Required | Value |\n| --- | --- | --- |\n| `iss` | Yes | Your issuer, exactly as registered with TeraRx at onboarding |\n| `sub` | Yes | Your patient id: the `external_patient_id` you used on `POST /v1/enrollments` |\n| `aud` | Yes | The TeraRx API audience for the environment, given at onboarding |\n| `iat` | Yes | Issued at, in Unix seconds |\n| `exp` | Yes | Expiry, at most 5 minutes after `iat` |\n| `jti` | Yes | A unique id. Each assertion can be exchanged once |\n| `tenant_id` | Platform partners only | The brand the patient is enrolled with. A brand's own assertions may omit it |\n\nTeraRx allows 30 seconds of clock skew on `iat` and `exp`. The assertion carries no names or health data.\n\nIf you registered a JWKS URL, TeraRx caches it for 10 minutes and fetches it again as soon as an assertion names a `kid` it has not seen (at most every 30 seconds). To rotate, publish the new key next to the old one, start signing with it, then remove the old one.\n\n| Problem | `code` | HTTP |\n| --- | --- | --- |\n| Signature does not match a registered key | `assertion_signature_invalid` | 400 |\n| `exp` has passed | `assertion_expired` | 400 |\n| `exp` is more than 5 minutes after `iat` | `assertion_lifetime_too_long` | 400 |\n| `jti` already used | `assertion_replayed` | 400 |\n| Wrong `aud` | `assertion_audience_invalid` | 400 |\n| `iss` not registered | `assertion_issuer_unknown` | 400 |\n| A required claim is missing or malformed, or `iat` is in the future | `assertion_invalid` | 400 |\n| A partner's assertion names a brand the partner may not act for, or one that is not live | `tenant_not_permitted` | 400 |\n| No open enrollment for `sub` | `patient_not_found` | 400 |\n| The enrollment is cancelled, completed or ineligible | `enrollment_not_active` | 400 |\n| The client lacks `patients:token_exchange` | `token_exchange_not_allowed` | 400 |\n| The client was revoked | `client_revoked` | 401, also for the patient tokens it already exchanged, within a minute |\n| Your client's exchanges passed its per-minute limit | `rate_limited` | 429 |\n| TeraRx could not fetch your JWKS URL, or could not check the `jti` | `service_unavailable` | 503 |\n\nEach problem also carries the RFC 6749 `error` field (`invalid_grant`, `invalid_client`, `unauthorized_client` ...) for OAuth libraries.\n\n## Prescriber systems: clinical clients\n\nYour prescriber system gets its own OAuth client, separate from the brand server's, with `clinical:read` (read flags) and `clinical:write` (acknowledge and resolve). It authenticates with client credentials like a brand server.\n\nA clinical client acts for many prescribers, so every clinical write names the individual in the request body:\n\n```json\n{\n  \"on_behalf_of\": { \"npi\": \"1234567893\", \"prescriber_id\": \"dr-00417\", \"name\": \"Dr. Alex Morgan, NP\" }\n}\n```\n\n`name` is required, plus at least one of `npi` or `prescriber_id`. A write without `on_behalf_of`, or with an NPI whose check digit is wrong, is refused with `422 validation_failed` and the field's `pointer`. TeraRx stores the prescriber and the client that sent it on the flag, shows the name to coaches, and records it in the audit log.\n"
    },
    {
      "name": "Tenants",
      "description": "A platform partner hosts several telehealth brands and switches TeraRx on for them. The partner integrates once, with one set of credentials for all its brands. A brand that integrates directly keeps its own client and needs none of this.\n\nEach brand stays its own tenant. Its patients, enrollments, logs and reports are separate from every other brand's, including brands under the same partner. Nothing is matched or shared across brands: a person enrolled with two of your brands is two patients.\n\n## What TeraRx sets up\n\nTeraRx creates each brand at onboarding, with its plans, prices, retention and rule matrix, and gives you its `tenant_id`. You get:\n\n| What | Count | Used for |\n| --- | --- | --- |\n| A brand-server client | One per environment, for all your brands | Client credentials, with the scopes your brands need, plus `tenants:read` |\n| Signing keys for patient assertions | One JWKS URL (or JWKS document) and one issuer | Token exchange for every brand's patients |\n| A clinical client | One per environment, if you run the prescriber tooling for your brands | Clinical flags. A brand whose prescriber system is separate (for example Beluga) keeps its own clinical client |\n| A webhook endpoint and secret | One, for all your brands | A brand may have its own endpoint instead |\n\n## Tokens: one brand at a time\n\nEvery token is for one brand. Name the brand with `tenant_id` when you ask for a token:\n\n```http\nPOST /v1/oauth/token\nAuthorization: Basic base64(client_id:client_secret)\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=client_credentials&tenant_id=a0000000-0000-4000-8000-000000000002&scope=enrollments:read%20enrollments:write\n```\n\nKeep one token per brand and reuse it for its hour. A call with brand A's token never sees brand B's patients; it answers `404` as if they did not exist.\n\n| Problem | `code` | HTTP |\n| --- | --- | --- |\n| No `tenant_id` | `tenant_required` | 400 |\n| A brand you may not act for, or one that is not live yet | `tenant_not_permitted` | 400 |\n\n`tenant_not_permitted` is the same answer for an unknown id and for another partner's brand. Rate limits count per brand, so one busy brand does not slow the others.\n\n## Patient assertions\n\nSign every brand's assertions with the same key and issuer, and add a `tenant_id` claim naming the brand the patient is enrolled with:\n\n```json\n{\n  \"iss\": \"https://partner.example.com\",\n  \"sub\": \"brand-pt-48213\",\n  \"aud\": \"https://sandbox.rx.tera.health\",\n  \"tenant_id\": \"a0000000-0000-4000-8000-000000000002\",\n  \"iat\": 1793635200,\n  \"exp\": 1793635500,\n  \"jti\": \"5f0c9a52-8a4e-4d4f-9a52-0f6e8b7c1d2e\"\n}\n```\n\n`sub` is the `external_patient_id` you sent on `POST /v1/enrollments` for that brand. Your ids may repeat across brands; TeraRx looks `sub` up within the brand named by `tenant_id`. An assertion without `tenant_id` is refused with `assertion_invalid`, one naming a brand you may not act for with `tenant_not_permitted`. Everything else is as in [Authentication](#tag/Auth).\n\n## Listing your brands\n\n`GET /v1/tenants` (scope `tenants:read`) lists every brand under your partner, whichever brand the token is for, with its `id`, `slug`, `display_name` and whether it is live. Use it to check your configuration against ours. You need one brand's `tenant_id`, from onboarding, to get the first token.\n\n## Webhooks\n\nEvents for all your brands go to your partner endpoint, signed with your secret, unless a brand has its own endpoint. Every event carries `tenant_id`: route on it. The payloads and signature are as in [Webhooks](#tag/Webhooks).\n\n## Reports and invoices\n\n`GET /v1/reports/brand` reports on the brand the token is for; ask once per brand. TeraRx sends one monthly invoice for all your brands, with a section per brand.\n"
    },
    {
      "name": "Enrollments",
      "description": "A patient's enrollment in coaching with one brand. Brand servers create and manage them and read status only, never clinical content."
    },
    {
      "name": "Treatment",
      "description": "The GLP-1 medication, dose and schedule the brand's prescriber set, mirrored by TeraRx and never changed."
    },
    {
      "name": "Consent",
      "description": "Proof of the legal documents a patient accepted at the brand's checkout."
    },
    {
      "name": "Brand logs",
      "description": "Logs the brand already holds, sent with the brand's own ids for safe retries, and corrected or deleted by those\nids. Brand servers get receipts, never the values back.\n"
    },
    {
      "name": "Events",
      "description": "Replay of the webhook events for the last 30 days, in order."
    },
    {
      "name": "Reports",
      "description": "The aggregate brand report. Groups under 10 patients are suppressed."
    },
    {
      "name": "Data requests",
      "description": "Export, delete and amend requests a patient makes through the brand. Moving a patient's records to another brand\nis not an API request: send TeraRx support the patient's signed authorization and support handles the transfer.\n"
    },
    {
      "name": "Patient",
      "description": "The patient's profile, settings, treatment and legal documents."
    },
    {
      "name": "Forms",
      "description": "Onboarding, check-in and eligibility forms, pinned to the version they were sent with."
    },
    {
      "name": "Logging",
      "description": "Meals, workouts, symptoms, injections and daily values. Weight and body measures go on the daily log. Logs made\nin the app can be corrected or deleted; deleted logs leave lists and rollups.\n"
    },
    {
      "name": "Protocols and plans",
      "description": "Published protocols, meal plans and workout plans, read only. Drafts are never visible to patients."
    },
    {
      "name": "Meal swap",
      "description": "The AI Coach swaps a meal for one that stays within the protocol and the brand's rule matrix."
    },
    {
      "name": "Library",
      "description": "Recipes and exercises that plans link to, that the patient can browse, save and rate."
    },
    {
      "name": "Care messaging",
      "description": "Threads with the coaches on the coached plan, photos, editing the last message, read state and reactions."
    },
    {
      "name": "Feedback",
      "description": "Popups that ask the patient about their coach. TeraRx writes the questions and decides when to ask."
    },
    {
      "name": "AI Coach",
      "description": "Chat with the AI Coach on every plan, and what it remembers. Replies stream or can be polled."
    },
    {
      "name": "Reminders",
      "description": "Upcoming injection, check-in, logging and habit reminders, and the patient's reminder settings, including whether\nthe AI Coach may start conversations.\n"
    },
    {
      "name": "Progress",
      "description": "Today at a glance, targets for a day, a week's stats and the milestones the patient reached."
    },
    {
      "name": "Clinical flags",
      "description": "Flags for the brand's prescriber, read and acted on with the clinical client. On the AI-only plan every\nescalation lands here. Each write names the individual prescriber in `on_behalf_of`.\n"
    },
    {
      "name": "Webhooks",
      "description": "TeraRx tells your server about changes with signed HTTPS `POST`s to the webhook URL registered for your brand. Each delivery is one event. Payloads are thin: ids and the minimum needed to route, never message bodies, form answers, protocol text or health values. Fetch details through the API with the right token.\n\n## Envelope\n\n```json\n{\n  \"id\": \"0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7\",\n  \"type\": \"clinical.flag_raised\",\n  \"created_at\": \"2026-10-26T14:05:00Z\",\n  \"tenant_id\": \"a0000000-0000-4000-8000-000000000002\",\n  \"data\": { \"enrollment_id\": \"…\", \"external_patient_id\": \"brand-pt-48213\", \"…\": \"…\" }\n}\n```\n\n`data` always has `enrollment_id` and your `external_patient_id`. The full list of events is below, and each event's payload is in the Webhooks section of the API reference. You can limit the events sent to you when your webhook is registered; by default you get all of them.\n\n| Event | When |\n| --- | --- |\n| `enrollment.created` | An enrollment was created |\n| `enrollment.stage_changed` | The enrollment moved to the next stage |\n| `enrollment.paused`, `enrollment.resumed`, `enrollment.cancelled` | Status changes |\n| `care_team.assigned`, `care_team.changed` | A coach was assigned, reassigned or removed (coached plan) |\n| `care_team.capacity_warning` | No licensed coach with capacity is available; the enrollment waits |\n| `care_team.feedback_due` | TeraRx would like the patient's feedback on a coach; show your feedback popup |\n| `form.requested`, `onboarding.completed` | A form was sent; every blocking onboarding form is done |\n| `protocol.published`, `protocol.updated` | A protocol went live, or a new version replaced it |\n| `message.created` | A new care or AI Coach message (ids only) |\n| `clinical.flag_raised` | A clinical flag for your prescriber |\n| `clinical.flag_redelivered` | A flag passed `ack_due_at` without an acknowledgement |\n| `clinical.flag_acknowledged`, `clinical.flag_resolved` | A prescriber acted on a flag |\n| `patient.disengaged` | No activity for your `disengaged_after_days` (7 by default) |\n| `patient.milestone_reached` | The patient reached a milestone; read its details with the patient's token |\n| `reminder.due` | A reminder is due; send the notification in your own words |\n| `data_request.completed` | An export, delete or amend request finished |\n\nOn the AI-only plan, **every** alert that raises the risk level and every AI Coach escalation sends `clinical.flag_raised`, even when the alert rule is set not to notify the brand: there is no coach to reach, so your prescriber is the human in the loop.\n\n## Verifying the signature\n\nEvery delivery carries three headers:\n\n| Header | Value |\n| --- | --- |\n| `TeraRx-Timestamp` | Unix time in seconds when this attempt was signed |\n| `TeraRx-Signature` | `v1=<hex>`; during a secret rotation `v1=<new>,v1=<old>` |\n| `TeraRx-Event-Id` | The event id, the same as `id` in the body |\n\nStep by step:\n\n1. Read the **raw** request body as bytes. Do not parse and re-serialize the JSON first; any change in whitespace breaks the signature.\n2. Read `TeraRx-Timestamp`. Reject the delivery if it is more than 5 minutes from your clock (replay protection).\n3. Build the signed payload: the timestamp, a period, then the raw body: `<timestamp>.<raw body>`.\n4. Compute `HMAC-SHA256(secret, signed_payload)` as lowercase hex, using your webhook secret.\n5. Split `TeraRx-Signature` on commas. Accept the delivery if **any** `v1=` value matches, compared in constant time.\n6. Dedupe on `TeraRx-Event-Id`: a retry carries the same id. Store ids for at least 24 hours and answer `200` to a repeat without processing it again.\n7. Answer `2xx` quickly, then process. Do the work after you respond, or queue it.\n\n### Worked example\n\nWith the secret `example_webhook_secret_new`, timestamp `1793023500` and this exact body:\n\n```\n{\"id\":\"0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7\",\"type\":\"clinical.flag_raised\",\"created_at\":\"2026-10-26T14:05:00Z\",\"tenant_id\":\"a0000000-0000-4000-8000-000000000002\",\"data\":{\"enrollment_id\":\"0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5\",\"external_patient_id\":\"brand-pt-48213\",\"flag_id\":\"0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6\",\"severity\":\"critical\",\"raised_risk_to\":\"high\",\"ack_due_at\":\"2026-10-26T16:05:00Z\"}}\n```\n\nthe header is `TeraRx-Signature: v1=5e9f492e2cee549f0d1688a9d4a6d0505ea1687e5c293eb28a01bad16ee7aa2a`. During a rotation where the old secret was `example_webhook_secret_old`, it is `v1=5e9f492e2cee549f0d1688a9d4a6d0505ea1687e5c293eb28a01bad16ee7aa2a,v1=2e8d962ded17a921cbc548b968abc024e9fcae75fd8ff8a0f2044999b0898416`.\n\n### Node\n\n```js\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\n\nexport function verifyTeraRx(rawBody, headers, secret, now = Date.now()) {\n  const timestamp = headers[\"terarx-timestamp\"];\n  if (!timestamp || Math.abs(now / 1000 - Number(timestamp)) > 300) return false;\n  const expected = createHmac(\"sha256\", secret).update(`${timestamp}.${rawBody}`).digest();\n  return (headers[\"terarx-signature\"] ?? \"\").split(\",\").some((part) => {\n    const [version, hex] = part.trim().split(\"=\");\n    const given = Buffer.from(hex ?? \"\", \"hex\");\n    return version === \"v1\" && given.length === expected.length && timingSafeEqual(given, expected);\n  });\n}\n```\n\n### Python\n\n```python\nimport hashlib, hmac, time\n\ndef verify_terarx(raw_body: bytes, headers: dict, secret: str) -> bool:\n    timestamp = headers.get(\"TeraRx-Timestamp\", \"\")\n    if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:\n        return False\n    expected = hmac.new(secret.encode(), f\"{timestamp}.\".encode() + raw_body, hashlib.sha256).hexdigest()\n    return any(\n        part.strip().startswith(\"v1=\") and hmac.compare_digest(part.strip()[3:], expected)\n        for part in headers.get(\"TeraRx-Signature\", \"\").split(\",\")\n    )\n```\n\n## Secret rotation\n\nTeraRx issues a new secret on request. For the rotation window (24 hours by default) every delivery is signed with both secrets, new first. Deploy the new secret, confirm deliveries verify with it, and tell TeraRx to end the window; after that only the new signature is sent.\n\n## Delivery and retries\n\n* Answer with any `2xx` within **10 seconds**. Anything else, or no answer in time, is a failed attempt.\n* Failed attempts are retried with exponential backoff (about 30 s, 2 min, 10 min, 30 min, then hourly) for **24 hours**. Each attempt is signed again with a fresh timestamp; the event id stays the same.\n* After 24 hours the event is dead-lettered. Nothing is lost: replay it with `GET /v1/events?since=<last event id you processed>`, which keeps 30 days of events in order.\n* Deliveries are not guaranteed to arrive in order. Use `created_at`, or fetch the current state through the API, when order matters.\n\n## Clinical flag re-delivery\n\nA flag must be acknowledged by its `ack_due_at`, which comes from the acknowledgement time agreed in your contract. When it passes, the flag stays open and TeraRx sends `clinical.flag_redelivered` with a new event id (so your dedupe does not swallow it), a new `ack_due_at` and a `redelivery_count`. This repeats until a prescriber acknowledges the flag with `POST /v1/clinical-flags/{flag_id}/acknowledge`. Route re-deliveries to whoever covers when the first prescriber does not answer.\n"
    }
  ],
  "paths": {
    "/v1/oauth/token": {
      "post": {
        "operationId": "createToken",
        "tags": [
          "Auth"
        ],
        "summary": "Get an access token",
        "description": "**Client credentials** (brand servers and prescriber systems): authenticate with HTTP Basic\n(`client_id:client_secret`) and send `grant_type=client_credentials`. The token lasts 1 hour and carries the\nclient's scopes, or the subset you ask for in `scope`.\n\n**Token exchange** (patients): send the brand-signed assertion as `subject_token`. No client secret is needed,\nso the brand's app can make this call itself with an assertion its server just signed. The result is a\n15-minute patient token bound to the one enrollment the assertion names. There is no refresh token; sign a\nnew assertion when it expires. Patient tokens are issued for enrollments that are `pending_screening`,\n`active` or `paused`.\n\nAn `integration` client cannot get tokens from the production API (`unauthorized_client`).\n\n**Platform partners** that act for several brands name the brand with `tenant_id` on the client-credentials\nrequest, and in a `tenant_id` claim in patient assertions. Every token is for one brand. See \"Platform\npartners\" in the Tenants tag.\n\nError codes: `invalid_client`, `client_revoked`, `unauthorized_client`, `unsupported_grant_type`, `invalid_scope`,\n`tenant_required`, `tenant_not_permitted`, `token_exchange_not_allowed`, `assertion_signature_invalid`,\n`assertion_expired`, `assertion_lifetime_too_long`, `assertion_replayed`, `assertion_audience_invalid`,\n`assertion_issuer_unknown`, `assertion_invalid`, `patient_not_found`, `enrollment_not_active`.\n",
        "security": [
          {
            "oauthClientBasic": []
          },
          {}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              },
              "examples": {
                "client_credentials": {
                  "summary": "Brand server",
                  "value": {
                    "grant_type": "client_credentials",
                    "scope": "enrollments:read enrollments:write logs:write"
                  }
                },
                "partner_client_credentials": {
                  "summary": "Platform partner, for one of its brands",
                  "value": {
                    "grant_type": "client_credentials",
                    "tenant_id": "a0000000-0000-4000-8000-000000000002",
                    "scope": "enrollments:read enrollments:write"
                  }
                },
                "token_exchange": {
                  "summary": "Patient token from a brand assertion",
                  "value": {
                    "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
                    "subject_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImRlbW8tMjAyNi0xMCJ9.<claims>.<signature>",
                    "subject_token_type": "urn:ietf:params:oauth:token-type:jwt"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Cache-Control": {
                "description": "Always `no-store` (RFC 6749 section 5.1).",
                "schema": {
                  "type": "string"
                },
                "example": "no-store"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                },
                "examples": {
                  "client_credentials": {
                    "summary": "Brand server token",
                    "value": {
                      "access_token": "trx_at_example_not_a_real_token",
                      "token_type": "Bearer",
                      "expires_in": 3600,
                      "scope": "enrollments:read enrollments:write logs:write"
                    }
                  },
                  "token_exchange": {
                    "summary": "Patient token",
                    "value": {
                      "access_token": "trx_pt_example_not_a_real_token",
                      "token_type": "Bearer",
                      "expires_in": 900,
                      "issued_token_type": "urn:ietf:params:oauth:token-type:access_token"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The grant is invalid. `error` follows RFC 6749; `code` says exactly why.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthProblem"
                },
                "examples": {
                  "assertion_expired": {
                    "summary": "The assertion's exp has passed",
                    "value": {
                      "type": "about:blank",
                      "title": "Bad Request",
                      "status": 400,
                      "code": "assertion_expired",
                      "detail": "The assertion has expired. Sign a new one.",
                      "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                      "error": "invalid_grant",
                      "error_description": "The assertion has expired."
                    }
                  },
                  "assertion_signature_invalid": {
                    "summary": "No registered key verifies the signature",
                    "value": {
                      "type": "about:blank",
                      "title": "Bad Request",
                      "status": 400,
                      "code": "assertion_signature_invalid",
                      "detail": "The assertion signature does not match any key in the brand's JWKS.",
                      "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                      "error": "invalid_grant",
                      "error_description": "Invalid assertion signature."
                    }
                  },
                  "assertion_replayed": {
                    "summary": "The jti was already used",
                    "value": {
                      "type": "about:blank",
                      "title": "Bad Request",
                      "status": 400,
                      "code": "assertion_replayed",
                      "detail": "This assertion's jti has already been used. Assertions are single use.",
                      "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                      "error": "invalid_grant",
                      "error_description": "Assertion already used."
                    }
                  },
                  "patient_not_found": {
                    "summary": "No enrollment for this sub",
                    "value": {
                      "type": "about:blank",
                      "title": "Bad Request",
                      "status": 400,
                      "code": "patient_not_found",
                      "detail": "No open enrollment matches the assertion's subject for this brand.",
                      "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                      "error": "invalid_grant",
                      "error_description": "Unknown patient."
                    }
                  },
                  "tenant_required": {
                    "summary": "A partner client did not name the brand",
                    "value": {
                      "type": "about:blank",
                      "title": "Bad Request",
                      "status": 400,
                      "code": "tenant_required",
                      "detail": "This client acts for several brands. Send tenant_id for the brand this token is for.",
                      "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                      "error": "invalid_request",
                      "error_description": "tenant_id is required."
                    }
                  },
                  "tenant_not_permitted": {
                    "summary": "A brand this client may not act for",
                    "value": {
                      "type": "about:blank",
                      "title": "Bad Request",
                      "status": 400,
                      "code": "tenant_not_permitted",
                      "detail": "This client cannot get tokens for that tenant_id. GET /v1/tenants lists the brands it may act for.",
                      "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                      "error": "invalid_target",
                      "error_description": "Tenant not permitted."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "description": "Client authentication failed or the client is revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthProblem"
                },
                "examples": {
                  "client_revoked": {
                    "summary": "Revoked client",
                    "value": {
                      "type": "about:blank",
                      "title": "Unauthorized",
                      "status": 401,
                      "code": "client_revoked",
                      "detail": "This client has been revoked. Contact TeraRx for new credentials.",
                      "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                      "error": "invalid_client",
                      "error_description": "Client revoked."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/tenants": {
      "get": {
        "operationId": "listTenants",
        "tags": [
          "Tenants"
        ],
        "summary": "List the brands this client may act for",
        "description": "A platform partner's client sees every brand under the partner, whichever brand its token is for. A brand's own\nclient sees its own brand. Use the ids as `tenant_id` on the token request and in patient assertions. A `cursor`\nthis list did not return answers `422 validation_failed`, so a partial list is never mistaken for the whole.\n",
        "security": [
          {
            "brandServer": [
              "tenants:read"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of brands.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantList"
                },
                "example": {
                  "data": [
                    {
                      "id": "a0000000-0000-4000-8000-000000000002",
                      "slug": "northwind-health",
                      "display_name": "Northwind Health",
                      "is_enabled": true
                    },
                    {
                      "id": "a0000000-0000-4000-8000-000000000003",
                      "slug": "summit-wellness",
                      "display_name": "Summit Wellness",
                      "is_enabled": false
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments": {
      "post": {
        "operationId": "createEnrollment",
        "tags": [
          "Enrollments"
        ],
        "summary": "Enroll a patient",
        "description": "Call this at checkout, or when an existing patient subscribes. In one transaction TeraRx creates the patient\nrecord for your brand (or reuses it for a returning patient), the enrollment, the consent records, the first\ntreatment version and the onboarding form assignments from TeraRx's form rules for your plan, prefilled from `intake`.\nOn the coached plan it then queues coach assignment for each care role.\n\nFires `enrollment.created`, then `form.requested` per form and, once coaches are assigned, `care_team.assigned`.\n\nUnique by `external_order_id`, and by `external_patient_id` among `active` and `paused` enrollments.\nError codes: `enrollment_exists`, `external_order_exists` (409); `plan_not_offered`, `unknown_medication`,\n`unknown_legal_document`, `validation_failed` (422).\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentCreate"
              },
              "example": {
                "plan_code": "ai_health_fitness",
                "external_patient_id": "brand-pt-48213",
                "external_order_id": "ord-2026-10-000123",
                "purchased_at": "2026-10-21T14:58:00Z",
                "patient": {
                  "first_name": "Jordan",
                  "last_name": "Rivera",
                  "email": "jordan.rivera@example.com",
                  "phone": "+12025550143",
                  "date_of_birth": "1986-04-12",
                  "sex": "female",
                  "height_cm": 165.1,
                  "state_code": "NY",
                  "timezone": "America/New_York",
                  "units": "imperial",
                  "conditions": [
                    "prediabetes"
                  ],
                  "health_profile": {
                    "goal_weight_kg": 72.5,
                    "activity_level": "lightly_active",
                    "food_allergies": [
                      "peanuts"
                    ],
                    "dietary_restrictions": [
                      "dairy_free"
                    ],
                    "food_dislikes": [
                      "mushrooms"
                    ],
                    "cooking": {
                      "skill": "beginner",
                      "appliances": [
                        "stove_range",
                        "microwave",
                        "air_fryer"
                      ],
                      "meal_preparer": "mostly_myself"
                    },
                    "lifestyle": {
                      "sleep_hours": 6.5,
                      "alcohol": "occasional",
                      "smoking": "never"
                    }
                  }
                },
                "intake": {
                  "weight_kg": 96.2,
                  "goal_weight_kg": 72.5,
                  "activity_level": "lightly_active"
                },
                "consents": [
                  {
                    "document_code": "coaching_consent",
                    "version": "2026-01",
                    "accepted_at": "2026-10-21T14:57:30Z",
                    "evidence": {
                      "ip": "203.0.113.24",
                      "checkout_id": "chk_2026_10_000123"
                    }
                  }
                ],
                "treatment": {
                  "medication_id": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f",
                  "dose_mg": 0.25,
                  "phase": "titration",
                  "injection_weekday": 1,
                  "started_on": "2026-09-28"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Enrolled.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              },
              "Location": {
                "description": "URL of the new enrollment.",
                "schema": {
                  "type": "string"
                },
                "example": "/v1/enrollments/0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                },
                "example": {
                  "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "external_order_id": "ord-2026-10-000123",
                  "plan_code": "ai_health_fitness",
                  "status": "active",
                  "stage": "awaiting_assignment",
                  "risk_level": "normal",
                  "data_sharing": true,
                  "purchased_at": "2026-10-21T14:58:00Z",
                  "created_at": "2026-10-21T14:58:02Z",
                  "assigned_at": null,
                  "onboarding_completed_at": null,
                  "first_protocol_published_at": null,
                  "last_activity_at": null,
                  "ended_at": null,
                  "care_team": [
                    {
                      "care_role": "health_coach",
                      "assigned": false,
                      "assigned_at": null
                    },
                    {
                      "care_role": "fitness_coach",
                      "assigned": false,
                      "assigned_at": null
                    }
                  ],
                  "forms": [
                    {
                      "form_assignment_id": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2",
                      "form_code": "glp1_onboarding",
                      "purpose": "onboarding",
                      "status": "sent",
                      "blocks_onboarding": true,
                      "due_at": "2026-10-24T15:00:00Z",
                      "completed_at": null
                    }
                  ],
                  "protocols": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "listEnrollments",
        "tags": [
          "Enrollments"
        ],
        "summary": "List enrollments",
        "description": "Your brand's enrollments, newest first. Filter by `external_patient_id` to find one patient's enrollments.",
        "security": [
          {
            "brandServer": [
              "enrollments:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "external_patient_id",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/ExternalId"
            },
            "example": "brand-pt-48213"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/EnrollmentStatus"
            },
            "example": "active"
          },
          {
            "name": "risk_level",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/RiskLevel"
            },
            "example": "high"
          },
          {
            "name": "plan_code",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/PlanCode"
            },
            "example": "ai_only"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of enrollments.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                      "external_patient_id": "brand-pt-48213",
                      "external_order_id": "ord-2026-10-000123",
                      "plan_code": "ai_health_fitness",
                      "status": "active",
                      "stage": "protocols_active",
                      "risk_level": "normal",
                      "data_sharing": true,
                      "purchased_at": "2026-10-21T14:58:00Z",
                      "created_at": "2026-10-21T14:58:02Z",
                      "assigned_at": "2026-10-21T15:12:00Z",
                      "onboarding_completed_at": "2026-10-22T09:30:00Z",
                      "first_protocol_published_at": "2026-10-23T16:45:00Z",
                      "last_activity_at": "2026-10-26T13:40:00Z",
                      "ended_at": null,
                      "care_team": [
                        {
                          "care_role": "health_coach",
                          "assigned": true,
                          "assigned_at": "2026-10-21T15:10:00Z"
                        },
                        {
                          "care_role": "fitness_coach",
                          "assigned": true,
                          "assigned_at": "2026-10-21T15:12:00Z"
                        }
                      ],
                      "forms": [
                        {
                          "form_assignment_id": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2",
                          "form_code": "glp1_onboarding",
                          "purpose": "onboarding",
                          "status": "completed",
                          "blocks_onboarding": true,
                          "due_at": "2026-10-24T15:00:00Z",
                          "completed_at": "2026-10-22T09:30:00Z"
                        }
                      ],
                      "protocols": [
                        {
                          "protocol_id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                          "type": "nutrition",
                          "version": 1,
                          "published_at": "2026-10-23T16:45:00Z"
                        }
                      ]
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "get": {
        "operationId": "getEnrollment",
        "tags": [
          "Enrollments"
        ],
        "summary": "Get an enrollment",
        "description": "Stage, care team status, form status, protocol timestamps and risk level. No clinical content.",
        "security": [
          {
            "brandServer": [
              "enrollments:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The enrollment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                },
                "example": {
                  "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "external_order_id": "ord-2026-10-000123",
                  "plan_code": "ai_only",
                  "status": "active",
                  "stage": "protocols_active",
                  "risk_level": "elevated",
                  "data_sharing": true,
                  "purchased_at": "2026-10-21T14:58:00Z",
                  "created_at": "2026-10-21T14:58:02Z",
                  "assigned_at": null,
                  "onboarding_completed_at": "2026-10-22T09:30:00Z",
                  "first_protocol_published_at": "2026-10-22T09:31:10Z",
                  "last_activity_at": "2026-10-26T13:40:00Z",
                  "ended_at": null,
                  "care_team": [],
                  "forms": [
                    {
                      "form_assignment_id": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2",
                      "form_code": "glp1_onboarding",
                      "purpose": "onboarding",
                      "status": "completed",
                      "blocks_onboarding": true,
                      "due_at": "2026-10-24T15:00:00Z",
                      "completed_at": "2026-10-22T09:30:00Z"
                    }
                  ],
                  "protocols": [
                    {
                      "protocol_id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                      "type": "nutrition",
                      "version": 2,
                      "published_at": "2026-10-25T08:00:00Z"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/patient": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "patch": {
        "operationId": "updateEnrollmentPatient",
        "tags": [
          "Enrollments"
        ],
        "summary": "Update the patient's details",
        "description": "Contact details, demographics, time zone, conditions and the health profile, when they change in your system.\nChanges reach the care team at once and apply to plans and AI Coach replies generated after them.\n\nA new `state_code` matters: coaches are licensed per state. A coach not licensed in the new state is taken off the\npatient and a licensed one is found, so you get `care_team.changed` with `reason_code: state_change` (or\n`care_team.capacity_warning` if none is free). Until then that role shows `assigned: false` in the response.\n\nError codes: `enrollment_not_active` (409) for a cancelled or completed enrollment, `validation_failed` (422).\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/BrandPatientUpdate"
              },
              "example": {
                "phone": "+12025550178",
                "state_code": "NJ",
                "health_profile": {
                  "food_allergies": [
                    "peanuts",
                    "sesame"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The enrollment's status after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                },
                "example": {
                  "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "external_order_id": "ord-2026-10-000123",
                  "plan_code": "ai_health_fitness",
                  "status": "active",
                  "stage": "protocols_active",
                  "risk_level": "normal",
                  "data_sharing": true,
                  "purchased_at": "2026-10-21T14:58:00Z",
                  "created_at": "2026-10-21T14:58:02Z",
                  "assigned_at": "2026-10-21T15:12:00Z",
                  "onboarding_completed_at": "2026-10-22T09:30:00Z",
                  "first_protocol_published_at": "2026-10-23T16:45:00Z",
                  "last_activity_at": "2026-10-26T13:40:00Z",
                  "ended_at": null,
                  "care_team": [
                    {
                      "care_role": "health_coach",
                      "assigned": false,
                      "assigned_at": null
                    },
                    {
                      "care_role": "fitness_coach",
                      "assigned": true,
                      "assigned_at": "2026-10-21T15:12:00Z"
                    }
                  ],
                  "forms": [],
                  "protocols": [
                    {
                      "protocol_id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                      "type": "nutrition",
                      "version": 1,
                      "published_at": "2026-10-23T16:45:00Z"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/plan": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "changeEnrollmentPlan",
        "tags": [
          "Enrollments"
        ],
        "summary": "Change plan",
        "description": "Move between `ai_health_fitness` and `ai_only`. Moving to `ai_only` ends the care team assignments\n(`care_team.changed`); moving to the coached plan queues assignment (`care_team.assigned` follows).\nBilling switches plan from the change. Error codes: `plan_not_offered` (422), `same_plan`,\n`invalid_status_transition` (409).\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanChange"
              },
              "example": {
                "plan_code": "ai_only",
                "reason": "Patient downgraded at renewal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The enrollment on its new plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                },
                "example": {
                  "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "external_order_id": "ord-2026-10-000123",
                  "plan_code": "ai_only",
                  "status": "active",
                  "stage": "protocols_active",
                  "risk_level": "normal",
                  "data_sharing": true,
                  "purchased_at": "2026-10-21T14:58:00Z",
                  "created_at": "2026-10-21T14:58:02Z",
                  "assigned_at": "2026-10-21T15:12:00Z",
                  "onboarding_completed_at": "2026-10-22T09:30:00Z",
                  "first_protocol_published_at": "2026-10-23T16:45:00Z",
                  "last_activity_at": "2026-10-26T13:40:00Z",
                  "ended_at": null,
                  "care_team": [],
                  "forms": [],
                  "protocols": [
                    {
                      "protocol_id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                      "type": "nutrition",
                      "version": 1,
                      "published_at": "2026-10-23T16:45:00Z"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/pause": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "pauseEnrollment",
        "tags": [
          "Enrollments"
        ],
        "summary": "Pause",
        "description": "Paused days are not billed. The patient keeps read access to their plan; reminders and new protocols stop.\nThe enrollment stays paused until you call resume.\nFires `enrollment.paused`. Error code: `invalid_status_transition` (409) unless the enrollment is `active`.\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Pause"
              },
              "example": {
                "reason": "Patient travelling"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The paused enrollment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                },
                "example": {
                  "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "external_order_id": "ord-2026-10-000123",
                  "plan_code": "ai_health_fitness",
                  "status": "paused",
                  "stage": "protocols_active",
                  "risk_level": "normal",
                  "data_sharing": true,
                  "purchased_at": "2026-10-21T14:58:00Z",
                  "created_at": "2026-10-21T14:58:02Z",
                  "assigned_at": "2026-10-21T15:12:00Z",
                  "onboarding_completed_at": "2026-10-22T09:30:00Z",
                  "first_protocol_published_at": "2026-10-23T16:45:00Z",
                  "last_activity_at": "2026-10-26T13:40:00Z",
                  "ended_at": null,
                  "care_team": [
                    {
                      "care_role": "health_coach",
                      "assigned": true,
                      "assigned_at": "2026-10-21T15:10:00Z"
                    },
                    {
                      "care_role": "fitness_coach",
                      "assigned": true,
                      "assigned_at": "2026-10-21T15:12:00Z"
                    }
                  ],
                  "forms": [],
                  "protocols": []
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/resume": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "resumeEnrollment",
        "tags": [
          "Enrollments"
        ],
        "summary": "Resume",
        "description": "Back to `active`. Fires `enrollment.resumed`. Error code: `invalid_status_transition` (409) unless the enrollment is `paused`.\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "responses": {
          "200": {
            "description": "The active enrollment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                },
                "example": {
                  "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "external_order_id": "ord-2026-10-000123",
                  "plan_code": "ai_health_fitness",
                  "status": "active",
                  "stage": "protocols_active",
                  "risk_level": "normal",
                  "data_sharing": true,
                  "purchased_at": "2026-10-21T14:58:00Z",
                  "created_at": "2026-10-21T14:58:02Z",
                  "assigned_at": "2026-10-21T15:12:00Z",
                  "onboarding_completed_at": "2026-10-22T09:30:00Z",
                  "first_protocol_published_at": "2026-10-23T16:45:00Z",
                  "last_activity_at": "2026-11-15T08:02:00Z",
                  "ended_at": null,
                  "care_team": [
                    {
                      "care_role": "health_coach",
                      "assigned": true,
                      "assigned_at": "2026-10-21T15:10:00Z"
                    },
                    {
                      "care_role": "fitness_coach",
                      "assigned": true,
                      "assigned_at": "2026-10-21T15:12:00Z"
                    }
                  ],
                  "forms": [],
                  "protocols": [
                    {
                      "protocol_id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                      "type": "nutrition",
                      "version": 1,
                      "published_at": "2026-10-23T16:45:00Z"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/cancel": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "cancelEnrollment",
        "tags": [
          "Enrollments"
        ],
        "summary": "Cancel",
        "description": "Ends the enrollment and the care team assignments, and starts the retention clock for the patient's records\n(your contract's retention period). Fires `enrollment.cancelled`. Error code: `invalid_status_transition` (409)\nwhen the enrollment has already ended.\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Cancel"
              },
              "example": {
                "reason": "subscription_ended"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The cancelled enrollment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                },
                "example": {
                  "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "external_order_id": "ord-2026-10-000123",
                  "plan_code": "ai_health_fitness",
                  "status": "cancelled",
                  "stage": "protocols_active",
                  "risk_level": "normal",
                  "data_sharing": true,
                  "purchased_at": "2026-10-21T14:58:00Z",
                  "created_at": "2026-10-21T14:58:02Z",
                  "assigned_at": "2026-10-21T15:12:00Z",
                  "onboarding_completed_at": "2026-10-22T09:30:00Z",
                  "first_protocol_published_at": "2026-10-23T16:45:00Z",
                  "last_activity_at": "2026-10-26T13:40:00Z",
                  "ended_at": "2026-12-21T00:00:00Z",
                  "care_team": [
                    {
                      "care_role": "health_coach",
                      "assigned": false,
                      "assigned_at": null
                    },
                    {
                      "care_role": "fitness_coach",
                      "assigned": false,
                      "assigned_at": null
                    }
                  ],
                  "forms": [],
                  "protocols": []
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/ai-coach-outreach": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "requestAiCoachOutreach",
        "tags": [
          "Enrollments"
        ],
        "summary": "Ask the AI Coach to reach out",
        "description": "The AI Coach starts a short check-in chat with the patient, for example after `patient.disengaged`. It goes out\nwithin minutes, outside the patient's quiet hours; you get `message.created` when it does, and send your push\nthen. At most one request every 3 days per enrollment. Error codes: `outreach_too_soon` (409),\n`outreach_off` (409) when the patient turned AI Coach outreach off, `ai_paused` (409),\n`enrollment_not_active` (409).\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "responses": {
          "202": {
            "description": "Scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCoachOutreach"
                },
                "example": {
                  "id": "0190f5e4-5d6e-7f80-9a1b-c2d3e4f5a6b7",
                  "status": "scheduled",
                  "scheduled_for": "2026-10-27T15:00:00Z",
                  "sent_at": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/medications": {
      "get": {
        "operationId": "listMedications",
        "tags": [
          "Treatment"
        ],
        "summary": "List medications",
        "description": "The GLP-1 products you can name in a treatment. The platform catalogue plus any added for your brand.",
        "security": [
          {
            "brandServer": [
              "enrollments:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Medications.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MedicationList"
                },
                "example": {
                  "data": [
                    {
                      "id": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f",
                      "ingredient": "semaglutide",
                      "product_name": "Wegovy",
                      "source": "branded",
                      "route": "injection",
                      "standard_doses_mg": [
                        0.25,
                        0.5,
                        1,
                        1.7,
                        2.4
                      ],
                      "scope": "platform"
                    },
                    {
                      "id": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                      "ingredient": "tirzepatide",
                      "product_name": "Compounded tirzepatide",
                      "source": "compounded",
                      "route": "injection",
                      "standard_doses_mg": [],
                      "scope": "platform"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/treatments": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "createTreatment",
        "tags": [
          "Treatment"
        ],
        "summary": "Update the treatment mirror",
        "description": "Send the treatment whenever your prescriber sets or changes it: a new dose, a phase change, a pause or a stop.\nEach call appends a version and the latest becomes current. TeraRx never changes a dose; protocols are\nredrafted against the new dose by the rule matrix.\n\nError codes: `unknown_medication`, `validation_failed` (422); `invalid_status_transition` (409) on an ended enrollment.\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TreatmentInput"
              },
              "example": {
                "medication_id": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f",
                "dose_mg": 0.5,
                "phase": "titration",
                "injection_weekday": 1,
                "started_on": "2026-09-28",
                "effective_from": "2026-10-26T00:00:00Z",
                "note": "Step up to 0.5 mg per titration schedule"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new current treatment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Treatment"
                },
                "example": {
                  "id": "0190f5c7-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
                  "medication": {
                    "id": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f",
                    "ingredient": "semaglutide",
                    "product_name": "Wegovy",
                    "source": "branded",
                    "route": "injection",
                    "standard_doses_mg": [
                      0.25,
                      0.5,
                      1,
                      1.7,
                      2.4
                    ],
                    "scope": "platform"
                  },
                  "dose_mg": 0.5,
                  "dose_amount": null,
                  "dose_unit": null,
                  "phase": "titration",
                  "schedule": null,
                  "injection_weekday": 1,
                  "started_on": "2026-09-28",
                  "treatment_week": 5,
                  "effective_from": "2026-10-26T00:00:00Z",
                  "source": "brand_api",
                  "note": "Step up to 0.5 mg per titration schedule",
                  "created_at": "2026-10-26T14:05:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "listTreatments",
        "tags": [
          "Treatment"
        ],
        "summary": "List treatment versions",
        "description": "The mirrored treatment history, newest first. Use it to reconcile with your own records.",
        "security": [
          {
            "brandServer": [
              "enrollments:read"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Treatment versions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TreatmentList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c7-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
                      "medication": {
                        "id": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f",
                        "ingredient": "semaglutide",
                        "product_name": "Wegovy",
                        "source": "branded",
                        "route": "injection",
                        "standard_doses_mg": [
                          0.25,
                          0.5,
                          1,
                          1.7,
                          2.4
                        ],
                        "scope": "platform"
                      },
                      "dose_mg": 0.5,
                      "dose_amount": null,
                      "dose_unit": null,
                      "phase": "titration",
                      "schedule": null,
                      "injection_weekday": 1,
                      "started_on": "2026-09-28",
                      "treatment_week": 5,
                      "effective_from": "2026-10-26T00:00:00Z",
                      "source": "brand_api",
                      "note": "Step up to 0.5 mg per titration schedule",
                      "created_at": "2026-10-26T14:05:00Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/consents": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "recordConsents",
        "tags": [
          "Consent"
        ],
        "summary": "Record consent proof",
        "description": "Proof that the patient accepted legal documents in your checkout, when it was not sent with the enrollment.\nDocuments still not accepted are shown to the patient on first open (`GET /v1/patient/legal-documents`).\nRecording a document the patient already accepted keeps the first acceptance.\nError code: `unknown_legal_document` (422).\n",
        "security": [
          {
            "brandServer": [
              "enrollments:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsentProofBatch"
              },
              "example": {
                "consents": [
                  {
                    "document_code": "terms",
                    "version": "2026-01",
                    "accepted_at": "2026-10-21T14:57:30Z",
                    "evidence": {
                      "ip": "203.0.113.24",
                      "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X)",
                      "checkout_id": "chk_2026_10_000123"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The consent records, one per document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsentRecordList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c8-2b3c-7d4e-8f50-6a7b8c9d0e1f",
                      "document_code": "terms",
                      "document_version": "2026-01",
                      "accepted_at": "2026-10-21T14:57:30Z",
                      "withdrawn_at": null,
                      "source": "brand_api"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "listConsents",
        "tags": [
          "Consent"
        ],
        "summary": "List consent records",
        "description": "Every document the patient has accepted for this enrollment, from your checkout or from the app.",
        "security": [
          {
            "brandServer": [
              "enrollments:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Consent records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsentRecordList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c8-2b3c-7d4e-8f50-6a7b8c9d0e1f",
                      "document_code": "coaching_consent",
                      "document_version": "2026-01",
                      "accepted_at": "2026-10-21T14:57:30Z",
                      "withdrawn_at": null,
                      "source": "brand_api"
                    },
                    {
                      "id": "0190f5c8-3c4d-7e5f-9a61-7b8c9d0e1f2a",
                      "document_code": "privacy",
                      "document_version": "2026-01",
                      "accepted_at": "2026-10-22T09:05:12Z",
                      "withdrawn_at": null,
                      "source": "brand_app"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/meals": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "createBrandMealLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Send a meal log",
        "description": "A meal your app already recorded. Returns a receipt, not the values. A repeated `external_id` returns the\nfirst receipt with `200`. While the patient has data sharing off, the log is stored but the care team does not see it.\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrandMealLogInput"
              },
              "example": {
                "eaten_at": "2026-10-26T12:30:00Z",
                "meal_type": "lunch",
                "description": "Chicken salad",
                "entry_method": "manual",
                "protein_g": 35,
                "calories_kcal": 420,
                "external_id": "meal-77120"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Already received; the first receipt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "external_id": "meal-77120",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T12:31:04Z",
                  "updated_at": "2026-10-26T12:31:04Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "201": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "external_id": "meal-77120",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T12:31:04Z",
                  "updated_at": "2026-10-26T12:31:04Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/workouts": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "createBrandWorkoutLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Send a workout log",
        "description": "A workout your app already recorded. A repeated `external_id` returns the first receipt with `200`.",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrandWorkoutLogInput"
              },
              "example": {
                "started_at": "2026-10-26T07:00:00Z",
                "activity_type": "walk",
                "duration_min": 30,
                "external_id": "workout-5531"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Already received; the first receipt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-6e7f-7081-9ba3-2c3d4e5f6071",
                  "external_id": "workout-5531",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T07:40:00Z",
                  "updated_at": "2026-10-26T07:40:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "201": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-6e7f-7081-9ba3-2c3d4e5f6071",
                  "external_id": "workout-5531",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T07:40:00Z",
                  "updated_at": "2026-10-26T07:40:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/symptoms": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "createBrandSymptomLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Send a symptom log",
        "description": "A symptom your app or clinicians already recorded. Alert rules run on it exactly as on a patient's own log,\nso a red flag here raises a clinical flag. A repeated `external_id` returns the first receipt with `200`.\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrandSymptomLogInput"
              },
              "example": {
                "occurred_at": "2026-10-26T19:45:00Z",
                "symptom": "constipation",
                "severity": 3,
                "external_id": "sym-20931"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Already received; the first receipt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                  "external_id": "sym-20931",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T19:46:10Z",
                  "updated_at": "2026-10-26T19:46:10Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "201": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                  "external_id": "sym-20931",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T19:46:10Z",
                  "updated_at": "2026-10-26T19:46:10Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/injections": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        }
      ],
      "post": {
        "operationId": "createBrandInjectionLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Send an injection log",
        "description": "A dose taken or missed, as your app recorded it. A repeated `external_id` returns the first receipt with `200`.",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrandInjectionLogInput"
              },
              "example": {
                "injected_at": "2026-10-26T08:00:00Z",
                "scheduled_for": "2026-10-26",
                "dose_mg": 0.5,
                "site": "thigh_right",
                "external_id": "inj-88213"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Already received; the first receipt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-8091-72a3-9dc5-4e5f60718293",
                  "external_id": "inj-88213",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T08:01:30Z",
                  "updated_at": "2026-10-26T08:01:30Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "201": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-8091-72a3-9dc5-4e5f60718293",
                  "external_id": "inj-88213",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T08:01:30Z",
                  "updated_at": "2026-10-26T08:01:30Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/meals/{external_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        },
        {
          "$ref": "#/components/parameters/ExternalLogId"
        }
      ],
      "patch": {
        "operationId": "updateBrandMealLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Correct a meal log",
        "description": "Corrects a meal your server sent, found by your `external_id`. A log the patient made in the app can't be\nchanged here (`403 log_not_owned`). Returns the receipt with the new `updated_at`; the values stay with the care\nteam.\nError codes: `log_not_owned` (403), `upload_not_found`, `meal_plan_item_not_found` (422).\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/MealLogUpdate"
              },
              "example": {
                "protein_g": 30,
                "calories_kcal": 360
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Corrected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "external_id": "meal-77120",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T12:31:04Z",
                  "updated_at": "2026-10-26T13:02:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteBrandMealLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Delete a meal log",
        "description": "Deletes a meal your server sent, for example one recorded against the wrong patient. Deleting it again returns\n`204`. Its `external_id` stays taken: sending it again returns the deleted log's receipt, so use a new id for a\nreplacement.\nError code: `log_not_owned` (403).\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/workouts/{external_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        },
        {
          "$ref": "#/components/parameters/ExternalLogId"
        }
      ],
      "patch": {
        "operationId": "updateBrandWorkoutLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Correct a workout log",
        "description": "Corrects a workout your server sent, found by your `external_id`. A log the patient made in the app can't be\nchanged here (`403 log_not_owned`). Returns the receipt with the new `updated_at`; the values stay with the care\nteam.\nError codes: `log_not_owned` (403), `workout_plan_item_not_found` (422).\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/WorkoutLogUpdate"
              },
              "example": {
                "duration_min": 45
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Corrected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-6e7f-7081-9ba3-2c3d4e5f6071",
                  "external_id": "workout-5531",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T07:40:00Z",
                  "updated_at": "2026-10-26T08:10:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteBrandWorkoutLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Delete a workout log",
        "description": "Deletes a workout your server sent, for example one recorded against the wrong patient. Deleting it again returns\n`204`. Its `external_id` stays taken: sending it again returns the deleted log's receipt, so use a new id for a\nreplacement.\nError code: `log_not_owned` (403).\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/symptoms/{external_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        },
        {
          "$ref": "#/components/parameters/ExternalLogId"
        }
      ],
      "patch": {
        "operationId": "updateBrandSymptomLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Correct a symptom log",
        "description": "Corrects a symptom your server sent, found by your `external_id`. A log the patient made in the app can't be\nchanged here (`403 log_not_owned`). Returns the receipt with the new `updated_at`; the values stay with the care\nteam.\nEditing or deleting a symptom never closes a clinical flag or lowers the risk level; only the prescriber's resolve\ndoes. A correction that makes a symptom more severe runs the alert rules again, like a new log, so it can raise a\nflag. A flag raised by a symptom deleted later shows `deleted_at` on its triggering record.\nError codes: `log_not_owned` (403).\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/SymptomLogUpdate"
              },
              "example": {
                "severity": 3,
                "note": "Worse after dinner than I first logged"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Corrected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                  "external_id": "sym-20931",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T19:46:10Z",
                  "updated_at": "2026-10-26T20:30:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteBrandSymptomLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Delete a symptom log",
        "description": "Deletes a symptom your server sent, for example one recorded against the wrong patient. Deleting it again returns\n`204`. Its `external_id` stays taken: sending it again returns the deleted log's receipt, so use a new id for a\nreplacement.\nEditing or deleting a symptom never closes a clinical flag or lowers the risk level; only the prescriber's resolve\ndoes. A correction that makes a symptom more severe runs the alert rules again, like a new log, so it can raise a\nflag. A flag raised by a symptom deleted later shows `deleted_at` on its triggering record.\nError code: `log_not_owned` (403).\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/injections/{external_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        },
        {
          "$ref": "#/components/parameters/ExternalLogId"
        }
      ],
      "patch": {
        "operationId": "updateBrandInjectionLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Correct an injection log",
        "description": "Corrects an injection your server sent, found by your `external_id`. A log the patient made in the app can't be\nchanged here (`403 log_not_owned`). Returns the receipt with the new `updated_at`; the values stay with the care\nteam.\nChanging a missed dose to taken (or back) does not close an alert already raised for it.\nError codes: `log_not_owned` (403), `injection_incomplete` (422) when the result is neither taken nor missed.\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/InjectionLogUpdate"
              },
              "example": {
                "missed": false,
                "injected_at": "2026-10-26T08:00:00Z",
                "dose_mg": 0.5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Corrected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogReceipt"
                },
                "example": {
                  "id": "0190f5c9-8091-72a3-9dc5-4e5f60718293",
                  "external_id": "inj-88213",
                  "log_date": "2026-10-26",
                  "created_at": "2026-10-26T08:01:30Z",
                  "updated_at": "2026-10-26T09:15:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteBrandInjectionLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Delete an injection log",
        "description": "Deletes an injection your server sent, for example one recorded against the wrong patient. Deleting it again returns\n`204`. Its `external_id` stays taken: sending it again returns the deleted log's receipt, so use a new id for a\nreplacement.\nChanging a missed dose to taken (or back) does not close an alert already raised for it.\nError code: `log_not_owned` (403).\n",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/enrollments/{enrollment_id}/daily-logs/{log_date}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EnrollmentId"
        },
        {
          "$ref": "#/components/parameters/LogDate"
        }
      ],
      "patch": {
        "operationId": "updateBrandDailyLog",
        "tags": [
          "Brand logs"
        ],
        "summary": "Send daily values",
        "description": "Weight, body measures, water, steps, sleep and other daily values your app recorded. Only the fields sent change.",
        "security": [
          {
            "brandServer": [
              "logs:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/DailyLogInput"
              },
              "example": {
                "weight_kg": 94.8,
                "steps": 7400
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyLogReceipt"
                },
                "example": {
                  "log_date": "2026-10-26",
                  "updated_at": "2026-10-26T14:05:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "operationId": "listEvents",
        "tags": [
          "Events"
        ],
        "summary": "Replay events",
        "description": "The same events as the webhooks, oldest first, for the last 30 days. After an outage, pass the id of the last\nevent you processed as `since`, then follow `next_cursor` until it is `null`. Every event appears exactly once,\nin order; events outside the 30-day window are gone.\nError code: `event_too_old` (410) when `since` is older than 30 days.\n",
        "security": [
          {
            "brandServer": [
              "events:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "description": "Start after this event id (exclusive). Omit to start at the oldest event kept.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7"
          },
          {
            "name": "type",
            "in": "query",
            "description": "Only these event types, comma-separated.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/EventType"
              }
            },
            "example": [
              "clinical.flag_raised",
              "clinical.flag_redelivered"
            ]
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of events.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7",
                      "type": "clinical.flag_raised",
                      "created_at": "2026-10-26T14:05:00Z",
                      "tenant_id": "a0000000-0000-4000-8000-000000000002",
                      "data": {
                        "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                        "external_patient_id": "brand-pt-48213",
                        "flag_id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                        "severity": "critical",
                        "raised_risk_to": "high",
                        "ack_due_at": "2026-10-26T16:05:00Z"
                      }
                    },
                    {
                      "id": "0190f5e1-0a1b-7c2d-9e3f-4a5b6c7d8e9f",
                      "type": "clinical.flag_acknowledged",
                      "created_at": "2026-10-26T14:20:00Z",
                      "tenant_id": "a0000000-0000-4000-8000-000000000002",
                      "data": {
                        "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                        "external_patient_id": "brand-pt-48213",
                        "flag_id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                        "acknowledged_at": "2026-10-26T14:20:00Z"
                      }
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "410": {
            "$ref": "#/components/responses/Gone"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/events/{event_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EventId"
        }
      ],
      "get": {
        "operationId": "getEvent",
        "tags": [
          "Events"
        ],
        "summary": "Get an event",
        "description": "One event by id, within the 30-day window.",
        "security": [
          {
            "brandServer": [
              "events:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The event.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Event"
                },
                "example": {
                  "id": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7",
                  "type": "clinical.flag_raised",
                  "created_at": "2026-10-26T14:05:00Z",
                  "tenant_id": "a0000000-0000-4000-8000-000000000002",
                  "data": {
                    "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                    "external_patient_id": "brand-pt-48213",
                    "flag_id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                    "severity": "critical",
                    "raised_risk_to": "high",
                    "ack_due_at": "2026-10-26T16:05:00Z"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/reports/brand": {
      "get": {
        "operationId": "getBrandReport",
        "tags": [
          "Reports"
        ],
        "summary": "Get the brand report",
        "description": "Enrollment counts, engagement and outcomes for a period, in total and per plan. Aggregates only, never\npatient-level values; any metric whose group has fewer than 10 patients is `null`. Ask for\n`Accept: application/pdf` for the same report as a PDF. Periods can be up to 366 days.\nError code: `period_too_long` (422).\n",
        "security": [
          {
            "brandServer": [
              "reports:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          },
          {
            "name": "plan_code",
            "in": "query",
            "description": "Only this plan.",
            "schema": {
              "$ref": "#/components/schemas/PlanCode"
            },
            "example": "ai_only"
          }
        ],
        "responses": {
          "200": {
            "description": "The report.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandReport"
                },
                "example": {
                  "period": {
                    "from": "2026-10-01",
                    "to": "2026-10-31"
                  },
                  "generated_at": "2026-11-01T06:00:00Z",
                  "min_group_size": 10,
                  "totals": {
                    "active_enrollments": 214,
                    "new_enrollments": 61,
                    "cancelled_enrollments": 12,
                    "engaged_last_7_days": 168,
                    "median_weight_change_kg": -4.6,
                    "protein_target_days_pct": 0.57,
                    "flags_raised": 18,
                    "flags_acknowledged_on_time_pct": 0.94,
                    "ai_coach_thumbs_up_pct": 0.88,
                    "retention_90_day_pct": null,
                    "median_hours_to_first_protocol": 26.5
                  },
                  "plans": [
                    {
                      "plan_code": "ai_health_fitness",
                      "metrics": {
                        "active_enrollments": 131,
                        "new_enrollments": 35,
                        "cancelled_enrollments": null,
                        "engaged_last_7_days": 109,
                        "median_weight_change_kg": -5.1,
                        "protein_target_days_pct": 0.63,
                        "flags_raised": 11,
                        "flags_acknowledged_on_time_pct": 1,
                        "ai_coach_thumbs_up_pct": 0.9,
                        "retention_90_day_pct": null,
                        "median_hours_to_first_protocol": 31
                      }
                    },
                    {
                      "plan_code": "ai_only",
                      "metrics": {
                        "active_enrollments": 83,
                        "new_enrollments": 26,
                        "cancelled_enrollments": null,
                        "engaged_last_7_days": 59,
                        "median_weight_change_kg": -3.8,
                        "protein_target_days_pct": 0.48,
                        "flags_raised": null,
                        "flags_acknowledged_on_time_pct": null,
                        "ai_coach_thumbs_up_pct": 0.86,
                        "retention_90_day_pct": null,
                        "median_hours_to_first_protocol": 0.1
                      }
                    }
                  ]
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/pdf"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/data-requests": {
      "post": {
        "operationId": "createDataRequest",
        "tags": [
          "Data requests"
        ],
        "summary": "Create a data request",
        "description": "A patient's request, made through you, to export, delete or amend their coaching records. Requests are\nprocessed in the background; `data_request.completed` fires when done.\nError codes: `data_request_in_progress` (409) for a second open request of the same kind, `validation_failed` (422).\n",
        "security": [
          {
            "brandServer": [
              "data_requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DataRequestCreate"
              },
              "examples": {
                "export": {
                  "summary": "Export",
                  "value": {
                    "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                    "kind": "export"
                  }
                },
                "amend": {
                  "summary": "Amendment",
                  "value": {
                    "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                    "kind": "amend",
                    "details": {
                      "record_type": "symptom_log",
                      "record_id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                      "description": "The severity was logged as 5 by mistake.",
                      "requested_change": "Severity should be 2."
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataRequest"
                },
                "example": {
                  "id": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13",
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "kind": "export",
                  "status": "received",
                  "requested_at": "2026-10-26T14:05:00Z",
                  "completed_at": null,
                  "export": null,
                  "amendment": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "listDataRequests",
        "tags": [
          "Data requests"
        ],
        "summary": "List data requests",
        "description": "Your brand's data requests, newest first.",
        "security": [
          {
            "brandServer": [
              "data_requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/DataRequestStatus"
            },
            "example": "processing"
          },
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/DataRequestKind"
            },
            "example": "amend"
          },
          {
            "name": "enrollment_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of data requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataRequestList"
                },
                "example": {
                  "data": [
                    {
                      "id": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13",
                      "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                      "external_patient_id": "brand-pt-48213",
                      "kind": "amend",
                      "status": "processing",
                      "requested_at": "2026-10-26T14:05:00Z",
                      "completed_at": null,
                      "export": null,
                      "amendment": {
                        "details": {
                          "record_type": "symptom_log",
                          "record_id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                          "description": "The severity was logged as 5 by mistake.",
                          "requested_change": "Severity should be 2."
                        },
                        "respond_by": "2026-12-25T14:05:00Z",
                        "decision": null,
                        "decision_note": null,
                        "decided_at": null
                      }
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/data-requests/{data_request_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DataRequestId"
        }
      ],
      "get": {
        "operationId": "getDataRequest",
        "tags": [
          "Data requests"
        ],
        "summary": "Get a data request",
        "description": "Status, and for exports whether the download is ready.",
        "security": [
          {
            "brandServer": [
              "data_requests:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The data request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataRequest"
                },
                "example": {
                  "id": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13",
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "kind": "export",
                  "status": "completed",
                  "requested_at": "2026-10-26T14:05:00Z",
                  "completed_at": "2026-10-26T14:40:00Z",
                  "export": {
                    "available": true,
                    "expires_at": "2026-11-02T14:40:00Z"
                  },
                  "amendment": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/data-requests/{data_request_id}/export-link": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DataRequestId"
        }
      ],
      "post": {
        "operationId": "createDataRequestExportLink",
        "tags": [
          "Data requests"
        ],
        "summary": "Get a download link",
        "description": "A short-lived link to the export file. Ask for a new link each time you download; the file itself stays until\n`export.expires_at`. Error codes: `export_not_ready` (409), `export_expired` (410).\n",
        "security": [
          {
            "brandServer": [
              "data_requests:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportLink"
                },
                "example": {
                  "url": "https://exports.example.com/7a2e4c61?signature=example",
                  "expires_at": "2026-10-26T14:50:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "410": {
            "$ref": "#/components/responses/Gone"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/data-requests/{data_request_id}/decision": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DataRequestId"
        }
      ],
      "post": {
        "operationId": "decideDataRequest",
        "tags": [
          "Data requests"
        ],
        "summary": "Decide an amendment",
        "description": "Accept or deny an `amend` request within 60 days of `requested_at`. A denial needs `decision_note` (HIPAA requires\nthe reason). Accepting applies the change and records the previous value in the record history.\nError codes: `not_an_amend_request`, `already_decided` (409).\n",
        "security": [
          {
            "brandServer": [
              "data_requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AmendDecision"
              },
              "examples": {
                "accepted": {
                  "summary": "Accept",
                  "value": {
                    "decision": "accepted",
                    "decision_note": "Corrected the severity to 2."
                  }
                },
                "denied": {
                  "summary": "Deny",
                  "value": {
                    "decision": "denied",
                    "decision_note": "The record is accurate as reported by the patient at the time."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The decided request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataRequest"
                },
                "example": {
                  "id": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13",
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "kind": "amend",
                  "status": "completed",
                  "requested_at": "2026-10-26T14:05:00Z",
                  "completed_at": "2026-10-28T10:00:00Z",
                  "export": null,
                  "amendment": {
                    "details": {
                      "record_type": "symptom_log",
                      "record_id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                      "description": "The severity was logged as 5 by mistake.",
                      "requested_change": "Severity should be 2."
                    },
                    "respond_by": "2026-12-25T14:05:00Z",
                    "decision": "accepted",
                    "decision_note": "Corrected the severity to 2.",
                    "decided_at": "2026-10-28T10:00:00Z"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient": {
      "get": {
        "operationId": "getMyProfile",
        "tags": [
          "Patient"
        ],
        "summary": "Get my profile",
        "description": "The patient's profile, plan, care team and brand details. Call it first after the token exchange.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The patient.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PatientProfile"
                },
                "example": {
                  "patient": {
                    "first_name": "Jordan",
                    "last_name": "Rivera",
                    "email": "jordan.rivera@example.com",
                    "phone": "+12025550143",
                    "date_of_birth": "1986-04-12",
                    "sex": "female",
                    "height_cm": 165.1,
                    "state_code": "NY",
                    "timezone": "America/New_York",
                    "language": "en",
                    "units": "imperial",
                    "conditions": [
                      "prediabetes"
                    ],
                    "health_profile": {
                      "goal_weight_kg": 72.5,
                      "activity_level": "lightly_active",
                      "food_allergies": [
                        "peanuts"
                      ],
                      "dietary_restrictions": [
                        "dairy_free"
                      ],
                      "food_dislikes": [
                        "mushrooms"
                      ],
                      "cooking": {
                        "skill": "beginner",
                        "appliances": [
                          "stove_range",
                          "microwave",
                          "air_fryer"
                        ],
                        "meal_preparer": "mostly_myself"
                      },
                      "lifestyle": {
                        "sleep_hours": 6.5,
                        "alcohol": "occasional",
                        "smoking": "never"
                      }
                    }
                  },
                  "enrollment": {
                    "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                    "plan_code": "ai_health_fitness",
                    "status": "active",
                    "stage": "protocols_active",
                    "data_sharing": true
                  },
                  "care_team": [
                    {
                      "care_role": "health_coach",
                      "display_name": "Maya C.",
                      "title": "Health Coach",
                      "credentials": [
                        "RD",
                        "NBC-HWC"
                      ],
                      "assigned_at": "2026-10-21T15:10:00Z"
                    }
                  ],
                  "brand": {
                    "display_name": "Demo Brand",
                    "primary_color": "#1A5F7A",
                    "support": {
                      "email": "support@example.com",
                      "phone": "+12025550100",
                      "url": "https://help.example.com"
                    }
                  },
                  "legal_documents_pending": 0
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "patch": {
        "operationId": "updateMyProfile",
        "tags": [
          "Patient"
        ],
        "summary": "Update my profile",
        "description": "Height; the health profile (activity level, food allergies, dietary restrictions, food dislikes, cooking and\nlifestyle); time zone, language, display units and data sharing. Changes apply to plans and AI Coach replies\ngenerated after them. Turning `data_sharing` off is recorded on the enrollment history and takes effect\nimmediately for the care team.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatientProfileUpdate"
              },
              "example": {
                "height_cm": 167.6,
                "units": "metric",
                "health_profile": {
                  "dietary_restrictions": [
                    "dairy_free",
                    "gluten_free"
                  ],
                  "cooking": {
                    "skill": "intermediate"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PatientProfile"
                },
                "example": {
                  "patient": {
                    "first_name": "Jordan",
                    "last_name": "Rivera",
                    "email": "jordan.rivera@example.com",
                    "phone": "+12025550143",
                    "date_of_birth": "1986-04-12",
                    "sex": "female",
                    "height_cm": 167.6,
                    "state_code": "NY",
                    "timezone": "America/New_York",
                    "language": "en",
                    "units": "metric",
                    "conditions": [
                      "prediabetes"
                    ],
                    "health_profile": {
                      "goal_weight_kg": 72.5,
                      "activity_level": "lightly_active",
                      "food_allergies": [
                        "peanuts"
                      ],
                      "dietary_restrictions": [
                        "dairy_free",
                        "gluten_free"
                      ],
                      "food_dislikes": [
                        "mushrooms"
                      ],
                      "cooking": {
                        "skill": "intermediate",
                        "appliances": [
                          "stove_range",
                          "microwave",
                          "air_fryer"
                        ],
                        "meal_preparer": "mostly_myself"
                      },
                      "lifestyle": {
                        "sleep_hours": 6.5,
                        "alcohol": "occasional",
                        "smoking": "never"
                      }
                    }
                  },
                  "enrollment": {
                    "id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                    "plan_code": "ai_health_fitness",
                    "status": "active",
                    "stage": "protocols_active",
                    "data_sharing": true
                  },
                  "care_team": [
                    {
                      "care_role": "health_coach",
                      "display_name": "Maya C.",
                      "title": "Health Coach",
                      "credentials": [
                        "RD",
                        "NBC-HWC"
                      ],
                      "assigned_at": "2026-10-21T15:10:00Z"
                    }
                  ],
                  "brand": {
                    "display_name": "Demo Brand",
                    "primary_color": "#1A5F7A",
                    "support": {
                      "email": "support@example.com",
                      "phone": "+12025550100",
                      "url": "https://help.example.com"
                    }
                  },
                  "legal_documents_pending": 0
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/treatment": {
      "get": {
        "operationId": "getMyTreatment",
        "tags": [
          "Patient"
        ],
        "summary": "Get my treatment",
        "description": "The current GLP-1 medication, dose and treatment week. Error code `treatment_not_found` (404) before one is set.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The current treatment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PatientTreatment"
                },
                "example": {
                  "medication": {
                    "ingredient": "semaglutide",
                    "product_name": "Wegovy",
                    "source": "branded",
                    "route": "injection"
                  },
                  "dose_mg": 0.5,
                  "dose_amount": null,
                  "dose_unit": null,
                  "phase": "titration",
                  "injection_weekday": 1,
                  "started_on": "2026-09-28",
                  "treatment_week": 5,
                  "effective_from": "2026-10-26T00:00:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/treatments": {
      "post": {
        "operationId": "reportMyTreatment",
        "tags": [
          "Patient"
        ],
        "summary": "Report my treatment (TeraRx Direct)",
        "description": "Direct patients self-report the GLP-1 they take. Brand patients' treatment comes from the brand's prescriber,\nso this returns `403 treatment_managed_by_brand` for them.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SelfReportedTreatment"
              },
              "example": {
                "medication_id": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f",
                "dose_mg": 0.5,
                "phase": "titration",
                "injection_weekday": 1,
                "started_on": "2026-09-28"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The reported treatment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PatientTreatment"
                },
                "example": {
                  "medication": {
                    "ingredient": "semaglutide",
                    "product_name": "Wegovy",
                    "source": "branded",
                    "route": "injection"
                  },
                  "dose_mg": 0.5,
                  "dose_amount": null,
                  "dose_unit": null,
                  "phase": "titration",
                  "injection_weekday": 1,
                  "started_on": "2026-09-28",
                  "treatment_week": 5,
                  "effective_from": "2026-10-26T14:05:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/legal-documents": {
      "get": {
        "operationId": "listMyLegalDocuments",
        "tags": [
          "Patient"
        ],
        "summary": "List my legal documents",
        "description": "The current version of every document that applies to the patient, with whether they accepted it.\nOn first open, ask for acceptance of each one with `required_on_first_open` and no `accepted_at`\nbefore showing coaching screens.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "Legal documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegalDocumentList"
                },
                "example": {
                  "data": [
                    {
                      "id": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f",
                      "code": "coaching_consent",
                      "version": "2026-01",
                      "url": "https://legal.example.com/coaching-consent/2026-01",
                      "required_on_first_open": true,
                      "effective_at": "2026-01-01T00:00:00Z",
                      "accepted_at": "2026-10-21T14:57:30Z"
                    },
                    {
                      "id": "4f6a8c0e-2b1d-4e3f-8a5b-9c1d3e5f7a9b",
                      "code": "privacy",
                      "version": "2026-01",
                      "url": "https://legal.example.com/privacy/2026-01",
                      "required_on_first_open": true,
                      "effective_at": "2026-01-01T00:00:00Z",
                      "accepted_at": null
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/consents": {
      "post": {
        "operationId": "acceptLegalDocument",
        "tags": [
          "Patient"
        ],
        "summary": "Accept a legal document",
        "description": "Records the patient's acceptance in the app. Accepting a document already accepted returns the existing\nrecord with `200`. Error code: `unknown_legal_document` (422).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsentAccept"
              },
              "example": {
                "legal_document_id": "4f6a8c0e-2b1d-4e3f-8a5b-9c1d3e5f7a9b"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Already accepted; the existing record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsentRecord"
                },
                "example": {
                  "id": "0190f5c8-3c4d-7e5f-9a61-7b8c9d0e1f2a",
                  "document_code": "privacy",
                  "document_version": "2026-01",
                  "accepted_at": "2026-10-22T09:05:12Z",
                  "withdrawn_at": null,
                  "source": "brand_app"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "201": {
            "description": "Accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsentRecord"
                },
                "example": {
                  "id": "0190f5c8-3c4d-7e5f-9a61-7b8c9d0e1f2a",
                  "document_code": "privacy",
                  "document_version": "2026-01",
                  "accepted_at": "2026-10-22T09:05:12Z",
                  "withdrawn_at": null,
                  "source": "brand_app"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/forms": {
      "get": {
        "operationId": "listMyForms",
        "tags": [
          "Forms"
        ],
        "summary": "List my forms",
        "description": "Forms sent to the patient, newest first. By default only open ones (`sent`, `in_progress`).\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filter by one or more statuses, comma-separated.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/FormAssignmentStatus"
              },
              "default": [
                "sent",
                "in_progress"
              ]
            },
            "example": [
              "sent",
              "in_progress"
            ]
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of form assignments.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormAssignmentList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2",
                      "form": {
                        "code": "glp1_onboarding",
                        "version": 1,
                        "purpose": "onboarding",
                        "title": "Coaching Onboarding"
                      },
                      "status": "sent",
                      "blocks_onboarding": true,
                      "due_at": "2026-10-24T15:00:00Z",
                      "sent_at": "2026-10-21T15:00:00Z",
                      "completed_at": null
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/forms/{form_assignment_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/FormAssignmentId"
        }
      ],
      "get": {
        "operationId": "getMyForm",
        "tags": [
          "Forms"
        ],
        "summary": "Get a form",
        "description": "The form's fields at the version it was sent with, the prefill from the brand's intake and any saved draft.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The form assignment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormAssignment"
                },
                "example": {
                  "id": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2",
                  "form": {
                    "code": "glp1_onboarding",
                    "version": 1,
                    "purpose": "onboarding",
                    "title": "Coaching Onboarding"
                  },
                  "status": "in_progress",
                  "blocks_onboarding": true,
                  "due_at": "2026-10-24T15:00:00Z",
                  "sent_at": "2026-10-21T15:00:00Z",
                  "completed_at": null,
                  "fields": [
                    {
                      "id": "weight_kg",
                      "type": "number",
                      "label": "Current weight",
                      "unit": "kg",
                      "required": true
                    },
                    {
                      "id": "primary_goal",
                      "type": "select",
                      "label": "Primary goal",
                      "options": [
                        "lose_weight",
                        "preserve_muscle",
                        "manage_side_effects",
                        "build_habits"
                      ],
                      "required": true
                    }
                  ],
                  "prefill": {
                    "weight_kg": 96.2
                  },
                  "draft_answers": {
                    "primary_goal": "preserve_muscle"
                  },
                  "answers": null,
                  "result": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/forms/{form_assignment_id}/draft": {
      "parameters": [
        {
          "$ref": "#/components/parameters/FormAssignmentId"
        }
      ],
      "put": {
        "operationId": "saveMyFormDraft",
        "tags": [
          "Forms"
        ],
        "summary": "Save a draft",
        "description": "Saves partial answers so the patient can finish later; the status becomes `in_progress`.\nEach call replaces the previous draft. Error code: `form_not_open` (409) once completed, expired or cancelled.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormAnswersInput"
              },
              "example": {
                "answers": {
                  "primary_goal": "preserve_muscle"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The form assignment with the saved draft.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormAssignment"
                },
                "example": {
                  "id": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2",
                  "form": {
                    "code": "glp1_onboarding",
                    "version": 1,
                    "purpose": "onboarding",
                    "title": "Coaching Onboarding"
                  },
                  "status": "in_progress",
                  "blocks_onboarding": true,
                  "due_at": "2026-10-24T15:00:00Z",
                  "sent_at": "2026-10-21T15:00:00Z",
                  "completed_at": null,
                  "fields": [
                    {
                      "id": "weight_kg",
                      "type": "number",
                      "label": "Current weight",
                      "unit": "kg",
                      "required": true
                    },
                    {
                      "id": "primary_goal",
                      "type": "select",
                      "label": "Primary goal",
                      "options": [
                        "lose_weight",
                        "preserve_muscle",
                        "manage_side_effects",
                        "build_habits"
                      ],
                      "required": true
                    }
                  ],
                  "prefill": {
                    "weight_kg": 96.2
                  },
                  "draft_answers": {
                    "primary_goal": "preserve_muscle"
                  },
                  "answers": null,
                  "result": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/forms/{form_assignment_id}/submit": {
      "parameters": [
        {
          "$ref": "#/components/parameters/FormAssignmentId"
        }
      ],
      "post": {
        "operationId": "submitMyForm",
        "tags": [
          "Forms"
        ],
        "summary": "Submit a form",
        "description": "Validates every answer against the fields (required, type, options, range) and completes the form.\nWhen the last blocking form is completed the enrollment moves to `onboarding_completed`\n(`onboarding.completed`). Answers to health profile questions (allergies, dietary restrictions, activity level,\ncooking, lifestyle and so on) update the patient's profile, readable with `GET /v1/patient`. An eligibility\nform returns its `result`.\nError codes: `validation_failed` (422, with a pointer per field such as `/answers/weight_kg`), `form_not_open` (409).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormAnswersInput"
              },
              "example": {
                "answers": {
                  "weight_kg": 96.2,
                  "primary_goal": "preserve_muscle"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The completed form.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormAssignment"
                },
                "example": {
                  "id": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2",
                  "form": {
                    "code": "glp1_onboarding",
                    "version": 1,
                    "purpose": "onboarding",
                    "title": "Coaching Onboarding"
                  },
                  "status": "completed",
                  "blocks_onboarding": true,
                  "due_at": "2026-10-24T15:00:00Z",
                  "sent_at": "2026-10-21T15:00:00Z",
                  "completed_at": "2026-10-22T09:30:00Z",
                  "fields": [
                    {
                      "id": "weight_kg",
                      "type": "number",
                      "label": "Current weight",
                      "unit": "kg",
                      "required": true
                    },
                    {
                      "id": "primary_goal",
                      "type": "select",
                      "label": "Primary goal",
                      "options": [
                        "lose_weight",
                        "preserve_muscle",
                        "manage_side_effects",
                        "build_habits"
                      ],
                      "required": true
                    }
                  ],
                  "prefill": {
                    "weight_kg": 96.2
                  },
                  "draft_answers": null,
                  "answers": {
                    "weight_kg": 96.2,
                    "primary_goal": "preserve_muscle"
                  },
                  "result": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/daily-logs": {
      "get": {
        "operationId": "listMyDailyLogs",
        "tags": [
          "Logging"
        ],
        "summary": "List my daily logs",
        "description": "One row per day with the patient's daily values and the rollups from meals, workouts and symptoms.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FromDate"
          },
          {
            "$ref": "#/components/parameters/ToDate"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Daily logs, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyLogList"
                },
                "example": {
                  "data": [
                    {
                      "log_date": "2026-10-26",
                      "water_ml": 1800,
                      "weight_kg": 94.8,
                      "waist_cm": null,
                      "hip_cm": null,
                      "body_fat_pct": null,
                      "steps": 7400,
                      "sleep_minutes": 430,
                      "sleep_quality": 4,
                      "mood": 4,
                      "stress": 2,
                      "energy": 3,
                      "habits_done": {
                        "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90:protein_each_meal": true
                      },
                      "metrics": {},
                      "protein_g": 92.5,
                      "calories_kcal": 1450,
                      "fiber_g": 21,
                      "workout_minutes": 35,
                      "max_symptom_severity": 2,
                      "sources": [
                        "brand_app"
                      ],
                      "updated_at": "2026-10-26T20:15:00Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/daily-logs/{log_date}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/LogDate"
        }
      ],
      "patch": {
        "operationId": "updateMyDailyLog",
        "tags": [
          "Logging"
        ],
        "summary": "Log daily values",
        "description": "Water, weight and body measures, steps, sleep, mood, stress, energy, habit check-offs and any other metric for\none day. Only the fields sent change. Dates more than 30 days back or in the future are refused\n(`log_date_out_of_range`, 422).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/DailyLogInput"
              },
              "example": {
                "water_ml": 1800,
                "weight_kg": 94.8,
                "mood": 4,
                "habits_done": {
                  "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90:protein_each_meal": true
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The day after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyLog"
                },
                "example": {
                  "log_date": "2026-10-26",
                  "water_ml": 1800,
                  "weight_kg": 94.8,
                  "waist_cm": null,
                  "hip_cm": null,
                  "body_fat_pct": null,
                  "steps": null,
                  "sleep_minutes": null,
                  "sleep_quality": null,
                  "mood": 4,
                  "stress": null,
                  "energy": null,
                  "habits_done": {
                    "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90:protein_each_meal": true
                  },
                  "metrics": {},
                  "protein_g": 48,
                  "calories_kcal": 720,
                  "fiber_g": 9,
                  "workout_minutes": null,
                  "max_symptom_severity": null,
                  "sources": [
                    "brand_app"
                  ],
                  "updated_at": "2026-10-26T14:05:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/today": {
      "get": {
        "operationId": "getMyToday",
        "tags": [
          "Progress"
        ],
        "summary": "Get today",
        "description": "What the home screen needs for the patient's today, in their time zone: targets against what's logged so far,\nthe plan's meals and workouts for the day, habits, the next reminder, recent milestones, and counts of open\nforms, unread care messages and legal documents to accept.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "Today.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Today"
                },
                "example": {
                  "date": "2026-10-27",
                  "treatment_week": 6,
                  "injection": {
                    "due_today": true,
                    "logged": false
                  },
                  "targets": [
                    {
                      "metric": "protein_g",
                      "label": "Protein",
                      "unit": "g",
                      "target": 110,
                      "progress": 72
                    },
                    {
                      "metric": "water_ml",
                      "label": "Water",
                      "unit": "ml",
                      "target": 2500,
                      "progress": 1250
                    }
                  ],
                  "meals": [
                    {
                      "meal_plan_item_id": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01",
                      "meal_type": "breakfast",
                      "title": "Greek yogurt protein bowl",
                      "recipe_id": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f",
                      "protein_g": 31,
                      "calories_kcal": 320,
                      "logged": true
                    },
                    {
                      "meal_plan_item_id": "5e3a0b42-7d9c-4f1e-8a83-2c4e6f8a0b13",
                      "meal_type": "lunch",
                      "title": "Chicken and quinoa bowl",
                      "recipe_id": null,
                      "protein_g": 38,
                      "calories_kcal": 450,
                      "logged": false
                    }
                  ],
                  "workouts": [
                    {
                      "workout_plan_item_id": "4d2f9a31-6c8b-4e0d-9f72-1b3c5d7e9f02",
                      "title": "Full-body strength A",
                      "duration_min": 30,
                      "logged": false
                    }
                  ],
                  "habits": [
                    {
                      "protocol_id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                      "key": "protein_each_meal",
                      "title": "Protein at every meal",
                      "done": false
                    }
                  ],
                  "next_reminder": {
                    "id": "0190f5c5-4a5b-7c61-8d78-9e0f1a2b3c45",
                    "kind": "injection",
                    "ref_key": null,
                    "due_at": "2026-10-27T13:00:00Z",
                    "status": "scheduled",
                    "recurring": true
                  },
                  "open_forms": 1,
                  "unread_care_messages": 2,
                  "legal_documents_pending": 0,
                  "new_milestones": []
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/targets": {
      "get": {
        "operationId": "getMyTargets",
        "tags": [
          "Progress"
        ],
        "summary": "Get targets and progress for a day",
        "description": "The targets from the protocols in force on `date`, with what that day's logs add up to. Metric codes are the\nprotocol targets' codes, so a new metric needs no app change to show. Error code: `date_out_of_range` (422) for\na day before the enrollment or in the future.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "description": "A day in the patient's time zone. Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-27"
          }
        ],
        "responses": {
          "200": {
            "description": "The day's targets and progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DayTargets"
                },
                "example": {
                  "date": "2026-10-27",
                  "targets": [
                    {
                      "metric": "protein_g",
                      "label": "Protein",
                      "unit": "g",
                      "target": 110,
                      "progress": 72
                    },
                    {
                      "metric": "water_ml",
                      "label": "Water",
                      "unit": "ml",
                      "target": 2500,
                      "progress": 1250
                    },
                    {
                      "metric": "fiber_g",
                      "label": "Fiber",
                      "unit": "g",
                      "target": 25,
                      "progress": 11
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/week-stats": {
      "get": {
        "operationId": "getMyWeekStats",
        "tags": [
          "Progress"
        ],
        "summary": "Get a week's stats",
        "description": "A summary of one week of treatment, numbered like `treatment_week` on `GET /v1/patient/treatment`: week 1\nstarts on the treatment's `started_on`. Defaults to the current week, counted up to today. Error code:\n`week_not_available` (404) for a week before the enrollment, after the current one, or before a treatment is set.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "name": "week_number",
            "in": "query",
            "description": "Omit for the current week.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 520
            },
            "example": 6
          }
        ],
        "responses": {
          "200": {
            "description": "The week.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WeekStats"
                },
                "example": {
                  "week_number": 6,
                  "start_date": "2026-10-21",
                  "end_date": "2026-10-27",
                  "days_logged": 5,
                  "logging_streak_days": 12,
                  "protein": {
                    "target_g": 110,
                    "avg_g": 96,
                    "days_at_target": 4
                  },
                  "calories_avg_kcal": 1480,
                  "water": {
                    "target_ml": 2500,
                    "avg_ml": 2100,
                    "days_at_target": 3
                  },
                  "workouts": {
                    "count": 3,
                    "minutes": 95
                  },
                  "steps_avg": 7400,
                  "weight": {
                    "start_kg": 96.4,
                    "end_kg": 95.6,
                    "change_kg": -0.8
                  },
                  "injections": {
                    "taken": 1,
                    "missed": 0
                  },
                  "symptoms": {
                    "days": 2,
                    "max_severity": 2
                  },
                  "milestones": [
                    {
                      "id": "0190f5e1-2a3b-7c4d-9e5f-6a7b8c9d0e1f",
                      "code": "protein_target_days_7",
                      "category": "nutrition",
                      "title": "7 days at your protein target",
                      "message": "You averaged 112 g a day, up from 74 g in your first week.",
                      "achieved_at": "2026-10-25T20:10:00Z",
                      "stats": {
                        "days": 7,
                        "avg_protein_g": 112,
                        "first_week_avg_protein_g": 74
                      }
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/milestones": {
      "get": {
        "operationId": "listMyMilestones",
        "tags": [
          "Progress"
        ],
        "summary": "List my milestones",
        "description": "Every milestone the patient reached in this enrollment, newest first. Your server hears about a new one from\n`patient.milestone_reached`, so the app can celebrate it.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The patient's milestones.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MilestoneList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5e1-2a3b-7c4d-9e5f-6a7b8c9d0e1f",
                      "code": "protein_target_days_7",
                      "category": "nutrition",
                      "title": "7 days at your protein target",
                      "message": "You averaged 112 g a day, up from 74 g in your first week.",
                      "achieved_at": "2026-10-25T20:10:00Z",
                      "stats": {
                        "days": 7,
                        "avg_protein_g": 112,
                        "first_week_avg_protein_g": 74
                      }
                    },
                    {
                      "id": "0190f5d9-1f2a-7b3c-8d4e-5f6a7b8c9d0e",
                      "code": "logging_streak_7",
                      "category": "logging",
                      "title": "7 days of logging in a row",
                      "message": "A full week of logging. That's what makes your plan work.",
                      "achieved_at": "2026-10-22T19:30:00Z",
                      "stats": {
                        "days": 7
                      }
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/milestones/{milestone_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MilestoneId"
        }
      ],
      "get": {
        "operationId": "getMyMilestone",
        "tags": [
          "Progress"
        ],
        "summary": "Get a milestone",
        "description": "The milestone with the patient's own numbers, for a celebration screen after `patient.milestone_reached`.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The milestone.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Milestone"
                },
                "example": {
                  "id": "0190f5e1-2a3b-7c4d-9e5f-6a7b8c9d0e1f",
                  "code": "weight_loss_5_pct",
                  "category": "weight",
                  "title": "5% of your starting weight",
                  "message": "You're down 5.1 kg since your first weigh-in. Keep the protein up to protect your muscle.",
                  "achieved_at": "2026-10-25T08:05:00Z",
                  "stats": {
                    "start_weight_kg": 100.7,
                    "current_weight_kg": 95.6,
                    "change_pct": -5.1
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/meal-photos": {
      "post": {
        "operationId": "createMealPhotoUpload",
        "tags": [
          "Logging"
        ],
        "summary": "Start a meal photo upload",
        "description": "Returns a pre-signed URL. Upload the photo there, then send `upload_id` as `photo_upload_id` on the meal log.\nAn upload not attached to a meal within 1 hour is deleted.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealPhotoUploadRequest"
              },
              "example": {
                "content_type": "image/jpeg",
                "content_length": 1843200
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Upload ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealPhotoUpload"
                },
                "example": {
                  "upload_id": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e",
                  "upload_url": "https://uploads.example.com/meal-photos/8e2c4a60?signature=example",
                  "method": "PUT",
                  "headers": {
                    "Content-Type": "image/jpeg"
                  },
                  "expires_at": "2026-10-26T14:15:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/meal-photos/{upload_id}/analysis": {
      "parameters": [
        {
          "$ref": "#/components/parameters/UploadId"
        }
      ],
      "post": {
        "operationId": "analyzeMealPhoto",
        "tags": [
          "Logging"
        ],
        "summary": "Analyze a meal photo",
        "description": "The AI Coach estimates the meal in an uploaded photo: what it is, its ingredients and their macros. Show the\nresult as an editable form, then save it with `POST /v1/patient/meals`, sending the same `photo_upload_id` and\n`entry_method: photo_ai`. Takes a few seconds. Asking again for the same upload returns the same analysis.\nCounts toward the plan's daily photo analysis limit (15 by default). Error codes: `upload_not_found` (404),\n`ai_paused` (409) when the AI Coach is paused for the plan, `daily_photo_analysis_cap_reached` (429),\n`ai_unavailable` (503).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The estimate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealAnalysis"
                },
                "example": {
                  "upload_id": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e",
                  "description": "Grilled chicken salad with quinoa",
                  "meal_type": "lunch",
                  "ingredients": [
                    {
                      "name": "Grilled chicken breast",
                      "quantity": 120,
                      "unit": "g",
                      "protein_g": 31,
                      "calories_kcal": 200,
                      "carbs_g": 0,
                      "fat_g": 4,
                      "fiber_g": 0
                    },
                    {
                      "name": "Quinoa, cooked",
                      "quantity": 90,
                      "unit": "g",
                      "protein_g": 4,
                      "calories_kcal": 110,
                      "carbs_g": 19,
                      "fat_g": 2,
                      "fiber_g": 3
                    },
                    {
                      "name": "Mixed greens and tomato",
                      "quantity": 80,
                      "unit": "g",
                      "protein_g": 1,
                      "calories_kcal": 20,
                      "carbs_g": 4,
                      "fat_g": 0,
                      "fiber_g": 2
                    }
                  ],
                  "totals": {
                    "protein_g": 36,
                    "calories_kcal": 330,
                    "carbs_g": 23,
                    "fat_g": 6,
                    "fiber_g": 5
                  },
                  "confidence": "medium",
                  "note": "The dressing isn't visible; add it if you used one."
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/patient/recent-foods": {
      "get": {
        "operationId": "listRecentFoods",
        "tags": [
          "Logging"
        ],
        "summary": "List my recent foods",
        "description": "Foods the patient logged before, most recently logged first, 10 at a time; follow `next_cursor` for the next 10.\nPicking one pre-fills a meal ingredient with the amount and macros from the last time. Correcting or deleting a\nmeal updates the list.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            },
            "example": 10
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of recent foods.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecentFoodList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5e2-3b4c-7d5e-8f60-7a8b9c0d1e2f",
                      "name": "Greek yogurt, plain, nonfat",
                      "quantity": 170,
                      "unit": "g",
                      "protein_g": 17,
                      "calories_kcal": 100,
                      "carbs_g": 6,
                      "fat_g": 0.7,
                      "fiber_g": 0,
                      "times_logged": 9,
                      "last_logged_at": "2026-10-27T07:45:00Z"
                    },
                    {
                      "id": "0190f5e2-1a2b-7c3d-9e4f-5a6b7c8d9e0f",
                      "name": "Chicken and quinoa bowl",
                      "quantity": null,
                      "unit": null,
                      "protein_g": 38,
                      "calories_kcal": 450,
                      "carbs_g": null,
                      "fat_g": null,
                      "fiber_g": null,
                      "times_logged": 3,
                      "last_logged_at": "2026-10-26T12:30:00Z"
                    }
                  ],
                  "next_cursor": "eyJpZCI6IjAxOTBmNWUyIn0"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/meals": {
      "post": {
        "operationId": "createMealLog",
        "tags": [
          "Logging"
        ],
        "summary": "Log a meal",
        "description": "Macros are optional; send what you have. Updates the day's protein, calorie and fiber rollups.\nError codes: `upload_not_found` (422) for an unknown or expired `photo_upload_id`, `meal_plan_item_not_found` (422).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealLogInput"
              },
              "example": {
                "eaten_at": "2026-10-26T12:30:00Z",
                "meal_type": "lunch",
                "description": "Greek yogurt with berries and almonds",
                "photo_upload_id": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e",
                "entry_method": "photo",
                "protein_g": 24,
                "calories_kcal": 310,
                "fiber_g": 6
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Logged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealLog"
                },
                "example": {
                  "id": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "eaten_at": "2026-10-26T12:30:00Z",
                  "log_date": "2026-10-26",
                  "meal_type": "lunch",
                  "description": "Greek yogurt with berries and almonds",
                  "photo_url": "https://media.example.com/meal-photos/8e2c4a60?signature=example",
                  "entry_method": "photo",
                  "protein_g": 24,
                  "calories_kcal": 310,
                  "fiber_g": 6,
                  "source": "brand_app",
                  "created_at": "2026-10-26T12:31:04Z",
                  "updated_at": "2026-10-26T12:31:04Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "listMealLogs",
        "tags": [
          "Logging"
        ],
        "summary": "List my meals",
        "description": "Meal logs in a date range, newest first.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FromDate"
          },
          {
            "$ref": "#/components/parameters/ToDate"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of meal logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealLogList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                      "eaten_at": "2026-10-26T12:30:00Z",
                      "log_date": "2026-10-26",
                      "meal_type": "lunch",
                      "description": "Greek yogurt with berries and almonds",
                      "entry_method": "manual",
                      "protein_g": 24,
                      "calories_kcal": 310,
                      "photo_url": null,
                      "source": "brand_app",
                      "created_at": "2026-10-26T12:31:04Z",
                      "updated_at": "2026-10-26T12:31:04Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/meals/{log_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/LogId"
        }
      ],
      "patch": {
        "operationId": "updateMealLog",
        "tags": [
          "Logging"
        ],
        "summary": "Correct a meal log",
        "description": "Changes a meal the patient logged. Only logs made in the app can be changed; a log the brand's server sent\nreturns `403 log_not_owned`. The previous version is kept in the record's history, and the day's rollups are\nrecalculated (for both days if the meal moves to another day).\nError codes: `log_not_owned` (403), `upload_not_found`, `meal_plan_item_not_found` (422).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/MealLogUpdate"
              },
              "example": {
                "protein_g": 30,
                "calories_kcal": 360
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The corrected log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealLog"
                },
                "example": {
                  "id": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "eaten_at": "2026-10-26T12:30:00Z",
                  "log_date": "2026-10-26",
                  "meal_type": "lunch",
                  "description": "Greek yogurt with berries and almonds",
                  "photo_url": null,
                  "entry_method": "manual",
                  "protein_g": 30,
                  "calories_kcal": 360,
                  "fiber_g": 6,
                  "source": "brand_app",
                  "created_at": "2026-10-26T12:31:04Z",
                  "updated_at": "2026-10-26T13:02:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteMealLog",
        "tags": [
          "Logging"
        ],
        "summary": "Delete a meal log",
        "description": "Deletes a meal logged by mistake. It leaves lists and the day's rollups at once; its history is kept until the\nbrand's retention period ends. Deleting it again returns `204`. Only logs made in the app can be deleted.\nError code: `log_not_owned` (403).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/workouts": {
      "post": {
        "operationId": "createWorkoutLog",
        "tags": [
          "Logging"
        ],
        "summary": "Log a workout",
        "description": "Updates the day's workout minutes. Link `workout_plan_item_id` when the workout came from the plan.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkoutLogInput"
              },
              "example": {
                "started_at": "2026-10-26T07:00:00Z",
                "activity_type": "strength",
                "duration_min": 35,
                "perceived_effort": 6,
                "workout_plan_item_id": "1b3d5f7a-9c2e-4a6b-8d0f-2e4a6c8e0b2d",
                "sets": [
                  {
                    "exercise_id": "5a7c9e1b-3d5f-4a8c-9e2b-4d6f8a0c2e4f",
                    "name": "Goblet squat",
                    "reps": 10,
                    "weight_kg": 12
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Logged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkoutLog"
                },
                "example": {
                  "id": "0190f5c9-6e7f-7081-9ba3-2c3d4e5f6071",
                  "started_at": "2026-10-26T07:00:00Z",
                  "log_date": "2026-10-26",
                  "activity_type": "strength",
                  "duration_min": 35,
                  "completed": true,
                  "perceived_effort": 6,
                  "workout_plan_item_id": "1b3d5f7a-9c2e-4a6b-8d0f-2e4a6c8e0b2d",
                  "sets": [
                    {
                      "exercise_id": "5a7c9e1b-3d5f-4a8c-9e2b-4d6f8a0c2e4f",
                      "name": "Goblet squat",
                      "reps": 10,
                      "weight_kg": 12
                    }
                  ],
                  "source": "brand_app",
                  "created_at": "2026-10-26T07:40:00Z",
                  "updated_at": "2026-10-26T07:40:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "listWorkoutLogs",
        "tags": [
          "Logging"
        ],
        "summary": "List my workouts",
        "description": "Workout logs in a date range, newest first.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FromDate"
          },
          {
            "$ref": "#/components/parameters/ToDate"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of workout logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkoutLogList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c9-6e7f-7081-9ba3-2c3d4e5f6071",
                      "started_at": "2026-10-26T07:00:00Z",
                      "log_date": "2026-10-26",
                      "activity_type": "walk",
                      "duration_min": 30,
                      "completed": true,
                      "source": "brand_app",
                      "created_at": "2026-10-26T07:40:00Z",
                      "updated_at": "2026-10-26T07:40:00Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/workouts/{log_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/LogId"
        }
      ],
      "patch": {
        "operationId": "updateWorkoutLog",
        "tags": [
          "Logging"
        ],
        "summary": "Correct a workout log",
        "description": "Changes a workout the patient logged. Only logs made in the app can be changed; a log the brand's server sent\nreturns `403 log_not_owned`. The previous version is kept in the record's history, and the day's rollups are\nrecalculated (for both days if the workout moves to another day).\nError codes: `log_not_owned` (403), `workout_plan_item_not_found` (422).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/WorkoutLogUpdate"
              },
              "example": {
                "duration_min": 45
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The corrected log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkoutLog"
                },
                "example": {
                  "id": "0190f5c9-6e7f-7081-9ba3-2c3d4e5f6071",
                  "started_at": "2026-10-26T07:00:00Z",
                  "log_date": "2026-10-26",
                  "activity_type": "strength",
                  "duration_min": 45,
                  "completed": true,
                  "perceived_effort": 6,
                  "source": "brand_app",
                  "created_at": "2026-10-26T07:40:00Z",
                  "updated_at": "2026-10-26T08:10:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteWorkoutLog",
        "tags": [
          "Logging"
        ],
        "summary": "Delete a workout log",
        "description": "Deletes a workout logged by mistake. It leaves lists and the day's rollups at once; its history is kept until the\nbrand's retention period ends. Deleting it again returns `204`. Only logs made in the app can be deleted.\nError code: `log_not_owned` (403).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/symptoms": {
      "post": {
        "operationId": "createSymptomLog",
        "tags": [
          "Logging"
        ],
        "summary": "Log a symptom",
        "description": "Severity 1 (mild) to 5 (severe). Alert rules run on every symptom: a red flag or a severe GI episode raises a\nclinical flag (to the coach on the coached plan, to the brand's prescriber on `ai_only`).\nWhen the response has `is_red_flag: true`, show the emergency guidance (call 911, or 988 for a mental health\ncrisis) before anything else. Coaching is not emergency care.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SymptomLogInput"
              },
              "example": {
                "occurred_at": "2026-10-26T19:45:00Z",
                "symptom": "nausea",
                "severity": 2,
                "note": "Mild, after dinner"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Logged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SymptomLog"
                },
                "example": {
                  "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                  "occurred_at": "2026-10-26T19:45:00Z",
                  "log_date": "2026-10-26",
                  "symptom": "nausea",
                  "severity": 2,
                  "note": "Mild, after dinner",
                  "is_red_flag": false,
                  "days_since_injection": 0,
                  "source": "brand_app",
                  "created_at": "2026-10-26T19:46:10Z",
                  "updated_at": "2026-10-26T19:46:10Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "listSymptomLogs",
        "tags": [
          "Logging"
        ],
        "summary": "List my symptoms",
        "description": "Symptom logs in a date range, newest first.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FromDate"
          },
          {
            "$ref": "#/components/parameters/ToDate"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of symptom logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SymptomLogList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                      "occurred_at": "2026-10-26T19:45:00Z",
                      "log_date": "2026-10-26",
                      "symptom": "nausea",
                      "severity": 2,
                      "is_red_flag": false,
                      "days_since_injection": 0,
                      "source": "brand_app",
                      "created_at": "2026-10-26T19:46:10Z",
                      "updated_at": "2026-10-26T19:46:10Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/symptoms/{log_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/LogId"
        }
      ],
      "patch": {
        "operationId": "updateSymptomLog",
        "tags": [
          "Logging"
        ],
        "summary": "Correct a symptom log",
        "description": "Changes a symptom the patient logged. Only logs made in the app can be changed; a log the brand's server sent\nreturns `403 log_not_owned`. The previous version is kept in the record's history, and the day's rollups are\nrecalculated (for both days if the symptom moves to another day).\nEditing or deleting a symptom never closes a clinical flag or lowers the risk level; only the prescriber's resolve\ndoes. A correction that makes a symptom more severe runs the alert rules again, like a new log, so it can raise a\nflag. A flag raised by a symptom deleted later shows `deleted_at` on its triggering record.\nError codes: `log_not_owned` (403).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/SymptomLogUpdate"
              },
              "example": {
                "severity": 3,
                "note": "Worse after dinner than I first logged"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The corrected log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SymptomLog"
                },
                "example": {
                  "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                  "occurred_at": "2026-10-26T19:45:00Z",
                  "log_date": "2026-10-26",
                  "symptom": "nausea",
                  "severity": 3,
                  "note": "Worse after dinner than I first logged",
                  "is_red_flag": false,
                  "days_since_injection": 2,
                  "source": "brand_app",
                  "created_at": "2026-10-26T19:46:10Z",
                  "updated_at": "2026-10-26T20:30:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteSymptomLog",
        "tags": [
          "Logging"
        ],
        "summary": "Delete a symptom log",
        "description": "Deletes a symptom logged by mistake. It leaves lists and the day's rollups at once; its history is kept until the\nbrand's retention period ends. Deleting it again returns `204`. Only logs made in the app can be deleted.\nEditing or deleting a symptom never closes a clinical flag or lowers the risk level; only the prescriber's resolve\ndoes. A correction that makes a symptom more severe runs the alert rules again, like a new log, so it can raise a\nflag. A flag raised by a symptom deleted later shows `deleted_at` on its triggering record.\nError code: `log_not_owned` (403).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/injections": {
      "post": {
        "operationId": "createInjectionLog",
        "tags": [
          "Logging"
        ],
        "summary": "Log an injection",
        "description": "A dose taken (`injected_at`) or missed (`missed: true`). A missed dose can raise a `missed_injection` alert.\nError code: `injection_incomplete` (422) when the log is neither taken nor missed.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InjectionLogInput"
              },
              "examples": {
                "taken": {
                  "summary": "Dose taken",
                  "value": {
                    "injected_at": "2026-10-26T08:00:00Z",
                    "scheduled_for": "2026-10-26",
                    "dose_mg": 0.5,
                    "site": "abdomen_left"
                  }
                },
                "missed": {
                  "summary": "Dose missed",
                  "value": {
                    "missed": true,
                    "scheduled_for": "2026-10-19"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Logged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InjectionLog"
                },
                "example": {
                  "id": "0190f5c9-8091-72a3-9dc5-4e5f60718293",
                  "injected_at": "2026-10-26T08:00:00Z",
                  "missed": false,
                  "scheduled_for": "2026-10-26",
                  "log_date": "2026-10-26",
                  "dose_mg": 0.5,
                  "site": "abdomen_left",
                  "source": "brand_app",
                  "created_at": "2026-10-26T08:01:30Z",
                  "updated_at": "2026-10-26T08:01:30Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "listInjectionLogs",
        "tags": [
          "Logging"
        ],
        "summary": "List my injections",
        "description": "Injection logs in a date range, newest first.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FromDate"
          },
          {
            "$ref": "#/components/parameters/ToDate"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of injection logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InjectionLogList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c9-8091-72a3-9dc5-4e5f60718293",
                      "injected_at": "2026-10-26T08:00:00Z",
                      "missed": false,
                      "scheduled_for": "2026-10-26",
                      "log_date": "2026-10-26",
                      "dose_mg": 0.5,
                      "site": "abdomen_left",
                      "source": "brand_app",
                      "created_at": "2026-10-26T08:01:30Z",
                      "updated_at": "2026-10-26T08:01:30Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/injections/{log_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/LogId"
        }
      ],
      "patch": {
        "operationId": "updateInjectionLog",
        "tags": [
          "Logging"
        ],
        "summary": "Correct an injection log",
        "description": "Changes an injection the patient logged. Only logs made in the app can be changed; a log the brand's server sent\nreturns `403 log_not_owned`. The previous version is kept in the record's history, and the day's rollups are\nrecalculated (for both days if the dose moves to another day).\nChanging a missed dose to taken (or back) does not close an alert already raised for it.\nError codes: `log_not_owned` (403), `injection_incomplete` (422) when the result is neither taken nor missed.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/InjectionLogUpdate"
              },
              "example": {
                "missed": false,
                "injected_at": "2026-10-26T08:00:00Z",
                "dose_mg": 0.5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The corrected log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InjectionLog"
                },
                "example": {
                  "id": "0190f5c9-8091-72a3-9dc5-4e5f60718293",
                  "injected_at": "2026-10-26T08:00:00Z",
                  "missed": false,
                  "scheduled_for": "2026-10-26",
                  "dose_mg": 0.5,
                  "site": "abdomen_left",
                  "log_date": "2026-10-26",
                  "source": "brand_app",
                  "created_at": "2026-10-26T08:01:30Z",
                  "updated_at": "2026-10-26T09:15:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteInjectionLog",
        "tags": [
          "Logging"
        ],
        "summary": "Delete an injection log",
        "description": "Deletes an injection logged by mistake. It leaves lists and the day's rollups at once; its history is kept until the\nbrand's retention period ends. Deleting it again returns `204`. Only logs made in the app can be deleted.\nChanging a missed dose to taken (or back) does not close an alert already raised for it.\nError code: `log_not_owned` (403).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/protocols": {
      "get": {
        "operationId": "listMyProtocols",
        "tags": [
          "Protocols and plans"
        ],
        "summary": "List my active protocols",
        "description": "At most one active protocol per type (nutrition, fitness, sleep, stress, lifestyle, supplements).\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "Active protocols.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtocolSummaryList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                      "type": "nutrition",
                      "version": 2,
                      "status": "active",
                      "mode": "full_plan",
                      "title": "Protein-first nutrition, titration weeks 5-8",
                      "summary": "Hit 110 g of protein a day and keep meals small while the dose goes up.",
                      "published_at": "2026-10-25T08:00:00Z",
                      "published_by": "coach"
                    },
                    {
                      "id": "0190f5c6-9cad-7e12-8f34-5a6b7c8d9e01",
                      "type": "fitness",
                      "version": 1,
                      "status": "active",
                      "mode": "full_plan",
                      "title": "Muscle-preserving strength, weeks 5-8",
                      "summary": "Two short strength sessions and daily walks.",
                      "published_at": "2026-10-23T16:45:00Z",
                      "published_by": "coach"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/protocols/{protocol_type}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ProtocolTypePath"
        }
      ],
      "get": {
        "operationId": "getMyProtocol",
        "tags": [
          "Protocols and plans"
        ],
        "summary": "Get my active protocol of a type",
        "description": "Error code: `protocol_not_found` (404) when there is no active protocol of this type yet.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The active protocol.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Protocol"
                },
                "example": {
                  "id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                  "type": "nutrition",
                  "version": 2,
                  "status": "active",
                  "mode": "full_plan",
                  "title": "Protein-first nutrition, titration weeks 5-8",
                  "summary": "Hit 110 g of protein a day and keep meals small while the dose goes up.",
                  "published_at": "2026-10-25T08:00:00Z",
                  "published_by": "coach",
                  "change_reason": "Dose increased to 0.5 mg",
                  "content": {
                    "markdown": "## This week\nAim for 30 g of protein at each meal and sip water through the day.\n",
                    "targets": [
                      {
                        "metric": "protein_g",
                        "value": 110,
                        "unit": "g",
                        "label": "Protein per day"
                      },
                      {
                        "metric": "water_ml",
                        "value": 2500,
                        "unit": "ml",
                        "label": "Water per day"
                      }
                    ],
                    "habits": [
                      {
                        "key": "protein_each_meal",
                        "title": "Protein at every meal",
                        "kind": "checkoff",
                        "target_value": null,
                        "unit": null
                      }
                    ],
                    "meal_plan_id": "0190f5ca-1a2b-7c3d-8e4f-5a6b7c8d9e01",
                    "workout_plan_id": null
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/protocols/{protocol_type}/versions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ProtocolTypePath"
        }
      ],
      "get": {
        "operationId": "listMyProtocolVersions",
        "tags": [
          "Protocols and plans"
        ],
        "summary": "List versions of a protocol",
        "description": "The active version and the superseded ones before it.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Versions, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtocolVersionList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                      "type": "nutrition",
                      "version": 2,
                      "status": "active",
                      "mode": "full_plan",
                      "title": "Protein-first nutrition, titration weeks 5-8",
                      "summary": "Hit 110 g of protein a day and keep meals small while the dose goes up.",
                      "published_at": "2026-10-25T08:00:00Z",
                      "published_by": "coach"
                    },
                    {
                      "id": "0190f5c6-7a8b-7c90-8d12-3e4f5a6b7c8d",
                      "type": "nutrition",
                      "version": 1,
                      "status": "superseded",
                      "mode": "full_plan",
                      "title": "Protein-first nutrition, weeks 1-4",
                      "summary": "Build the protein habit while the dose starts low.",
                      "published_at": "2026-10-23T16:45:00Z",
                      "published_by": "coach"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/protocols/{protocol_type}/versions/{version}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ProtocolTypePath"
        },
        {
          "$ref": "#/components/parameters/ProtocolVersion"
        }
      ],
      "get": {
        "operationId": "getMyProtocolVersion",
        "tags": [
          "Protocols and plans"
        ],
        "summary": "Get one version of a protocol",
        "description": "Any published version, active or superseded.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The protocol version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Protocol"
                },
                "example": {
                  "id": "0190f5c6-7a8b-7c90-8d12-3e4f5a6b7c8d",
                  "type": "nutrition",
                  "version": 1,
                  "status": "superseded",
                  "mode": "full_plan",
                  "title": "Protein-first nutrition, weeks 1-4",
                  "summary": "Build the protein habit while the dose starts low.",
                  "published_at": "2026-10-23T16:45:00Z",
                  "published_by": "coach",
                  "change_reason": null,
                  "content": {
                    "markdown": "## Getting started\nStart each day with a protein breakfast.\n",
                    "targets": [
                      {
                        "metric": "protein_g",
                        "value": 100,
                        "unit": "g",
                        "label": "Protein per day"
                      }
                    ],
                    "habits": [
                      {
                        "key": "protein_each_meal",
                        "title": "Protein at every meal",
                        "kind": "checkoff",
                        "target_value": null,
                        "unit": null
                      }
                    ],
                    "meal_plan_id": null,
                    "workout_plan_id": null
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/meal-plan": {
      "get": {
        "operationId": "getMyMealPlan",
        "tags": [
          "Protocols and plans"
        ],
        "summary": "Get my meal plan",
        "description": "The active meal plan, day by day, including any swapped meals. Error code `meal_plan_not_found` (404).\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The active meal plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealPlan"
                },
                "example": {
                  "id": "0190f5ca-1a2b-7c3d-8e4f-5a6b7c8d9e01",
                  "protocol_id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                  "version": 1,
                  "status": "active",
                  "title": "Week 5 meal plan",
                  "starts_on": "2026-10-26",
                  "published_by": "coach",
                  "items": [
                    {
                      "id": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01",
                      "day_index": 0,
                      "meal_type": "breakfast",
                      "sort_order": 0,
                      "title": "Greek yogurt bowl",
                      "description": "Nonfat Greek yogurt with berries and almonds",
                      "protein_g": 24,
                      "calories_kcal": 310,
                      "details": {
                        "prep_minutes": 5
                      },
                      "recipe_id": null,
                      "swap": null
                    },
                    {
                      "id": "4d2f9a31-6c8b-4e0d-9f72-1b3c5d7e9f02",
                      "day_index": 0,
                      "meal_type": "dinner",
                      "sort_order": 0,
                      "title": "Chicken and quinoa bowl",
                      "description": "Grilled chicken, quinoa, roasted vegetables",
                      "protein_g": 38,
                      "calories_kcal": 480,
                      "details": {
                        "prep_minutes": 25
                      },
                      "recipe_id": null,
                      "swap": {
                        "original_title": "Salmon with quinoa",
                        "reason": "Does not like fish",
                        "swapped_by": "ai",
                        "swapped_at": "2026-10-26T11:02:00Z"
                      }
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/workout-plan": {
      "get": {
        "operationId": "getMyWorkoutPlan",
        "tags": [
          "Protocols and plans"
        ],
        "summary": "Get my workout plan",
        "description": "The active workout plan, day by day. Error code `workout_plan_not_found` (404).\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The active workout plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkoutPlan"
                },
                "example": {
                  "id": "0190f5cb-2b3c-7d4e-8f50-6a7b8c9d0e12",
                  "protocol_id": "0190f5c6-9cad-7e12-8f34-5a6b7c8d9e01",
                  "version": 1,
                  "status": "active",
                  "title": "Muscle-preserving strength, weeks 5-8",
                  "starts_on": "2026-10-26",
                  "published_by": "coach",
                  "items": [
                    {
                      "id": "1b3d5f7a-9c2e-4a6b-8d0f-2e4a6c8e0b2d",
                      "day_index": 1,
                      "sort_order": 0,
                      "title": "Full-body strength A",
                      "description": "Three moves, three sets each. Stop two reps before failure.",
                      "duration_min": 30,
                      "exercises": [
                        {
                          "exercise_id": "5a7c9e1b-3d5f-4a8c-9e2b-4d6f8a0c2e4f",
                          "name": "Goblet squat",
                          "sets": 3,
                          "reps": "8-12",
                          "rest_s": 60,
                          "notes": "Keep your chest up",
                          "media_url": "https://media.example.com/exercises/goblet-squat.mp4"
                        }
                      ]
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/meal-plan/items/{item_id}/swap-options": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MealPlanItemId"
        }
      ],
      "post": {
        "operationId": "createMealSwapOptions",
        "tags": [
          "Meal swap"
        ],
        "summary": "Ask the AI Coach for swap options",
        "description": "The AI Coach proposes replacements for one meal and keeps only those that stay within the protocol's targets and the\nbrand's rule matrix (allergies, foods to avoid, calorie floor). Takes a few seconds. Options expire after\n30 minutes. Counts toward the plan's daily AI Coach cap.\n\nError codes: `ai_paused` (409) when the AI Coach is paused for the plan, `daily_message_cap_reached` (429),\n`ai_unavailable` (503).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealSwapOptionsRequest"
              },
              "example": {
                "reason": "I don't like fish",
                "avoid": [
                  "fish"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Options checked against the plan's constraints.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealSwapOptions"
                },
                "example": {
                  "item_id": "4d2f9a31-6c8b-4e0d-9f72-1b3c5d7e9f02",
                  "options": [
                    {
                      "option_id": "opt_1",
                      "title": "Chicken and quinoa bowl",
                      "description": "Grilled chicken, quinoa, roasted vegetables",
                      "protein_g": 38,
                      "calories_kcal": 480,
                      "details": {
                        "prep_minutes": 25
                      }
                    },
                    {
                      "option_id": "opt_2",
                      "title": "Tofu stir-fry with edamame",
                      "description": "Firm tofu, edamame, broccoli and brown rice",
                      "protein_g": 34,
                      "calories_kcal": 460,
                      "details": {
                        "prep_minutes": 20
                      }
                    }
                  ],
                  "note": null,
                  "expires_at": "2026-10-26T11:30:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/patient/meal-plan/items/{item_id}/swap": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MealPlanItemId"
        }
      ],
      "post": {
        "operationId": "swapMeal",
        "tags": [
          "Meal swap"
        ],
        "summary": "Swap a meal",
        "description": "Replaces the meal with one of the options. The original meal and the reason are kept on the item and shown to\nthe care team. Error codes: `swap_option_expired` (409), `swap_option_not_found` (422).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealSwapRequest"
              },
              "example": {
                "option_id": "opt_1",
                "reason": "I don't like fish"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The swapped meal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealPlanItem"
                },
                "example": {
                  "id": "4d2f9a31-6c8b-4e0d-9f72-1b3c5d7e9f02",
                  "day_index": 0,
                  "meal_type": "dinner",
                  "sort_order": 0,
                  "title": "Chicken and quinoa bowl",
                  "description": "Grilled chicken, quinoa, roasted vegetables",
                  "protein_g": 38,
                  "calories_kcal": 480,
                  "details": {
                    "prep_minutes": 25
                  },
                  "recipe_id": null,
                  "swap": {
                    "original_title": "Salmon with quinoa",
                    "reason": "I don't like fish",
                    "swapped_by": "ai",
                    "swapped_at": "2026-10-26T11:02:00Z"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/meal-plan/items/{item_id}/rating": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MealPlanItemId"
        }
      ],
      "put": {
        "operationId": "rateMealPlanItem",
        "tags": [
          "Protocols and plans"
        ],
        "summary": "Rate a meal on my plan",
        "description": "1 to 5 stars with an optional comment, shown on the plan as `my_rating`; rating again replaces it. Coaches see\nit, and new plans, swaps and the AI Coach avoid meals rated 1 or 2. To rate the recipe itself wherever it\nappears, use `PUT /v1/patient/library/{library_item_id}/rating`.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealRatingInput"
              },
              "example": {
                "rating": 4,
                "comment": "Filling, but I'd like it less spicy."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The rating.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealRating"
                },
                "example": {
                  "rating": 4,
                  "comment": "Filling, but I'd like it less spicy.",
                  "updated_at": "2026-10-27T13:05:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteMealPlanItemRating",
        "tags": [
          "Protocols and plans"
        ],
        "summary": "Clear a meal rating",
        "description": "Clearing a rating that isn't there changes nothing.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Cleared.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/library": {
      "get": {
        "operationId": "listLibraryItems",
        "tags": [
          "Library"
        ],
        "summary": "Browse recipes and exercises",
        "description": "Searches the recipes and exercises the patient can see, alphabetically. Recipes that contain one of the patient's\nfood allergies, or don't fit one of their dietary restrictions, are never returned. Food dislikes are not filtered.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "name": "kind",
            "in": "query",
            "description": "Omit for both.",
            "schema": {
              "$ref": "#/components/schemas/LibraryKind"
            },
            "example": "recipe"
          },
          {
            "name": "meal_type",
            "in": "query",
            "description": "Recipes for this meal.",
            "schema": {
              "$ref": "#/components/schemas/MealType"
            },
            "example": "breakfast"
          },
          {
            "name": "tag",
            "in": "query",
            "description": "Items with this tag, for example `high_protein`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z][a-z0-9_]*$"
            },
            "example": "mild_nausea"
          },
          {
            "name": "q",
            "in": "query",
            "description": "Words in the title.",
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "example": "yogurt"
          },
          {
            "name": "favorites",
            "in": "query",
            "description": "Only the items the patient saved, most recently saved first.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of library items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LibraryItemList"
                },
                "example": {
                  "data": [
                    {
                      "id": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f",
                      "kind": "recipe",
                      "slug": "greek-yogurt-protein-bowl",
                      "title": "Greek yogurt protein bowl",
                      "category": "breakfast",
                      "tags": [
                        "high_protein",
                        "mild_nausea"
                      ],
                      "thumbnail_url": "https://media.example.com/library/greek-yogurt-protein-bowl-thumb.jpg",
                      "calories_kcal": 320,
                      "protein_g": 31,
                      "favorite": true
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/library/{library_item_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/LibraryItemId"
        }
      ],
      "get": {
        "operationId": "getLibraryItem",
        "tags": [
          "Library"
        ],
        "summary": "Get a recipe or exercise",
        "description": "The full recipe or exercise, for example from a meal plan's `recipe_id` or a workout's `exercise_id`. Unlike the\nlist, this returns the item whatever the patient's profile; use `recipe.allergens` to warn them.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LibraryItem"
                },
                "examples": {
                  "recipe": {
                    "summary": "A recipe",
                    "value": {
                      "id": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f",
                      "kind": "recipe",
                      "slug": "greek-yogurt-protein-bowl",
                      "title": "Greek yogurt protein bowl",
                      "summary": "A no-cook breakfast with 31 g of protein.",
                      "category": "breakfast",
                      "tags": [
                        "high_protein",
                        "mild_nausea"
                      ],
                      "media": [
                        {
                          "kind": "image",
                          "url": "https://media.example.com/library/greek-yogurt-protein-bowl.jpg",
                          "thumbnail_url": "https://media.example.com/library/greek-yogurt-protein-bowl-thumb.jpg"
                        }
                      ],
                      "recipe": {
                        "servings": 1,
                        "serving_size": "1 bowl (about 300 g)",
                        "prep_minutes": 5,
                        "cook_minutes": 0,
                        "difficulty": "easy",
                        "cuisine": null,
                        "meal_types": [
                          "breakfast",
                          "snack"
                        ],
                        "appliances": [],
                        "ingredients": [
                          {
                            "name": "Greek yogurt, plain, nonfat",
                            "quantity": 200,
                            "unit": "g"
                          },
                          {
                            "name": "Blueberries",
                            "quantity": 75,
                            "unit": "g"
                          },
                          {
                            "name": "Chia seeds",
                            "quantity": 10,
                            "unit": "g"
                          }
                        ],
                        "steps": [
                          "Spoon the yogurt into a bowl",
                          "Top with the blueberries and chia seeds"
                        ],
                        "nutrients": {
                          "calories_kcal": 320,
                          "protein_g": 31,
                          "carbs_g": 30,
                          "fat_g": 9,
                          "fiber_g": 6
                        },
                        "allergens": [
                          "milk"
                        ],
                        "diets": [
                          "vegetarian",
                          "gluten_free"
                        ],
                        "why": "Small, cold and high in protein, so it is easy to eat on a low-appetite day."
                      },
                      "exercise": null,
                      "favorite": true,
                      "my_rating": {
                        "rating": 5,
                        "comment": null,
                        "updated_at": "2026-10-24T08:15:00Z"
                      }
                    }
                  },
                  "exercise": {
                    "summary": "An exercise",
                    "value": {
                      "id": "5a7c9e1b-3d5f-4a8c-9e2b-4d6f8a0c2e4f",
                      "kind": "exercise",
                      "slug": "goblet-squat",
                      "title": "Goblet squat",
                      "summary": "A squat holding one weight at your chest, to keep leg muscle while losing weight.",
                      "category": "lower_body",
                      "tags": [
                        "strength"
                      ],
                      "media": [
                        {
                          "kind": "video",
                          "url": "https://media.example.com/library/goblet-squat.mp4",
                          "thumbnail_url": "https://media.example.com/library/goblet-squat.jpg"
                        }
                      ],
                      "recipe": null,
                      "exercise": {
                        "focus": "Lower body",
                        "muscle_groups": [
                          "quadriceps",
                          "glutes"
                        ],
                        "equipment": [
                          "dumbbell"
                        ],
                        "difficulty": "beginner",
                        "starting_position": "Stand with feet shoulder-width apart, holding one dumbbell at your chest.",
                        "instructions": [
                          "Sit back and down until your thighs are parallel to the floor",
                          "Push through your heels to stand"
                        ],
                        "key_points": [
                          "Keep your chest up",
                          "Knees track over your toes"
                        ]
                      },
                      "favorite": false,
                      "my_rating": null
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/library/{library_item_id}/favorite": {
      "parameters": [
        {
          "$ref": "#/components/parameters/LibraryItemId"
        }
      ],
      "put": {
        "operationId": "favoriteLibraryItem",
        "tags": [
          "Library"
        ],
        "summary": "Save a recipe or exercise",
        "description": "Adds it to the patient's favorites (`GET /v1/patient/library?favorites=true`). Saving it again changes nothing.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Saved.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "unfavoriteLibraryItem",
        "tags": [
          "Library"
        ],
        "summary": "Remove a favorite",
        "description": "Removing one that isn't saved changes nothing.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Removed.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/library/{library_item_id}/rating": {
      "parameters": [
        {
          "$ref": "#/components/parameters/LibraryItemId"
        }
      ],
      "put": {
        "operationId": "rateLibraryItem",
        "tags": [
          "Library"
        ],
        "summary": "Rate a recipe",
        "description": "1 to 5 stars with an optional comment; rating again replaces it. New meal plans, swaps and the AI Coach avoid\nrecipes rated 1 or 2, and coaches see the ratings. After a low rating the app can offer to add a food dislike with\n`PATCH /v1/patient`. Error code: `not_a_recipe` (422) for an exercise.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealRatingInput"
              },
              "example": {
                "rating": 2,
                "comment": "Too sweet for me."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The rating.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealRating"
                },
                "example": {
                  "rating": 2,
                  "comment": "Too sweet for me.",
                  "updated_at": "2026-10-27T12:40:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteLibraryItemRating",
        "tags": [
          "Library"
        ],
        "summary": "Clear a recipe rating",
        "description": "Clearing a rating that isn't there changes nothing.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Cleared.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/care/conversations": {
      "get": {
        "operationId": "listCareConversations",
        "tags": [
          "Care messaging"
        ],
        "summary": "List my care threads",
        "description": "One thread per coach on the care team, with unread counts.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "responses": {
          "200": {
            "description": "Care threads.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CareConversationList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12",
                      "coach": {
                        "care_role": "health_coach",
                        "display_name": "Maya C.",
                        "title": "Health Coach",
                        "credentials": [
                          "RD",
                          "NBC-HWC"
                        ],
                        "assigned_at": "2026-10-21T15:10:00Z"
                      },
                      "last_message_at": "2026-10-26T13:40:00Z",
                      "unread_count": 1,
                      "patient_last_read_at": "2026-10-26T09:00:00Z",
                      "coach_last_read_at": "2026-10-26T13:40:00Z"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/care/conversations/{conversation_id}/messages": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ConversationId"
        }
      ],
      "get": {
        "operationId": "listCareMessages",
        "tags": [
          "Care messaging"
        ],
        "summary": "List messages in a care thread",
        "description": "Newest first. New messages are announced by `message.created`; fetch them here.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of messages.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23",
                      "conversation_id": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12",
                      "sender": {
                        "type": "coach",
                        "display_name": "Maya C.",
                        "care_role": "health_coach"
                      },
                      "body": "Great job on your protein yesterday. How is the nausea today?",
                      "created_at": "2026-10-26T13:40:00Z",
                      "edited_at": null,
                      "deleted": false,
                      "seen_by_other_side": false,
                      "attachment": null,
                      "reactions": [],
                      "feedback": null
                    }
                  ],
                  "next_cursor": "eyJpZCI6IjAxOTBmNWM0In0"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "sendCareMessage",
        "tags": [
          "Care messaging"
        ],
        "summary": "Message my coach",
        "description": "Text, a photo, or both. For a photo, start an upload with `POST /v1/patient/message-photos`, upload it, then\nsend its `upload_id` as `photo_upload_id`. Coaching is not emergency care. Show the 911 and 988 guidance next\nto the message box: coaches do not answer around the clock. Error codes: `conversation_archived` (409),\n`upload_not_found` (422).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CareMessageInput"
              },
              "example": {
                "body": "Nausea is better today. Can I swap dinner?"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                },
                "example": {
                  "id": "0190f5c4-3f40-7b52-8c67-8d9e0f1a2b34",
                  "conversation_id": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12",
                  "sender": {
                    "type": "patient",
                    "display_name": "Jordan",
                    "care_role": null
                  },
                  "body": "Nausea is better today. Can I swap dinner?",
                  "created_at": "2026-10-26T14:05:00Z",
                  "edited_at": null,
                  "deleted": false,
                  "seen_by_other_side": false,
                  "attachment": null,
                  "reactions": [],
                  "feedback": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/care/conversations/{conversation_id}/read": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ConversationId"
        }
      ],
      "post": {
        "operationId": "markCareConversationRead",
        "tags": [
          "Care messaging"
        ],
        "summary": "Mark a care thread read",
        "description": "Moves the patient's read marker. The coach sees their messages as seen.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReadMarker"
              },
              "example": {
                "read_at": "2026-10-26T14:05:00Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The read state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadState"
                },
                "example": {
                  "conversation_id": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12",
                  "patient_last_read_at": "2026-10-26T14:05:00Z",
                  "unread_count": 0
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/messages/{message_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MessageId"
        }
      ],
      "patch": {
        "operationId": "updateMyMessage",
        "tags": [
          "Care messaging"
        ],
        "summary": "Edit my last message",
        "description": "Changes the text of the patient's most recent message in a care thread. Only that one can be edited, and only in\ncare threads (AI Coach replies are written from what the patient sent). The coach sees it marked as edited, and\nthe previous text is kept in the record's history. Error codes: `not_last_message` (409) for an older message\nor one the patient didn't send, `message_not_editable` (422) in an AI Coach chat, `conversation_archived` (409).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/MessageUpdate"
              },
              "example": {
                "body": "Nausea is better today. Can I swap tonight's dinner?"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The edited message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                },
                "example": {
                  "id": "0190f5c4-3f40-7b52-8c67-8d9e0f1a2b34",
                  "conversation_id": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12",
                  "sender": {
                    "type": "patient",
                    "display_name": "Jordan",
                    "care_role": null
                  },
                  "body": "Nausea is better today. Can I swap tonight's dinner?",
                  "created_at": "2026-10-26T14:05:00Z",
                  "edited_at": "2026-10-26T14:06:30Z",
                  "deleted": false,
                  "seen_by_other_side": false,
                  "attachment": null,
                  "reactions": [],
                  "feedback": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/messages/{message_id}/reactions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MessageId"
        }
      ],
      "put": {
        "operationId": "setMessageReactions",
        "tags": [
          "Care messaging"
        ],
        "summary": "Set my reactions on a message",
        "description": "Replaces the patient's reactions on any message in their care or AI Coach threads. Send `[]` to remove them.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReactionsInput"
              },
              "example": {
                "emojis": [
                  "👍"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "All reactions on the message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reactions"
                },
                "example": {
                  "message_id": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23",
                  "reactions": [
                    {
                      "emoji": "👍",
                      "by": "patient"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/message-photos": {
      "post": {
        "operationId": "createMessagePhotoUpload",
        "tags": [
          "Care messaging"
        ],
        "summary": "Start a photo upload for my coach",
        "description": "Returns a pre-signed URL. Upload the photo there, then send `upload_id` as `photo_upload_id` with the message.\nAn upload not sent within 1 hour is deleted. The coach sees the photo in the thread; the patient's copy comes\nback as an `image` attachment with a short-lived `url`.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealPhotoUploadRequest"
              },
              "example": {
                "content_type": "image/jpeg",
                "content_length": 2097152
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Upload ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealPhotoUpload"
                },
                "example": {
                  "upload_id": "9f3d5b71-2a4c-4e6f-8b0d-1c3e5a7b9d2f",
                  "upload_url": "https://uploads.example.com/message-photos/9f3d5b71?signature=example",
                  "method": "PUT",
                  "headers": {
                    "Content-Type": "image/jpeg"
                  },
                  "expires_at": "2026-10-27T15:15:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/feedback-requests": {
      "get": {
        "operationId": "listMyFeedbackRequests",
        "tags": [
          "Feedback"
        ],
        "summary": "List open feedback popups",
        "description": "Popups waiting for an answer, oldest first. `care_team.feedback_due` tells your server when one opens; check here\ntoo, for example when the app opens, in case a webhook was missed.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "responses": {
          "200": {
            "description": "Open popups.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackRequestList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6",
                      "status": "requested",
                      "care_role": "health_coach",
                      "coach": {
                        "care_role": "health_coach",
                        "display_name": "Maya C.",
                        "title": "Health Coach",
                        "credentials": [
                          "RD"
                        ],
                        "assigned_at": "2026-09-15T10:00:00Z"
                      },
                      "survey": {
                        "code": "coach_feedback",
                        "version": 1,
                        "title": "How is coaching going?",
                        "intro": "It takes less than a minute.",
                        "questions": [
                          {
                            "key": "overall",
                            "kind": "rating",
                            "label": "How would you rate your coach so far?",
                            "required": true,
                            "scale_max": 5
                          },
                          {
                            "key": "comment",
                            "kind": "text",
                            "label": "Anything else you would like to share?",
                            "required": false,
                            "max_length": 1000
                          }
                        ]
                      },
                      "requested_at": "2026-10-27T15:00:00Z",
                      "expires_at": "2026-11-10T15:00:00Z",
                      "answers": null,
                      "answered_at": null
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/feedback-requests/{feedback_request_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/FeedbackRequestId"
        }
      ],
      "get": {
        "operationId": "getMyFeedbackRequest",
        "tags": [
          "Feedback"
        ],
        "summary": "Get a feedback popup",
        "description": "The popup's title, questions and the coach it is about. TeraRx writes the questions; render each one by its\n`kind`. Don't show a popup whose `status` is no longer `requested`.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "responses": {
          "200": {
            "description": "The popup.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackRequest"
                },
                "example": {
                  "id": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6",
                  "status": "requested",
                  "care_role": "health_coach",
                  "coach": {
                    "care_role": "health_coach",
                    "display_name": "Maya C.",
                    "title": "Health Coach",
                    "credentials": [
                      "RD"
                    ],
                    "assigned_at": "2026-09-15T10:00:00Z"
                  },
                  "survey": {
                    "code": "coach_feedback",
                    "version": 1,
                    "title": "How is coaching going?",
                    "intro": "It takes less than a minute.",
                    "questions": [
                      {
                        "key": "overall",
                        "kind": "rating",
                        "label": "How would you rate your coach so far?",
                        "required": true,
                        "scale_max": 5
                      },
                      {
                        "key": "helpful",
                        "kind": "thumbs",
                        "label": "Did your coach help you this month?",
                        "required": false
                      },
                      {
                        "key": "more_help_with",
                        "kind": "choice",
                        "label": "What would you like more help with?",
                        "required": false,
                        "options": [
                          {
                            "value": "nutrition",
                            "label": "Nutrition"
                          },
                          {
                            "value": "exercise",
                            "label": "Exercise"
                          },
                          {
                            "value": "side_effects",
                            "label": "Side effects"
                          },
                          {
                            "value": "motivation",
                            "label": "Motivation"
                          }
                        ]
                      },
                      {
                        "key": "comment",
                        "kind": "text",
                        "label": "Anything else you would like to share?",
                        "required": false,
                        "max_length": 1000
                      }
                    ]
                  },
                  "requested_at": "2026-10-27T15:00:00Z",
                  "expires_at": "2026-11-10T15:00:00Z",
                  "answers": null,
                  "answered_at": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/feedback-requests/{feedback_request_id}/response": {
      "parameters": [
        {
          "$ref": "#/components/parameters/FeedbackRequestId"
        }
      ],
      "post": {
        "operationId": "answerMyFeedbackRequest",
        "tags": [
          "Feedback"
        ],
        "summary": "Answer a feedback popup",
        "description": "Checks each answer against its question: every `required` question answered, ratings from 1 to `scale_max`,\nthumbs `up` or `down`, choices among the `options`, text within `max_length`. The answers go to TeraRx, which\nuses them to support its coaches. Error codes: `validation_failed` (422, with a pointer per answer such as\n`/answers/overall`), `feedback_request_closed` (409) once answered, dismissed or expired.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeedbackResponseInput"
              },
              "example": {
                "answers": {
                  "overall": 5,
                  "helpful": "up",
                  "more_help_with": "side_effects",
                  "comment": "Maya's tips for nausea made a real difference."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Answered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackRequest"
                },
                "example": {
                  "id": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6",
                  "status": "answered",
                  "care_role": "health_coach",
                  "coach": {
                    "care_role": "health_coach",
                    "display_name": "Maya C.",
                    "title": "Health Coach",
                    "credentials": [
                      "RD"
                    ],
                    "assigned_at": "2026-09-15T10:00:00Z"
                  },
                  "survey": {
                    "code": "coach_feedback",
                    "version": 1,
                    "title": "How is coaching going?",
                    "intro": "It takes less than a minute.",
                    "questions": [
                      {
                        "key": "overall",
                        "kind": "rating",
                        "label": "How would you rate your coach so far?",
                        "required": true,
                        "scale_max": 5
                      }
                    ]
                  },
                  "requested_at": "2026-10-27T15:00:00Z",
                  "expires_at": "2026-11-10T15:00:00Z",
                  "answers": {
                    "overall": 5,
                    "helpful": "up",
                    "more_help_with": "side_effects",
                    "comment": "Maya's tips for nausea made a real difference."
                  },
                  "answered_at": "2026-10-27T15:02:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/feedback-requests/{feedback_request_id}/dismiss": {
      "parameters": [
        {
          "$ref": "#/components/parameters/FeedbackRequestId"
        }
      ],
      "post": {
        "operationId": "dismissMyFeedbackRequest",
        "tags": [
          "Feedback"
        ],
        "summary": "Dismiss a feedback popup",
        "description": "The patient closed the popup without answering; it won't be offered again. Error code:\n`feedback_request_closed` (409) once answered, dismissed or expired.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "responses": {
          "200": {
            "description": "Dismissed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackRequest"
                },
                "example": {
                  "id": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6",
                  "status": "dismissed",
                  "care_role": "health_coach",
                  "coach": {
                    "care_role": "health_coach",
                    "display_name": "Maya C.",
                    "title": "Health Coach",
                    "credentials": [
                      "RD"
                    ],
                    "assigned_at": "2026-09-15T10:00:00Z"
                  },
                  "survey": {
                    "code": "coach_feedback",
                    "version": 1,
                    "title": "How is coaching going?",
                    "intro": "It takes less than a minute.",
                    "questions": [
                      {
                        "key": "overall",
                        "kind": "rating",
                        "label": "How would you rate your coach so far?",
                        "required": true,
                        "scale_max": 5
                      }
                    ]
                  },
                  "requested_at": "2026-10-27T15:00:00Z",
                  "expires_at": "2026-11-10T15:00:00Z",
                  "answers": null,
                  "answered_at": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/ai-coach/conversations": {
      "get": {
        "operationId": "listAiCoachConversations",
        "tags": [
          "AI Coach"
        ],
        "summary": "List my AI Coach chats",
        "description": "The patient's chats with the AI Coach, most recent first. A patient can have many.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of chats.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCoachConversationList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5cc-3c4d-7e5f-8061-7a8b9c0d1e23",
                      "title": "Dinner ideas",
                      "created_at": "2026-10-26T11:00:00Z",
                      "last_message_at": "2026-10-26T11:01:30Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "createAiCoachConversation",
        "tags": [
          "AI Coach"
        ],
        "summary": "Start an AI Coach chat",
        "description": "Opens a new chat. The AI Coach remembers confirmed preferences across chats.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiCoachConversationCreate"
              },
              "example": {
                "title": "Dinner ideas"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCoachConversation"
                },
                "example": {
                  "id": "0190f5cc-3c4d-7e5f-8061-7a8b9c0d1e23",
                  "title": "Dinner ideas",
                  "created_at": "2026-10-26T11:00:00Z",
                  "last_message_at": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/ai-coach/conversations/{conversation_id}/messages": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ConversationId"
        }
      ],
      "get": {
        "operationId": "listAiCoachMessages",
        "tags": [
          "AI Coach"
        ],
        "summary": "List messages in an AI Coach chat",
        "description": "Newest first, the patient's messages and the AI Coach's replies.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of messages.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5cc-5e6f-7071-9283-9c0d1e2f3a45",
                      "conversation_id": "0190f5cc-3c4d-7e5f-8061-7a8b9c0d1e23",
                      "sender": {
                        "type": "ai",
                        "display_name": "AI Coach",
                        "care_role": null
                      },
                      "body": "Try a chicken and quinoa bowl tonight. It keeps you near 38 g of protein.",
                      "created_at": "2026-10-26T11:01:30Z",
                      "edited_at": null,
                      "deleted": false,
                      "seen_by_other_side": true,
                      "attachment": null,
                      "reactions": [],
                      "feedback": {
                        "rating": "up",
                        "note": null
                      }
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "sendAiCoachMessage",
        "tags": [
          "AI Coach"
        ],
        "summary": "Message the AI Coach",
        "description": "Stores the patient's message and starts the AI Coach's reply. The response has the stored message and the reply in\n`pending`; get the reply with `GET /v1/patient/ai-coach/messages/{message_id}/reply`, by polling or as a stream.\n\nThe AI Coach is not emergency care. Show the 911 and 988 guidance next to the message box. When the AI Coach escalates (a red-flag\nsymptom, a dosing or medication question, a new or severe side effect), the reply carries `escalation`:\non `ai_only` it is a clinical flag to the brand's prescriber, on the coached plan a task for the coach.\n\nWhen the AI Coach is paused for the plan, the reply is the plan's holding message. Error codes:\n`daily_message_cap_reached` (429), `ai_unavailable` (503).\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageInput"
              },
              "example": {
                "body": "What can I eat tonight instead of salmon?"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Message stored; the reply is on its way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCoachMessageAccepted"
                },
                "example": {
                  "message": {
                    "id": "0190f5cc-4d5e-7f60-8172-8b9c0d1e2f34",
                    "conversation_id": "0190f5cc-3c4d-7e5f-8061-7a8b9c0d1e23",
                    "sender": {
                      "type": "patient",
                      "display_name": "Jordan",
                      "care_role": null
                    },
                    "body": "What can I eat tonight instead of salmon?",
                    "created_at": "2026-10-26T11:01:00Z",
                    "edited_at": null,
                    "deleted": false,
                    "seen_by_other_side": false,
                    "attachment": null,
                    "reactions": [],
                    "feedback": null
                  },
                  "reply": {
                    "reply_to_message_id": "0190f5cc-4d5e-7f60-8172-8b9c0d1e2f34",
                    "status": "pending",
                    "message": null,
                    "escalation": null,
                    "show_emergency_guidance": false
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/patient/ai-coach/messages/{message_id}/reply": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MessageId"
        }
      ],
      "get": {
        "operationId": "getAiCoachReply",
        "tags": [
          "AI Coach"
        ],
        "summary": "Get the AI Coach's reply",
        "description": "`message_id` is the patient's message. Two ways to read the reply:\n\n* **Poll** with `Accept: application/json` every 1-2 seconds until `status` is `completed` or `failed`.\n* **Stream** with `Accept: text/event-stream` (Server-Sent Events). Events: `delta` (`{\"text\": \"...\"}`, the\n  next piece of the reply), then one `completed` with the full `AiCoachReply`, or `error` with a problem document.\n  Guardrails run before text is streamed, so a blocked reply never streams.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The reply's state, or the stream.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCoachReply"
                },
                "examples": {
                  "completed": {
                    "summary": "Reply ready",
                    "value": {
                      "reply_to_message_id": "0190f5cc-4d5e-7f60-8172-8b9c0d1e2f34",
                      "status": "completed",
                      "message": {
                        "id": "0190f5cc-5e6f-7071-9283-9c0d1e2f3a45",
                        "conversation_id": "0190f5cc-3c4d-7e5f-8061-7a8b9c0d1e23",
                        "sender": {
                          "type": "ai",
                          "display_name": "AI Coach",
                          "care_role": null
                        },
                        "body": "Try a chicken and quinoa bowl tonight. It keeps you near 38 g of protein.",
                        "created_at": "2026-10-26T11:01:30Z",
                        "edited_at": null,
                        "deleted": false,
                        "seen_by_other_side": false,
                        "attachment": null,
                        "reactions": [],
                        "feedback": null
                      },
                      "escalation": null,
                      "show_emergency_guidance": false
                    }
                  },
                  "escalated": {
                    "summary": "Escalated to the prescriber (ai_only)",
                    "value": {
                      "reply_to_message_id": "0190f5cc-6f70-7182-a394-0d1e2f3a4b56",
                      "status": "completed",
                      "message": {
                        "id": "0190f5cc-7081-7293-84a5-1e2f3a4b5c67",
                        "conversation_id": "0190f5cc-3c4d-7e5f-8061-7a8b9c0d1e23",
                        "sender": {
                          "type": "ai",
                          "display_name": "AI Coach",
                          "care_role": null
                        },
                        "body": "I can't advise on changing your dose. I've let your prescriber's team know so they can follow up with you.",
                        "created_at": "2026-10-26T11:05:10Z",
                        "edited_at": null,
                        "deleted": false,
                        "seen_by_other_side": false,
                        "attachment": null,
                        "reactions": [],
                        "feedback": null
                      },
                      "escalation": {
                        "to": "prescriber",
                        "notice": "I've let your prescriber's team know so they can follow up with you."
                      },
                      "show_emergency_guidance": false
                    }
                  }
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Server-Sent Events, as described above."
                },
                "example": "event: delta\ndata: {\"text\": \"Try a chicken and quinoa bowl\"}\n\nevent: delta\ndata: {\"text\": \" tonight.\"}\n\nevent: completed\ndata: {\"reply_to_message_id\": \"0190f5cc-4d5e-7f60-8172-8b9c0d1e2f34\", \"status\": \"completed\", \"show_emergency_guidance\": false}\n"
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/ai-coach/messages/{message_id}/feedback": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MessageId"
        }
      ],
      "put": {
        "operationId": "rateAiCoachMessage",
        "tags": [
          "AI Coach"
        ],
        "summary": "Rate an AI Coach reply",
        "description": "Thumbs up or down on one of the AI Coach's messages, with an optional note. Rating again replaces it. Error code `not_an_ai_message` (422).\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeedbackInput"
              },
              "example": {
                "rating": "down",
                "note": "The swap still had fish in it"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The rating.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feedback"
                },
                "example": {
                  "message_id": "0190f5cc-5e6f-7071-9283-9c0d1e2f3a45",
                  "rating": "down",
                  "note": "The swap still had fish in it"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/ai-coach/memories": {
      "get": {
        "operationId": "listAiCoachMemories",
        "tags": [
          "AI Coach"
        ],
        "summary": "List what the AI Coach remembers",
        "description": "Things the AI Coach remembers from the patient's chats, such as foods they dislike or when they like to work out,\nso the patient can check them. Brands never see them.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "Everything the AI Coach currently remembers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCoachMemoryList"
                },
                "example": {
                  "data": [
                    {
                      "id": "6c8e0a2b-4d6f-4a1c-8e3b-5d7f9a1c3e5b",
                      "summary": "Doesn't like fish",
                      "confirmed": false,
                      "created_at": "2026-10-24T18:20:00Z",
                      "updated_at": "2026-10-24T18:20:00Z"
                    },
                    {
                      "id": "7d9f1b3c-5e7a-4b2d-9f4c-6e8a0b2d4f6c",
                      "summary": "Prefers to work out before breakfast",
                      "confirmed": true,
                      "created_at": "2026-10-22T07:05:00Z",
                      "updated_at": "2026-10-23T08:00:00Z"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/ai-coach/memories/{memory_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/MemoryId"
        }
      ],
      "patch": {
        "operationId": "updateAiCoachMemory",
        "tags": [
          "AI Coach"
        ],
        "summary": "Confirm a memory",
        "description": "The patient confirms that a memory is right (or takes the confirmation back). To correct a memory, delete it and tell the AI Coach.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/AiCoachMemoryUpdate"
              },
              "example": {
                "confirmed": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The memory.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCoachMemory"
                },
                "example": {
                  "id": "6c8e0a2b-4d6f-4a1c-8e3b-5d7f9a1c3e5b",
                  "summary": "Doesn't like fish",
                  "confirmed": true,
                  "created_at": "2026-10-24T18:20:00Z",
                  "updated_at": "2026-10-26T10:00:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "deleteAiCoachMemory",
        "tags": [
          "AI Coach"
        ],
        "summary": "Forget a memory",
        "description": "The AI Coach stops using it at once. Deleting it again returns `204`.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "204": {
            "description": "Forgotten.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/reminders": {
      "get": {
        "operationId": "listMyReminders",
        "tags": [
          "Reminders"
        ],
        "summary": "List my reminders",
        "description": "Injection days, check-in forms, logging nudges and habits. Brand apps also receive `reminder.due` and send the\nnotification in their own words; this list is for showing what is coming.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "scheduled",
                "sent",
                "cancelled"
              ],
              "default": "scheduled"
            },
            "example": "scheduled"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of reminders.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReminderList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5c5-4a5b-7c61-8d78-9e0f1a2b3c45",
                      "kind": "injection",
                      "ref_key": null,
                      "due_at": "2026-11-02T13:00:00Z",
                      "status": "scheduled",
                      "recurring": true
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/reminders/{reminder_id}/snooze": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ReminderId"
        }
      ],
      "post": {
        "operationId": "snoozeReminder",
        "tags": [
          "Reminders"
        ],
        "summary": "Snooze a reminder",
        "description": "Moves a scheduled or just-sent reminder later by `minutes` (5 minutes to 24 hours). Error code `reminder_not_snoozable` (409) once cancelled.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Snooze"
              },
              "example": {
                "minutes": 60
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The rescheduled reminder.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reminder"
                },
                "example": {
                  "id": "0190f5c5-4a5b-7c61-8d78-9e0f1a2b3c45",
                  "kind": "injection",
                  "ref_key": null,
                  "due_at": "2026-11-02T14:00:00Z",
                  "status": "scheduled",
                  "recurring": true
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/patient/reminder-settings": {
      "get": {
        "operationId": "getMyReminderSettings",
        "tags": [
          "Reminders"
        ],
        "summary": "Get my reminder settings",
        "description": "Which reminders are on, when they are sent, and quiet hours. Anything the patient has not set shows the brand's default.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "responses": {
          "200": {
            "description": "The settings in force.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReminderSettings"
                },
                "example": {
                  "injection": {
                    "enabled": true,
                    "time": "09:00"
                  },
                  "check_in": {
                    "enabled": true
                  },
                  "log_nudge": {
                    "enabled": true,
                    "time": "19:30"
                  },
                  "habit": {
                    "enabled": true,
                    "time": "08:00"
                  },
                  "ai_coach_outreach": {
                    "enabled": true
                  },
                  "quiet_hours": {
                    "start": "21:30",
                    "end": "07:30"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "patch": {
        "operationId": "updateMyReminderSettings",
        "tags": [
          "Reminders"
        ],
        "summary": "Change my reminder settings",
        "description": "Turning a kind off cancels its scheduled reminders and stops `reminder.due` for it, so a brand app sends fewer\nnotifications too; turning it back on schedules the next one. A new time applies from the next reminder. The\nsettings belong to the patient and carry over to a later enrollment with the same brand.\n\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
        "security": [
          {
            "patientToken": []
          }
        ],
        "x-plans": [
          "ai_health_fitness",
          "ai_only"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/ReminderSettingsUpdate"
              },
              "example": {
                "habit": {
                  "enabled": false
                },
                "quiet_hours": {
                  "start": "21:30",
                  "end": "07:30"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The settings in force after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReminderSettings"
                },
                "example": {
                  "injection": {
                    "enabled": true,
                    "time": "09:00"
                  },
                  "check_in": {
                    "enabled": true
                  },
                  "log_nudge": {
                    "enabled": true,
                    "time": "19:30"
                  },
                  "habit": {
                    "enabled": false,
                    "time": "08:00"
                  },
                  "ai_coach_outreach": {
                    "enabled": true
                  },
                  "quiet_hours": {
                    "start": "21:30",
                    "end": "07:30"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/clinical-flags": {
      "get": {
        "operationId": "listClinicalFlags",
        "tags": [
          "Clinical flags"
        ],
        "summary": "List clinical flags",
        "description": "Your brand's flags, oldest first so the longest-waiting come first. By default only those needing action\n(`open` and `acknowledged`). On the AI-only plan every escalation lands here, so poll this as a backstop to\nthe `clinical.flag_raised` webhook.\n",
        "security": [
          {
            "clinicalClient": [
              "clinical:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "One or more statuses, comma-separated.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/ClinicalFlagStatus"
              },
              "default": [
                "open",
                "acknowledged"
              ]
            },
            "example": [
              "open"
            ]
          },
          {
            "name": "severity",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/Severity"
            },
            "example": "critical"
          },
          {
            "name": "enrollment_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
          },
          {
            "name": "external_patient_id",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/ExternalId"
            },
            "example": "brand-pt-48213"
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only flags changed after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-26T00:00:00Z"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of flags.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalFlagList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                      "status": "open",
                      "severity": "critical",
                      "title": "Acute GI distress",
                      "rule_code": "acute_gi",
                      "source": "alert_rule",
                      "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                      "external_patient_id": "brand-pt-48213",
                      "plan_code": "ai_only",
                      "risk_level": "high",
                      "raised_risk_to": "high",
                      "details": {
                        "symptom": "vomiting",
                        "severity_score": 4,
                        "escalation_reason": null,
                        "values": {}
                      },
                      "triggering_records": [
                        {
                          "type": "symptom_log",
                          "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                          "occurred_at": "2026-10-26T13:50:00Z"
                        }
                      ],
                      "timeline": [
                        {
                          "occurred_at": "2026-10-26T08:00:00Z",
                          "kind": "injection",
                          "dose_mg": 0.5
                        },
                        {
                          "occurred_at": "2026-10-26T13:50:00Z",
                          "kind": "symptom",
                          "symptom": "vomiting",
                          "severity": 4,
                          "text": "Could not keep water down this morning"
                        }
                      ],
                      "treatment": {
                        "medication": {
                          "ingredient": "semaglutide",
                          "product_name": "Wegovy",
                          "source": "branded",
                          "route": "injection"
                        },
                        "dose_mg": 0.5,
                        "dose_amount": null,
                        "dose_unit": null,
                        "phase": "titration",
                        "injection_weekday": 1,
                        "started_on": "2026-09-28",
                        "treatment_week": 5,
                        "effective_from": "2026-10-26T00:00:00Z"
                      },
                      "coach_note": null,
                      "ack_due_at": "2026-10-26T16:05:00Z",
                      "redelivery_count": 0,
                      "acknowledgement": null,
                      "resolution": null,
                      "created_at": "2026-10-26T14:05:00Z",
                      "updated_at": "2026-10-26T14:05:00Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/clinical-flags/{flag_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ClinicalFlagId"
        }
      ],
      "get": {
        "operationId": "getClinicalFlag",
        "tags": [
          "Clinical flags"
        ],
        "summary": "Get a clinical flag",
        "description": "Symptom, severity, the triggering records, a timeline around them, the treatment and any coach note.",
        "security": [
          {
            "clinicalClient": [
              "clinical:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The flag.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalFlag"
                },
                "example": {
                  "id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                  "status": "open",
                  "severity": "critical",
                  "title": "Dosing question escalated by the AI Coach",
                  "rule_code": null,
                  "source": "ai_coach_escalation",
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "plan_code": "ai_only",
                  "risk_level": "elevated",
                  "raised_risk_to": "elevated",
                  "details": {
                    "symptom": null,
                    "severity_score": null,
                    "escalation_reason": "dosing_question",
                    "values": {}
                  },
                  "triggering_records": [
                    {
                      "type": "message",
                      "id": "0190f5cc-6f70-7182-a394-0d1e2f3a4b56",
                      "occurred_at": "2026-10-26T11:05:00Z"
                    }
                  ],
                  "timeline": [
                    {
                      "occurred_at": "2026-10-26T11:05:00Z",
                      "kind": "ai_coach_escalation",
                      "text": "Patient asked whether to take a second dose this week after missing Monday."
                    }
                  ],
                  "treatment": null,
                  "coach_note": null,
                  "ack_due_at": "2026-10-26T13:05:00Z",
                  "redelivery_count": 1,
                  "acknowledgement": null,
                  "resolution": null,
                  "created_at": "2026-10-26T11:05:10Z",
                  "updated_at": "2026-10-26T13:05:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/clinical-flags/{flag_id}/acknowledge": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ClinicalFlagId"
        }
      ],
      "post": {
        "operationId": "acknowledgeClinicalFlag",
        "tags": [
          "Clinical flags"
        ],
        "summary": "Acknowledge a flag",
        "description": "Tells TeraRx a prescriber has the flag, which stops re-delivery. It does not change risk.\nAcknowledging again returns the flag unchanged. Fires `clinical.flag_acknowledged`.\nError codes: `flag_closed` (409) once resolved or dismissed, `validation_failed` (422) without `name` and `npi` or `prescriber_id`.\n",
        "security": [
          {
            "clinicalClient": [
              "clinical:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AcknowledgeInput"
              },
              "example": {
                "on_behalf_of": {
                  "npi": "1234567893",
                  "name": "Dr. Alex Morgan, NP"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The acknowledged flag.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalFlag"
                },
                "example": {
                  "id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                  "status": "acknowledged",
                  "severity": "critical",
                  "title": "Acute GI distress",
                  "rule_code": "acute_gi",
                  "source": "alert_rule",
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "plan_code": "ai_only",
                  "risk_level": "high",
                  "raised_risk_to": "high",
                  "details": {
                    "symptom": "vomiting",
                    "severity_score": 4,
                    "escalation_reason": null,
                    "values": {}
                  },
                  "triggering_records": [
                    {
                      "type": "symptom_log",
                      "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                      "occurred_at": "2026-10-26T13:50:00Z"
                    }
                  ],
                  "timeline": [],
                  "treatment": null,
                  "coach_note": null,
                  "ack_due_at": "2026-10-26T16:05:00Z",
                  "redelivery_count": 0,
                  "acknowledgement": {
                    "at": "2026-10-26T14:20:00Z",
                    "by": {
                      "npi": "1234567893",
                      "name": "Dr. Alex Morgan, NP"
                    }
                  },
                  "resolution": null,
                  "created_at": "2026-10-26T14:05:00Z",
                  "updated_at": "2026-10-26T14:20:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/clinical-flags/{flag_id}/resolve": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ClinicalFlagId"
        }
      ],
      "post": {
        "operationId": "resolveClinicalFlag",
        "tags": [
          "Clinical flags"
        ],
        "summary": "Resolve a flag",
        "description": "Records the prescriber's decision and sets the enrollment's risk level to `new_risk_level`. This is the only\nway risk goes down. Resolving an open flag acknowledges it too. Fires `clinical.flag_resolved`.\nError codes: `flag_closed` (409) once resolved or dismissed, `validation_failed` (422).\n",
        "security": [
          {
            "clinicalClient": [
              "clinical:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResolveInput"
              },
              "example": {
                "on_behalf_of": {
                  "npi": "1234567893",
                  "name": "Dr. Alex Morgan, NP"
                },
                "resolution_note": "Spoke with patient. Holding at 0.5 mg for two more weeks; antiemetic prescribed.",
                "new_risk_level": "elevated"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The resolved flag.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalFlag"
                },
                "example": {
                  "id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                  "status": "resolved",
                  "severity": "critical",
                  "title": "Acute GI distress",
                  "rule_code": "acute_gi",
                  "source": "alert_rule",
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "plan_code": "ai_only",
                  "risk_level": "elevated",
                  "raised_risk_to": "high",
                  "details": {
                    "symptom": "vomiting",
                    "severity_score": 4,
                    "escalation_reason": null,
                    "values": {}
                  },
                  "triggering_records": [
                    {
                      "type": "symptom_log",
                      "id": "0190f5c9-7f80-7192-8cb4-3d4e5f607182",
                      "occurred_at": "2026-10-26T13:50:00Z"
                    }
                  ],
                  "timeline": [],
                  "treatment": null,
                  "coach_note": null,
                  "ack_due_at": "2026-10-26T16:05:00Z",
                  "redelivery_count": 0,
                  "acknowledgement": {
                    "at": "2026-10-26T14:20:00Z",
                    "by": {
                      "npi": "1234567893",
                      "name": "Dr. Alex Morgan, NP"
                    }
                  },
                  "resolution": {
                    "at": "2026-10-26T15:10:00Z",
                    "by": {
                      "npi": "1234567893",
                      "name": "Dr. Alex Morgan, NP"
                    },
                    "resolution_note": "Spoke with patient. Holding at 0.5 mg for two more weeks; antiemetic prescribed.",
                    "new_risk_level": "elevated"
                  },
                  "created_at": "2026-10-26T14:05:00Z",
                  "updated_at": "2026-10-26T15:10:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
                "schema": {
                  "type": "string"
                },
                "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per minute for this client (600 by default, set per contract).",
                "schema": {
                  "type": "integer"
                },
                "example": 600
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                },
                "example": 587
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                },
                "example": 42
              },
              "Idempotent-Replayed": {
                "description": "`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.",
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "webhooks": {
    "enrollment.created": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onEnrollmentCreated",
        "tags": [
          "Webhooks"
        ],
        "summary": "enrollment.created",
        "description": "A new enrollment, after `POST /v1/enrollments` (or a TeraRx Direct signup).",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentCreatedEvent"
              },
              "example": {
                "id": "0190f5d0-1a2b-7c3d-8e4f-5a6b7c8d9e01",
                "type": "enrollment.created",
                "created_at": "2026-10-21T14:58:02Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "external_order_id": "ord-2026-10-000123",
                  "plan_code": "ai_health_fitness",
                  "status": "active",
                  "stage": "created"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "enrollment.stage_changed": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onEnrollmentStageChanged",
        "tags": [
          "Webhooks"
        ],
        "summary": "enrollment.stage_changed",
        "description": "The enrollment moved along `created → awaiting_assignment → assigned → onboarding_pending → onboarding_completed → protocols_active`.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentStageChangedEvent"
              },
              "example": {
                "id": "0190f5d0-2b3c-7d4e-8f50-6a7b8c9d0e12",
                "type": "enrollment.stage_changed",
                "created_at": "2026-10-22T09:30:01Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "from": "onboarding_pending",
                  "to": "onboarding_completed"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "enrollment.paused": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onEnrollmentPaused",
        "tags": [
          "Webhooks"
        ],
        "summary": "enrollment.paused",
        "description": "The enrollment was paused. Paused days are not billed.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentPausedEvent"
              },
              "example": {
                "id": "0190f5d0-3c4d-7e5f-8061-7b8c9d0e1f23",
                "type": "enrollment.paused",
                "created_at": "2026-11-01T10:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "enrollment.resumed": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onEnrollmentResumed",
        "tags": [
          "Webhooks"
        ],
        "summary": "enrollment.resumed",
        "description": "The enrollment is active again.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentResumedEvent"
              },
              "example": {
                "id": "0190f5d0-4d5e-7f60-9172-8c9d0e1f2a34",
                "type": "enrollment.resumed",
                "created_at": "2026-11-15T08:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "enrollment.cancelled": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onEnrollmentCancelled",
        "tags": [
          "Webhooks"
        ],
        "summary": "enrollment.cancelled",
        "description": "The enrollment ended. The retention period for the patient's records starts.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentCancelledEvent"
              },
              "example": {
                "id": "0190f5d0-5e6f-7071-8283-9d0e1f2a3b45",
                "type": "enrollment.cancelled",
                "created_at": "2026-12-21T00:00:05Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "ended_at": "2026-12-21T00:00:00Z",
                  "cancel_reason": "subscription_ended"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "care_team.assigned": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onCareTeamAssigned",
        "tags": [
          "Webhooks"
        ],
        "summary": "care_team.assigned",
        "description": "A coach was assigned to a care role (coached plan). Coach identity is not sent.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CareTeamAssignedEvent"
              },
              "example": {
                "id": "0190f5d1-1a2b-7c3d-8e4f-5a6b7c8d9e02",
                "type": "care_team.assigned",
                "created_at": "2026-10-21T15:10:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "care_role": "health_coach",
                  "assigned_at": "2026-10-21T15:10:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "care_team.changed": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onCareTeamChanged",
        "tags": [
          "Webhooks"
        ],
        "summary": "care_team.changed",
        "description": "A care role was reassigned to another coach, or ended (for example on a move to `ai_only`). `reason_code` says why,\nfor example `state_change` after you updated the patient's state.\n",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CareTeamChangedEvent"
              },
              "example": {
                "id": "0190f5d1-2b3c-7d4e-8f50-6a7b8c9d0e13",
                "type": "care_team.changed",
                "created_at": "2026-11-03T12:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "care_role": "fitness_coach",
                  "change": "reassigned",
                  "reason_code": "coach_unavailable",
                  "changed_at": "2026-11-03T12:00:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "care_team.capacity_warning": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onCareTeamCapacityWarning",
        "tags": [
          "Webhooks"
        ],
        "summary": "care_team.capacity_warning",
        "description": "No coach with a license in the patient's state and free capacity is available, so the enrollment is waiting.\nBrands on `brand_coaches` never fall back to the TeraRx pool.\n",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CareTeamCapacityWarningEvent"
              },
              "example": {
                "id": "0190f5d1-3c4d-7e5f-9061-7b8c9d0e1f24",
                "type": "care_team.capacity_warning",
                "created_at": "2026-10-21T19:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "care_role": "fitness_coach",
                  "state_code": "NY",
                  "waiting_since": "2026-10-21T14:58:02Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "care_team.feedback_due": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onCareTeamFeedbackDue",
        "tags": [
          "Webhooks"
        ],
        "summary": "care_team.feedback_due",
        "description": "TeraRx would like the patient's feedback on the coach in `care_role`. Show your feedback popup: read its content with\n`GET /v1/patient/feedback-requests/{feedback_request_id}` and send the answers with\n`POST /v1/patient/feedback-requests/{feedback_request_id}/response`. TeraRx decides when to ask.\n",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CareTeamFeedbackDueEvent"
              },
              "example": {
                "id": "0190f5e3-5d6e-7f80-8a91-c2d3e4f5a6b7",
                "type": "care_team.feedback_due",
                "created_at": "2026-10-27T15:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "feedback_request_id": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6",
                  "care_role": "health_coach",
                  "expires_at": "2026-11-10T15:00:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "form.requested": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onFormRequested",
        "tags": [
          "Webhooks"
        ],
        "summary": "form.requested",
        "description": "A form was sent to the patient. Prompt them in your app; they fill it in with `GET /v1/patient/forms/{form_assignment_id}`.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormRequestedEvent"
              },
              "example": {
                "id": "0190f5d1-4d5e-7f60-8172-8c9d0e1f2a35",
                "type": "form.requested",
                "created_at": "2026-10-21T15:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "form_assignment_id": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2",
                  "form_code": "glp1_onboarding",
                  "purpose": "onboarding",
                  "due_at": "2026-10-24T15:00:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "onboarding.completed": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onOnboardingCompleted",
        "tags": [
          "Webhooks"
        ],
        "summary": "onboarding.completed",
        "description": "Every blocking onboarding form is done. Protocol drafting starts.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OnboardingCompletedEvent"
              },
              "example": {
                "id": "0190f5d1-5e6f-7071-9283-9d0e1f2a3b46",
                "type": "onboarding.completed",
                "created_at": "2026-10-22T09:30:01Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "completed_at": "2026-10-22T09:30:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "protocol.published": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onProtocolPublished",
        "tags": [
          "Webhooks"
        ],
        "summary": "protocol.published",
        "description": "The first version of a protocol type is live. The patient reads it with `GET /v1/patient/protocols/{protocol_type}`.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProtocolPublishedEvent"
              },
              "example": {
                "id": "0190f5d1-6f70-7182-a394-0e1f2a3b4c57",
                "type": "protocol.published",
                "created_at": "2026-10-23T16:45:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "protocol_id": "0190f5c6-7a8b-7c90-8d12-3e4f5a6b7c8d",
                  "protocol_type": "nutrition",
                  "version": 1,
                  "published_at": "2026-10-23T16:45:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "protocol.updated": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onProtocolUpdated",
        "tags": [
          "Webhooks"
        ],
        "summary": "protocol.updated",
        "description": "A new version replaced the active protocol of a type (for example after a dose change).",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProtocolUpdatedEvent"
              },
              "example": {
                "id": "0190f5d1-7081-7293-84a5-1f2a3b4c5d68",
                "type": "protocol.updated",
                "created_at": "2026-10-25T08:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "protocol_id": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90",
                  "protocol_type": "nutrition",
                  "version": 2,
                  "published_at": "2026-10-25T08:00:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "message.created": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onMessageCreated",
        "tags": [
          "Webhooks"
        ],
        "summary": "message.created",
        "description": "A new message in a care thread or from the AI Coach, so your app can notify the patient. Ids only: the body is never\nsent. Keep push notification text generic (\"You have a new message\").\n",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageCreatedEvent"
              },
              "example": {
                "id": "0190f5d1-8192-73a4-95b6-2a3b4c5d6e79",
                "type": "message.created",
                "created_at": "2026-10-26T13:40:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "conversation_id": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12",
                  "message_id": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23",
                  "conversation_kind": "care",
                  "sender_type": "coach"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "clinical.flag_raised": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onClinicalFlagRaised",
        "tags": [
          "Webhooks"
        ],
        "summary": "clinical.flag_raised",
        "description": "A clinical flag for your prescriber. Read it with the clinical client (`GET /v1/clinical-flags/{flag_id}`) and\nacknowledge it before `ack_due_at`.\n\nSent when an alert rule set to notify the brand fires, and on the AI-only plan for **every** alert that raises\nthe risk level and every AI Coach escalation, whatever the rule says: there is no coach to reach.\nEmergencies are never handled by flag; the patient is told to call 911 or 988.\n",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClinicalFlagRaisedEvent"
              },
              "example": {
                "id": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7",
                "type": "clinical.flag_raised",
                "created_at": "2026-10-26T14:05:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "flag_id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                  "severity": "critical",
                  "raised_risk_to": "high",
                  "ack_due_at": "2026-10-26T16:05:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "clinical.flag_redelivered": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onClinicalFlagRedelivered",
        "tags": [
          "Webhooks"
        ],
        "summary": "clinical.flag_redelivered",
        "description": "A flag passed its `ack_due_at` without an acknowledgement. It stays open, gets a new deadline and is sent again\nwith a new event id (so your dedupe does not drop it), until a prescriber acknowledges it. Escalate internally.\n",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClinicalFlagRedeliveredEvent"
              },
              "example": {
                "id": "0190f5e0-1b2c-7d3e-8f4a-5b6c7d8e9f01",
                "type": "clinical.flag_redelivered",
                "created_at": "2026-10-26T16:05:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "flag_id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                  "severity": "critical",
                  "ack_due_at": "2026-10-26T18:05:00Z",
                  "redelivery_count": 1,
                  "first_raised_at": "2026-10-26T14:05:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "clinical.flag_acknowledged": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onClinicalFlagAcknowledged",
        "tags": [
          "Webhooks"
        ],
        "summary": "clinical.flag_acknowledged",
        "description": "A prescriber acknowledged the flag. Re-delivery stops.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClinicalFlagAcknowledgedEvent"
              },
              "example": {
                "id": "0190f5e1-0a1b-7c2d-9e3f-4a5b6c7d8e9f",
                "type": "clinical.flag_acknowledged",
                "created_at": "2026-10-26T14:20:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "flag_id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                  "acknowledged_at": "2026-10-26T14:20:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "clinical.flag_resolved": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onClinicalFlagResolved",
        "tags": [
          "Webhooks"
        ],
        "summary": "clinical.flag_resolved",
        "description": "A prescriber resolved the flag and set the enrollment's risk level to `new_risk_level`.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClinicalFlagResolvedEvent"
              },
              "example": {
                "id": "0190f5e2-1c2d-7e3f-8a4b-5c6d7e8f9a02",
                "type": "clinical.flag_resolved",
                "created_at": "2026-10-26T15:10:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "flag_id": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6",
                  "resolved_at": "2026-10-26T15:10:00Z",
                  "new_risk_level": "elevated"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "patient.disengaged": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onPatientDisengaged",
        "tags": [
          "Webhooks"
        ],
        "summary": "patient.disengaged",
        "description": "No logs or messages for your brand's `disengaged_after_days` (7 by default). A nudge from your app may help.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatientDisengagedEvent"
              },
              "example": {
                "id": "0190f5d0-6f70-7182-9394-0e1f2a3b4c56",
                "type": "patient.disengaged",
                "created_at": "2026-11-09T06:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "last_activity_at": "2026-11-02T13:40:00Z",
                  "inactive_days": 7
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "patient.milestone_reached": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onPatientMilestoneReached",
        "tags": [
          "Webhooks"
        ],
        "summary": "patient.milestone_reached",
        "description": "The patient reached a milestone. Celebrate it in your app: read the personal details with\n`GET /v1/patient/milestones/{milestone_id}` using the patient's token. Keep any push text generic.\n",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatientMilestoneReachedEvent"
              },
              "example": {
                "id": "0190f5e1-3b4c-7d5e-8f60-a1b2c3d4e5f6",
                "type": "patient.milestone_reached",
                "created_at": "2026-10-25T20:10:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "milestone_id": "0190f5e1-2a3b-7c4d-9e5f-6a7b8c9d0e1f",
                  "code": "protein_target_days_7",
                  "achieved_at": "2026-10-25T20:10:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "reminder.due": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onReminderDue",
        "tags": [
          "Webhooks"
        ],
        "summary": "reminder.due",
        "description": "A reminder is due. Send the notification in your own words, with no health details in the push text.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReminderDueEvent"
              },
              "example": {
                "id": "0190f5d1-92a3-74b5-86c7-3b4c5d6e7f8a",
                "type": "reminder.due",
                "created_at": "2026-11-02T13:00:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "reminder_id": "0190f5c5-4a5b-7c61-8d78-9e0f1a2b3c45",
                  "kind": "injection",
                  "due_at": "2026-11-02T13:00:00Z",
                  "form_assignment_id": null
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    },
    "data_request.completed": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WebhookTimestamp"
        },
        {
          "$ref": "#/components/parameters/WebhookSignature"
        },
        {
          "$ref": "#/components/parameters/WebhookEventId"
        }
      ],
      "post": {
        "operationId": "onDataRequestCompleted",
        "tags": [
          "Webhooks"
        ],
        "summary": "data_request.completed",
        "description": "A data request finished. For an export, get a download link with `POST /v1/data-requests/{data_request_id}/export-link`.",
        "security": [
          {
            "webhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DataRequestCompletedEvent"
              },
              "example": {
                "id": "0190f5d1-a3b4-75c6-97d8-4c5d6e7f8a9b",
                "type": "data_request.completed",
                "created_at": "2026-10-26T14:40:00Z",
                "tenant_id": "a0000000-0000-4000-8000-000000000002",
                "data": {
                  "enrollment_id": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "external_patient_id": "brand-pt-48213",
                  "data_request_id": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13",
                  "kind": "export",
                  "status": "completed"
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "$ref": "#/components/responses/WebhookReceived"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauthClientBasic": {
        "type": "http",
        "scheme": "basic",
        "description": "HTTP Basic with your `client_id` and `client_secret`, only on `POST /v1/oauth/token` for the\n`client_credentials` grant. You may send them as `client_id` and `client_secret` form fields instead.\n"
      },
      "brandServer": {
        "type": "oauth2",
        "description": "A brand's server, one OAuth client per brand and environment. Get a token with the\n`client_credentials` grant and send it as `Authorization: Bearer <token>`. Tokens last 1 hour.\nA brand server reads status and ids only; it never reads clinical content. A platform partner holds one\nclient for all its brands and gets one token per brand, naming it with `tenant_id`.\n",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "/v1/oauth/token",
            "scopes": {
              "enrollments:read": "Read enrollment status, stage, risk level, treatment mirror and consent records",
              "enrollments:write": "Create enrollments, change plan, pause, resume, cancel, update the treatment mirror and record consent proof",
              "logs:write": "Send logs the brand already holds (meals, workouts, symptoms, injections, weight and daily values)",
              "events:read": "Replay events with GET /v1/events",
              "reports:read": "Read the aggregate brand report",
              "data_requests:read": "Read data requests and download exports",
              "data_requests:write": "Create data requests and decide amendments",
              "patients:token_exchange": "Mint patient tokens. Needs a registered JWKS URL or public keys and a JWT issuer",
              "tenants:read": "List the brands this client may act for with GET /v1/tenants"
            }
          }
        }
      },
      "clinicalClient": {
        "type": "oauth2",
        "description": "The brand's prescriber system (its clinician tool or Beluga), with its own OAuth client separate from the\nbrand server's. Every write carries the individual prescriber in `on_behalf_of`. Tokens last 1 hour.\n",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "/v1/oauth/token",
            "scopes": {
              "clinical:read": "Read clinical flags with symptom, severity, timeline and coach note",
              "clinical:write": "Acknowledge and resolve clinical flags"
            }
          }
        }
      },
      "patientToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "A 15-minute token bound to one patient and one enrollment, issued by `POST /v1/oauth/token` with the\ntoken-exchange grant. Treat it as opaque. When it expires, exchange a fresh assertion; there is no refresh token.\n"
      },
      "webhookSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "TeraRx-Signature",
        "description": "Not a credential you send. TeraRx signs every webhook delivery with your webhook secret; verify\n`TeraRx-Signature` as described in \"Webhooks and signatures\".\n"
      }
    },
    "schemas": {
      "ClientCredentialsGrant": {
        "type": "object",
        "description": "OAuth 2.0 client credentials (RFC 6749 section 4.4), for brand servers and prescriber systems.",
        "required": [
          "grant_type"
        ],
        "properties": {
          "grant_type": {
            "type": "string",
            "const": "client_credentials"
          },
          "scope": {
            "type": "string",
            "description": "Space-separated scopes. Omit to get every scope the client holds. Asking for one it does not hold fails with `invalid_scope`.",
            "example": "enrollments:read enrollments:write logs:write"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid",
            "description": "The brand this token is for. Required for a platform partner's client, which acts for several brands and\ngets one token per brand (`tenant_required` without it, `tenant_not_permitted` for a brand it may not act for).\nA brand's own client may omit it or send its own tenant id.\n",
            "example": "a0000000-0000-4000-8000-000000000002"
          },
          "client_id": {
            "type": "string",
            "description": "Only when not using HTTP Basic.",
            "example": "demo_brand_integration"
          },
          "client_secret": {
            "type": "string",
            "description": "Only when not using HTTP Basic.",
            "example": "example-client-secret-not-real"
          }
        }
      },
      "TokenExchangeGrant": {
        "type": "object",
        "description": "OAuth 2.0 token exchange (RFC 8693). `subject_token` is a JWT the brand's server signed with its own private key\n(RFC 7523 profile). The API checks it against the brand's registered JWKS and returns a patient token.\nTeraRx never holds a key that can mint patient sessions. A platform partner's assertion names the brand in a\n`tenant_id` claim.\n",
        "required": [
          "grant_type",
          "subject_token",
          "subject_token_type"
        ],
        "properties": {
          "grant_type": {
            "type": "string",
            "const": "urn:ietf:params:oauth:grant-type:token-exchange"
          },
          "subject_token": {
            "type": "string",
            "description": "The signed patient assertion. See \"Patient assertion\" in this tag's description for the claims.",
            "example": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImRlbW8tMjAyNi0xMCJ9.<claims>.<signature>"
          },
          "subject_token_type": {
            "type": "string",
            "const": "urn:ietf:params:oauth:token-type:jwt"
          },
          "requested_token_type": {
            "type": "string",
            "const": "urn:ietf:params:oauth:token-type:access_token",
            "description": "Optional. The only supported value."
          }
        }
      },
      "TokenRequest": {
        "description": "One endpoint, two grants. `grant_type` picks the shape.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/ClientCredentialsGrant"
          },
          {
            "$ref": "#/components/schemas/TokenExchangeGrant"
          }
        ],
        "discriminator": {
          "propertyName": "grant_type",
          "mapping": {
            "client_credentials": "#/components/schemas/ClientCredentialsGrant",
            "urn:ietf:params:oauth:grant-type:token-exchange": "#/components/schemas/TokenExchangeGrant"
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "expires_in"
        ],
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Opaque to callers. Do not parse it.",
            "example": "trx_at_example_not_a_real_token"
          },
          "token_type": {
            "type": "string",
            "const": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds. 3600 for client tokens, 900 for patient tokens.",
            "example": 3600
          },
          "scope": {
            "type": "string",
            "description": "Space-separated scopes granted. Absent on patient tokens.",
            "example": "enrollments:read enrollments:write logs:write"
          },
          "issued_token_type": {
            "type": "string",
            "const": "urn:ietf:params:oauth:token-type:access_token",
            "description": "Token exchange only (RFC 8693)."
          }
        }
      },
      "ValidationIssue": {
        "type": "object",
        "required": [
          "pointer",
          "code"
        ],
        "properties": {
          "pointer": {
            "type": "string",
            "description": "JSON Pointer (RFC 6901) to the field in the request body, or `path:<name>`, `query:<name>` or `header:<name>` for a parameter.",
            "example": "/patient/state_code"
          },
          "code": {
            "type": "string",
            "enum": [
              "required",
              "invalid_type",
              "invalid_format",
              "out_of_range",
              "too_long",
              "unknown_value",
              "not_allowed"
            ],
            "example": "invalid_format"
          },
          "detail": {
            "type": "string",
            "description": "What the field must look like. Never repeats the value that was sent.",
            "example": "Must be a two-letter USPS state code."
          }
        }
      },
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details, sent as `application/problem+json` with every 4xx and 5xx.\nA problem never contains patient data: no names, no values from the request, no free text the caller sent.\n",
        "required": [
          "type",
          "title",
          "status",
          "code",
          "request_id"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri-reference",
            "description": "`about:blank` until the docs have a public home. Branch on `code`, not on `type` or `title`.",
            "example": "about:blank"
          },
          "title": {
            "type": "string",
            "description": "The HTTP status phrase.",
            "example": "Not Found"
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599,
            "example": 404
          },
          "detail": {
            "type": "string",
            "description": "What went wrong, in words safe to log.",
            "example": "No enrollment with this id is visible to this client."
          },
          "instance": {
            "type": "string",
            "format": "uri-reference",
            "description": "The path of the request that failed.",
            "example": "/v1/enrollments/0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
          },
          "code": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "Stable machine-readable code. New codes may be added; existing ones never change meaning.",
            "example": "enrollment_not_found"
          },
          "request_id": {
            "type": "string",
            "description": "Same value as the `X-Request-Id` response header. Quote it when you contact TeraRx.",
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "errors": {
            "type": "array",
            "description": "One entry per invalid field, for `validation_failed`.",
            "items": {
              "$ref": "#/components/schemas/ValidationIssue"
            }
          }
        }
      },
      "OAuthProblem": {
        "description": "A problem document that also carries the RFC 6749 `error` fields, so standard OAuth libraries can read it.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Problem"
          },
          {
            "type": "object",
            "required": [
              "error"
            ],
            "properties": {
              "error": {
                "type": "string",
                "enum": [
                  "invalid_request",
                  "invalid_client",
                  "invalid_grant",
                  "unauthorized_client",
                  "unsupported_grant_type",
                  "invalid_scope",
                  "invalid_target"
                ],
                "example": "invalid_grant"
              },
              "error_description": {
                "type": "string",
                "example": "The assertion has expired."
              }
            }
          }
        ]
      },
      "Uuid": {
        "type": "string",
        "format": "uuid",
        "example": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
      },
      "Tenant": {
        "type": "object",
        "description": "A brand on TeraRx. Each brand's patients and data are separate, including brands under one platform partner.",
        "required": [
          "id",
          "slug",
          "display_name",
          "is_enabled"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "slug": {
            "type": "string",
            "description": "Short stable name, set by TeraRx at onboarding.",
            "example": "northwind-health"
          },
          "display_name": {
            "type": "string",
            "example": "Northwind Health"
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Whether the brand is live. A token for a brand that is not live is refused with `tenant_not_permitted`.",
            "example": true
          }
        }
      },
      "NextCursor": {
        "type": [
          "string",
          "null"
        ],
        "description": "Pass it back as `cursor` for the next page. `null` on the last page.",
        "example": "eyJpZCI6IjAxOTBmNWMyIn0"
      },
      "TenantList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Ordered by `slug`.",
            "items": {
              "$ref": "#/components/schemas/Tenant"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "ExternalId": {
        "type": "string",
        "minLength": 1,
        "maxLength": 128,
        "pattern": "^[\\x21-\\x7E]+$",
        "description": "Your own identifier, printable ASCII without spaces.",
        "example": "brand-pt-48213"
      },
      "EnrollmentStatus": {
        "type": "string",
        "enum": [
          "pending_screening",
          "ineligible",
          "active",
          "paused",
          "cancelled",
          "completed"
        ],
        "example": "active"
      },
      "RiskLevel": {
        "type": "string",
        "enum": [
          "normal",
          "elevated",
          "high"
        ],
        "description": "Raised by clinical flags. Only a prescriber's resolve lowers it.",
        "example": "normal"
      },
      "PlanCode": {
        "type": "string",
        "enum": [
          "ai_only",
          "ai_health_fitness"
        ],
        "description": "* `ai_only`: the AI Coach only. Escalations go to the brand's prescriber as clinical flags.\n* `ai_health_fitness`: the AI Coach plus a health coach (nutrition) and a fitness coach.\n",
        "example": "ai_health_fitness"
      },
      "EnrollmentStage": {
        "type": "string",
        "enum": [
          "created",
          "awaiting_assignment",
          "assigned",
          "onboarding_pending",
          "onboarding_completed",
          "protocols_active"
        ],
        "example": "onboarding_pending"
      },
      "Timestamp": {
        "type": "string",
        "format": "date-time",
        "description": "ISO 8601 in UTC.",
        "example": "2026-10-26T14:05:00Z"
      },
      "CareRole": {
        "type": "string",
        "pattern": "^[a-z][a-z0-9_]*$",
        "description": "A care role on the coached plan. Today `health_coach` or `fitness_coach`; more may be added.",
        "example": "health_coach"
      },
      "CareTeamStatus": {
        "type": "object",
        "description": "One care role on the coached plan. Brand servers see whether it is filled, never who fills it.",
        "required": [
          "care_role",
          "assigned"
        ],
        "properties": {
          "care_role": {
            "$ref": "#/components/schemas/CareRole"
          },
          "assigned": {
            "type": "boolean",
            "example": true
          },
          "assigned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-21T15:12:00Z"
          }
        }
      },
      "FormAssignmentStatus": {
        "type": "string",
        "enum": [
          "pending",
          "sent",
          "in_progress",
          "completed",
          "expired",
          "cancelled"
        ],
        "example": "sent"
      },
      "FormStatus": {
        "type": "object",
        "required": [
          "form_assignment_id",
          "form_code",
          "purpose",
          "status",
          "blocks_onboarding"
        ],
        "properties": {
          "form_assignment_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2"
          },
          "form_code": {
            "type": "string",
            "example": "glp1_onboarding"
          },
          "purpose": {
            "type": "string",
            "enum": [
              "onboarding",
              "check_in",
              "eligibility"
            ],
            "example": "onboarding"
          },
          "status": {
            "$ref": "#/components/schemas/FormAssignmentStatus"
          },
          "blocks_onboarding": {
            "type": "boolean",
            "example": true
          },
          "due_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-24T15:00:00Z"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          }
        }
      },
      "ProtocolType": {
        "type": "string",
        "enum": [
          "nutrition",
          "fitness",
          "sleep",
          "stress",
          "lifestyle",
          "supplements"
        ],
        "example": "nutrition"
      },
      "ProtocolStatusSummary": {
        "type": "object",
        "description": "Timestamps only. The content is for the patient and the care team.",
        "required": [
          "protocol_id",
          "type",
          "version",
          "published_at"
        ],
        "properties": {
          "protocol_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90"
          },
          "type": {
            "$ref": "#/components/schemas/ProtocolType"
          },
          "version": {
            "type": "integer",
            "example": 1
          },
          "published_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "Enrollment": {
        "type": "object",
        "description": "The brand server's view of an enrollment. Status and ids only, never clinical content.",
        "required": [
          "id",
          "external_patient_id",
          "plan_code",
          "status",
          "stage",
          "risk_level",
          "data_sharing",
          "created_at",
          "care_team",
          "forms",
          "protocols"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "external_patient_id": {
            "$ref": "#/components/schemas/ExternalId"
          },
          "external_order_id": {
            "type": [
              "string",
              "null"
            ],
            "example": "ord-2026-10-000123"
          },
          "plan_code": {
            "$ref": "#/components/schemas/PlanCode"
          },
          "status": {
            "$ref": "#/components/schemas/EnrollmentStatus"
          },
          "stage": {
            "$ref": "#/components/schemas/EnrollmentStage"
          },
          "risk_level": {
            "$ref": "#/components/schemas/RiskLevel"
          },
          "data_sharing": {
            "type": "boolean",
            "example": true
          },
          "purchased_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-21T14:58:00Z"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "assigned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the last care role was filled.",
            "example": "2026-10-21T15:12:00Z"
          },
          "onboarding_completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          },
          "first_protocol_published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          },
          "last_activity_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last patient activity, updated about hourly.",
            "example": "2026-10-26T13:40:00Z"
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          },
          "care_team": {
            "type": "array",
            "description": "Empty on `ai_only`.",
            "items": {
              "$ref": "#/components/schemas/CareTeamStatus"
            }
          },
          "forms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FormStatus"
            }
          },
          "protocols": {
            "type": "array",
            "description": "Active protocols.",
            "items": {
              "$ref": "#/components/schemas/ProtocolStatusSummary"
            }
          }
        }
      },
      "EnrollmentList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Enrollment"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "BiologicalSex": {
        "type": "string",
        "enum": [
          "female",
          "male",
          "intersex"
        ],
        "example": "female"
      },
      "StateCode": {
        "type": "string",
        "pattern": "^[A-Z]{2}$",
        "description": "US state of residence (USPS code). Decides which licensed coaches can be assigned.",
        "example": "NY"
      },
      "UnitSystem": {
        "type": "string",
        "enum": [
          "metric",
          "imperial"
        ],
        "description": "Display preference only. The API always takes and returns metric values.",
        "example": "imperial"
      },
      "ActivityLevel": {
        "type": "string",
        "enum": [
          "sedentary",
          "lightly_active",
          "moderately_active",
          "very_active"
        ],
        "description": "* `sedentary`: little to no exercise\n* `lightly_active`: light exercise 1-3 days a week\n* `moderately_active`: moderate exercise 3-5 days a week\n* `very_active`: hard exercise 6-7 days a week\n",
        "example": "lightly_active"
      },
      "FoodAllergen": {
        "type": "string",
        "enum": [
          "milk",
          "eggs",
          "fish",
          "shellfish",
          "tree_nuts",
          "peanuts",
          "wheat",
          "soybeans",
          "sesame"
        ],
        "description": "The FDA's nine major food allergens. Anything else goes in `other_food_allergies`.",
        "example": "peanuts"
      },
      "DietaryRestriction": {
        "type": "string",
        "enum": [
          "vegetarian",
          "vegan",
          "pescatarian",
          "gluten_free",
          "dairy_free",
          "halal",
          "kosher",
          "low_carb",
          "keto",
          "mediterranean",
          "low_fodmap"
        ],
        "description": "Medical diets (renal, low sodium for a condition) are conditions on the patient, not restrictions.",
        "example": "dairy_free"
      },
      "CookingPreferences": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "skill": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "beginner",
              "intermediate",
              "advanced",
              null
            ],
            "example": "beginner"
          },
          "appliances": {
            "type": "array",
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "stove_range",
                "oven",
                "microwave",
                "air_fryer",
                "slow_cooker",
                "pressure_cooker",
                "blender",
                "food_processor",
                "grill",
                "stand_mixer"
              ]
            },
            "example": [
              "stove_range",
              "microwave",
              "air_fryer"
            ]
          },
          "cuisines": {
            "type": "array",
            "description": "Cuisines the patient enjoys.",
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "american",
                "italian",
                "mexican",
                "chinese",
                "japanese",
                "thai",
                "korean",
                "indian",
                "french",
                "middle_eastern"
              ]
            },
            "example": [
              "mexican",
              "italian"
            ]
          },
          "meal_preparer": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who usually prepares the patient's meals.",
            "enum": [
              "mostly_myself",
              "shared_with_someone_else",
              "mostly_someone_else",
              "varies_a_lot",
              null
            ],
            "example": "mostly_myself"
          },
          "dining_out": {
            "type": [
              "string",
              "null"
            ],
            "description": "How often the patient eats out or orders in.",
            "enum": [
              "rarely",
              "two_to_three_per_week",
              "four_to_six_per_week",
              "daily",
              null
            ],
            "example": "two_to_three_per_week"
          }
        }
      },
      "Lifestyle": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "sleep_hours": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 24,
            "description": "Typical hours of sleep a night.",
            "example": 6.5
          },
          "alcohol": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "none",
              "occasional",
              "weekly",
              "several_per_week",
              "daily",
              null
            ],
            "description": "Alcohol can worsen GLP-1 side effects; the AI Coach takes it into account.",
            "example": "occasional"
          },
          "smoking": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "never",
              "former",
              "current",
              null
            ],
            "example": "never"
          }
        }
      },
      "HealthProfile": {
        "type": "object",
        "description": "What plans and the AI Coach are built around. Every field is optional. In a `PATCH`, send only what changes;\n`null` clears a value and `[]` clears a list.\n",
        "additionalProperties": false,
        "properties": {
          "goal_weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 20,
            "maximum": 400,
            "example": 72.5
          },
          "activity_level": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ActivityLevel"
              },
              {
                "type": "null"
              }
            ]
          },
          "food_allergies": {
            "type": "array",
            "description": "Allergies among the FDA's nine major food allergens. Meal plans and swaps never include them.",
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/FoodAllergen"
            },
            "example": [
              "peanuts",
              "shellfish"
            ]
          },
          "other_food_allergies": {
            "type": "array",
            "description": "Any other food allergy, in the patient's words. Treated like the coded ones.",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 100
            },
            "example": [
              "kiwi"
            ]
          },
          "dietary_restrictions": {
            "type": "array",
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/DietaryRestriction"
            },
            "example": [
              "dairy_free",
              "halal"
            ]
          },
          "food_dislikes": {
            "type": "array",
            "description": "Foods the patient avoids without being allergic. Plans leave them out where they can.",
            "maxItems": 30,
            "items": {
              "type": "string",
              "maxLength": 100
            },
            "example": [
              "mushrooms"
            ]
          },
          "medications": {
            "type": "array",
            "description": "Other medications, as the brand records them. The GLP-1 is the treatment, not listed here.",
            "maxItems": 30,
            "items": {
              "type": "string",
              "maxLength": 200
            },
            "example": [
              "metformin"
            ]
          },
          "cooking": {
            "$ref": "#/components/schemas/CookingPreferences"
          },
          "lifestyle": {
            "$ref": "#/components/schemas/Lifestyle"
          }
        }
      },
      "PatientProfileInput": {
        "type": "object",
        "description": "What the brand already knows about the patient. Stored on the patient record for this brand only.",
        "required": [
          "first_name",
          "date_of_birth",
          "sex",
          "state_code"
        ],
        "properties": {
          "first_name": {
            "type": "string",
            "maxLength": 100,
            "example": "Jordan"
          },
          "last_name": {
            "type": "string",
            "maxLength": 100,
            "example": "Rivera"
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 254,
            "example": "jordan.rivera@example.com"
          },
          "phone": {
            "type": "string",
            "pattern": "^\\+[1-9][0-9]{7,14}$",
            "description": "E.164.",
            "example": "+12025550143"
          },
          "date_of_birth": {
            "type": "string",
            "format": "date",
            "example": "1986-04-12"
          },
          "sex": {
            "$ref": "#/components/schemas/BiologicalSex"
          },
          "height_cm": {
            "type": "number",
            "minimum": 50,
            "maximum": 260,
            "example": 165.1
          },
          "state_code": {
            "$ref": "#/components/schemas/StateCode"
          },
          "timezone": {
            "type": "string",
            "description": "IANA time zone. Log dates and reminders follow it.",
            "default": "America/New_York",
            "example": "America/New_York"
          },
          "language": {
            "type": "string",
            "description": "BCP 47 language tag.",
            "default": "en",
            "example": "en"
          },
          "units": {
            "$ref": "#/components/schemas/UnitSystem"
          },
          "conditions": {
            "type": "array",
            "description": "Condition codes the brand's rule matrix keys on, for example `type_2_diabetes`.",
            "items": {
              "type": "string",
              "pattern": "^[a-z][a-z0-9_]*$"
            },
            "example": [
              "prediabetes"
            ]
          },
          "health_profile": {
            "$ref": "#/components/schemas/HealthProfile"
          }
        }
      },
      "ConsentProofInput": {
        "type": "object",
        "description": "Proof that the patient accepted a legal document during the brand's checkout.",
        "required": [
          "document_code",
          "version",
          "accepted_at"
        ],
        "properties": {
          "document_code": {
            "type": "string",
            "description": "For example `coaching_consent`, `terms`, `privacy`, `hipaa_notice`.",
            "example": "coaching_consent"
          },
          "version": {
            "type": "string",
            "example": "2026-01"
          },
          "accepted_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "evidence": {
            "type": "object",
            "description": "How the brand captured the acceptance.",
            "additionalProperties": false,
            "properties": {
              "ip": {
                "type": "string",
                "description": "IPv4 or IPv6 address.",
                "example": "203.0.113.24"
              },
              "user_agent": {
                "type": "string",
                "maxLength": 512,
                "example": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X)"
              },
              "checkout_id": {
                "type": "string",
                "maxLength": 128,
                "example": "chk_2026_10_000123"
              }
            }
          }
        }
      },
      "TreatmentPhase": {
        "type": "string",
        "enum": [
          "pending_start",
          "titration",
          "maintenance",
          "taper",
          "off_ramp",
          "paused",
          "stopped"
        ],
        "example": "titration"
      },
      "TreatmentInput": {
        "type": "object",
        "description": "The medication, dose and schedule your prescriber set. TeraRx mirrors it and never changes it.\nEach call adds a version; the latest is the current treatment and earlier ones are the dose history.\n",
        "required": [
          "medication_id",
          "dose_mg",
          "phase"
        ],
        "properties": {
          "medication_id": {
            "$ref": "#/components/schemas/Uuid",
            "description": "From `GET /v1/medications`.",
            "example": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f"
          },
          "dose_mg": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 100,
            "example": 0.5
          },
          "dose_amount": {
            "type": "number",
            "description": "The dose as prescribed, when it is not in mg (for example 20 units of a compounded vial).",
            "example": 20
          },
          "dose_unit": {
            "type": "string",
            "maxLength": 20,
            "example": "units"
          },
          "phase": {
            "$ref": "#/components/schemas/TreatmentPhase"
          },
          "schedule": {
            "type": "object",
            "description": "A custom titration ladder or microdosing schedule.",
            "additionalProperties": true,
            "example": {
              "steps": [
                {
                  "from_week": 1,
                  "dose_mg": 0.25
                },
                {
                  "from_week": 5,
                  "dose_mg": 0.5
                }
              ]
            }
          },
          "injection_weekday": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6,
            "description": "0 is Sunday. Drives injection-day reminders.",
            "example": 1
          },
          "started_on": {
            "type": "string",
            "format": "date",
            "description": "First dose. The treatment week is counted from it.",
            "example": "2026-09-28"
          },
          "effective_from": {
            "$ref": "#/components/schemas/Timestamp",
            "description": "When this dose takes effect. Defaults to now."
          },
          "note": {
            "type": "string",
            "maxLength": 1000,
            "description": "Visible to the care team only.",
            "example": "Step up to 0.5 mg per titration schedule"
          }
        }
      },
      "EnrollmentCreate": {
        "type": "object",
        "required": [
          "external_patient_id",
          "patient"
        ],
        "properties": {
          "plan_code": {
            "$ref": "#/components/schemas/PlanCode",
            "description": "Omit to use the brand's default plan."
          },
          "external_patient_id": {
            "$ref": "#/components/schemas/ExternalId",
            "description": "Your patient id. It is the `sub` of the patient assertions you sign later."
          },
          "external_order_id": {
            "$ref": "#/components/schemas/ExternalId",
            "description": "Your order id. Unique per brand, so a retried checkout cannot enroll twice.",
            "example": "ord-2026-10-000123"
          },
          "purchased_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "patient": {
            "$ref": "#/components/schemas/PatientProfileInput"
          },
          "intake": {
            "type": "object",
            "description": "Intake answers you already collected. Keys that match a form field's `prefill_from` prefill onboarding forms.",
            "additionalProperties": true,
            "example": {
              "weight_kg": 96.2,
              "goal_weight_kg": 72.5,
              "activity_level": "lightly_active"
            }
          },
          "consents": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/ConsentProofInput"
            }
          },
          "treatment": {
            "$ref": "#/components/schemas/TreatmentInput"
          },
          "data_sharing": {
            "type": "boolean",
            "default": true,
            "description": "Whether the care team may read this patient's logs. The patient can change it later."
          }
        }
      },
      "first_name": {
        "type": "string",
        "maxLength": 100,
        "example": "Jordan"
      },
      "last_name": {
        "type": "string",
        "maxLength": 100,
        "example": "Rivera"
      },
      "email": {
        "type": "string",
        "format": "email",
        "maxLength": 254,
        "example": "jordan.rivera@example.com"
      },
      "phone": {
        "type": "string",
        "pattern": "^\\+[1-9][0-9]{7,14}$",
        "description": "E.164.",
        "example": "+12025550143"
      },
      "date_of_birth": {
        "type": "string",
        "format": "date",
        "example": "1986-04-12"
      },
      "height_cm": {
        "type": "number",
        "minimum": 50,
        "maximum": 260,
        "example": 165.1
      },
      "timezone": {
        "type": "string",
        "description": "IANA time zone. Log dates and reminders follow it.",
        "default": "America/New_York",
        "example": "America/New_York"
      },
      "language": {
        "type": "string",
        "description": "BCP 47 language tag.",
        "default": "en",
        "example": "en"
      },
      "conditions": {
        "type": "array",
        "description": "Condition codes the brand's rule matrix keys on, for example `type_2_diabetes`.",
        "items": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "example": [
          "prediabetes"
        ]
      },
      "BrandPatientUpdate": {
        "type": "object",
        "description": "JSON Merge Patch (RFC 7396) of the patient's details. Send only the fields that changed: the patient edits some of\nthem too (height, units, the health profile), and the last write wins. `health_profile` merges key by key.\n",
        "minProperties": 1,
        "additionalProperties": false,
        "properties": {
          "first_name": {
            "$ref": "#/components/schemas/first_name"
          },
          "last_name": {
            "$ref": "#/components/schemas/last_name"
          },
          "email": {
            "$ref": "#/components/schemas/email"
          },
          "phone": {
            "$ref": "#/components/schemas/phone"
          },
          "date_of_birth": {
            "$ref": "#/components/schemas/date_of_birth"
          },
          "sex": {
            "$ref": "#/components/schemas/BiologicalSex"
          },
          "height_cm": {
            "$ref": "#/components/schemas/height_cm"
          },
          "state_code": {
            "$ref": "#/components/schemas/StateCode"
          },
          "timezone": {
            "$ref": "#/components/schemas/timezone"
          },
          "language": {
            "$ref": "#/components/schemas/language"
          },
          "units": {
            "$ref": "#/components/schemas/UnitSystem"
          },
          "conditions": {
            "$ref": "#/components/schemas/conditions"
          },
          "health_profile": {
            "$ref": "#/components/schemas/HealthProfile"
          }
        }
      },
      "PlanChange": {
        "type": "object",
        "required": [
          "plan_code"
        ],
        "properties": {
          "plan_code": {
            "$ref": "#/components/schemas/PlanCode"
          },
          "reason": {
            "type": "string",
            "maxLength": 500,
            "description": "Kept on the enrollment history. Do not include health details.",
            "example": "Patient upgraded at renewal"
          }
        }
      },
      "Pause": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "maxLength": 500,
            "example": "Patient travelling"
          }
        }
      },
      "Cancel": {
        "type": "object",
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "type": "string",
            "enum": [
              "patient_request",
              "subscription_ended",
              "payment_failed",
              "medically_ineligible",
              "other"
            ],
            "example": "subscription_ended"
          },
          "note": {
            "type": "string",
            "maxLength": 500,
            "example": "Subscription not renewed"
          }
        }
      },
      "AiCoachOutreach": {
        "type": "object",
        "required": [
          "id",
          "status",
          "scheduled_for"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5e4-5d6e-7f80-9a1b-c2d3e4f5a6b7"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "sent",
              "skipped"
            ],
            "example": "scheduled"
          },
          "scheduled_for": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          }
        }
      },
      "Medication": {
        "type": "object",
        "required": [
          "id",
          "ingredient",
          "product_name",
          "source",
          "route",
          "standard_doses_mg"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f"
          },
          "ingredient": {
            "type": "string",
            "enum": [
              "semaglutide",
              "tirzepatide"
            ],
            "example": "semaglutide"
          },
          "product_name": {
            "type": "string",
            "example": "Wegovy"
          },
          "source": {
            "type": "string",
            "enum": [
              "branded",
              "compounded"
            ],
            "example": "branded"
          },
          "route": {
            "type": "string",
            "example": "injection"
          },
          "standard_doses_mg": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "example": [
              0.25,
              0.5,
              1,
              1.7,
              2.4
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "platform",
              "brand"
            ],
            "description": "`platform` is the shared catalogue; `brand` was added for your brand only.",
            "example": "platform"
          }
        }
      },
      "MedicationList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Medication"
            }
          }
        }
      },
      "RecordSource": {
        "type": "string",
        "enum": [
          "app",
          "brand_app",
          "brand_api",
          "wearable",
          "coach",
          "ai",
          "system"
        ],
        "readOnly": true,
        "description": "Set by the API from the caller. `brand_api` for brand servers, `brand_app` for patient tokens issued to a brand.",
        "example": "brand_app"
      },
      "Treatment": {
        "type": "object",
        "required": [
          "id",
          "medication",
          "dose_mg",
          "phase",
          "effective_from",
          "source",
          "created_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c7-1a2b-7c3d-8e4f-5a6b7c8d9e0f"
          },
          "medication": {
            "$ref": "#/components/schemas/Medication"
          },
          "dose_mg": {
            "type": "number",
            "example": 0.5
          },
          "dose_amount": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "dose_unit": {
            "type": [
              "string",
              "null"
            ],
            "example": null
          },
          "phase": {
            "$ref": "#/components/schemas/TreatmentPhase"
          },
          "schedule": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "example": null
          },
          "injection_weekday": {
            "type": [
              "integer",
              "null"
            ],
            "example": 1
          },
          "started_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "example": "2026-09-28"
          },
          "treatment_week": {
            "type": [
              "integer",
              "null"
            ],
            "readOnly": true,
            "description": "Week of treatment today, counted from `started_on` (week 1 is the first 7 days).",
            "example": 5
          },
          "effective_from": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "source": {
            "$ref": "#/components/schemas/RecordSource"
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "example": "Step up to 0.5 mg per titration schedule"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "TreatmentList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Newest first. The first item is the current treatment.",
            "items": {
              "$ref": "#/components/schemas/Treatment"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "ConsentRecord": {
        "type": "object",
        "required": [
          "id",
          "document_code",
          "document_version",
          "accepted_at",
          "source"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c8-2b3c-7d4e-8f50-6a7b8c9d0e1f"
          },
          "document_code": {
            "type": "string",
            "example": "coaching_consent"
          },
          "document_version": {
            "type": "string",
            "example": "2026-01"
          },
          "accepted_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "withdrawn_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          },
          "source": {
            "$ref": "#/components/schemas/RecordSource"
          }
        }
      },
      "ConsentRecordList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsentRecord"
            }
          }
        }
      },
      "ConsentProofBatch": {
        "type": "object",
        "required": [
          "consents"
        ],
        "properties": {
          "consents": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/ConsentProofInput"
            }
          }
        }
      },
      "MealType": {
        "type": "string",
        "enum": [
          "breakfast",
          "lunch",
          "dinner",
          "snack"
        ],
        "example": "lunch"
      },
      "Ingredient": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "example": "Greek yogurt, plain, nonfat"
          },
          "quantity": {
            "type": "number",
            "example": 170
          },
          "unit": {
            "type": "string",
            "example": "g"
          },
          "protein_g": {
            "type": "number",
            "example": 17
          },
          "calories_kcal": {
            "type": "integer",
            "example": 100
          },
          "carbs_g": {
            "type": "number",
            "example": 6
          },
          "fat_g": {
            "type": "number",
            "example": 0.7
          },
          "fiber_g": {
            "type": "number",
            "example": 0
          }
        }
      },
      "MealLogInput": {
        "type": "object",
        "required": [
          "eaten_at"
        ],
        "properties": {
          "eaten_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "meal_type": {
            "$ref": "#/components/schemas/MealType"
          },
          "meal_plan_item_id": {
            "$ref": "#/components/schemas/Uuid",
            "description": "Set when the patient ate a meal from their plan.",
            "example": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
          },
          "description": {
            "type": "string",
            "maxLength": 1000,
            "example": "Greek yogurt with berries and almonds"
          },
          "photo_upload_id": {
            "$ref": "#/components/schemas/Uuid",
            "writeOnly": true,
            "description": "From `POST /v1/patient/meal-photos`, after the photo was uploaded. Not returned; read `photo_url` instead.",
            "example": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e"
          },
          "entry_method": {
            "type": "string",
            "enum": [
              "manual",
              "photo",
              "photo_ai",
              "text_ai",
              "barcode",
              "plan"
            ],
            "description": "How it was entered. `photo_ai` when the form was pre-filled by `POST /v1/patient/meal-photos/{upload_id}/analysis`\n(send the same `photo_upload_id`); TeraRx then compares what was saved with the estimate.\n",
            "example": "manual"
          },
          "protein_g": {
            "type": "number",
            "minimum": 0,
            "maximum": 500,
            "example": 24
          },
          "calories_kcal": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000,
            "example": 310
          },
          "carbs_g": {
            "type": "number",
            "minimum": 0,
            "example": 28
          },
          "fat_g": {
            "type": "number",
            "minimum": 0,
            "example": 11
          },
          "fiber_g": {
            "type": "number",
            "minimum": 0,
            "example": 6
          },
          "sugar_g": {
            "type": "number",
            "minimum": 0,
            "example": 14
          },
          "sodium_mg": {
            "type": "integer",
            "minimum": 0,
            "example": 95
          },
          "nutrients": {
            "type": "object",
            "description": "Vitamins, minerals and anything else, keyed by nutrient code.",
            "additionalProperties": {
              "type": "number"
            },
            "example": {
              "calcium_mg": 220
            }
          },
          "ingredients": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/Ingredient"
            }
          },
          "external_id": {
            "$ref": "#/components/schemas/ExternalId",
            "description": "Your id for this log. A second log with the same id returns the first one instead of a duplicate.",
            "example": "meal-77120"
          }
        }
      },
      "BrandMealLogInput": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MealLogInput"
          },
          {
            "required": [
              "external_id"
            ]
          }
        ]
      },
      "LocalDate": {
        "type": "string",
        "format": "date",
        "description": "A calendar date in the patient's time zone.",
        "example": "2026-10-26"
      },
      "LogReceipt": {
        "type": "object",
        "description": "What a brand server gets back for a log. The values stay with the care team.",
        "required": [
          "id",
          "external_id",
          "log_date",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60"
          },
          "external_id": {
            "$ref": "#/components/schemas/ExternalId",
            "example": "meal-77120"
          },
          "log_date": {
            "$ref": "#/components/schemas/LocalDate"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp",
            "description": "When the log was last corrected; the same as `created_at` until then."
          }
        }
      },
      "WorkoutSet": {
        "type": "object",
        "properties": {
          "exercise_id": {
            "$ref": "#/components/schemas/Uuid",
            "description": "A library exercise, when known.",
            "example": "5a7c9e1b-3d5f-4a8c-9e2b-4d6f8a0c2e4f"
          },
          "name": {
            "type": "string",
            "example": "Goblet squat"
          },
          "reps": {
            "type": "integer",
            "minimum": 0,
            "example": 10
          },
          "weight_kg": {
            "type": "number",
            "minimum": 0,
            "example": 12
          }
        }
      },
      "WorkoutLogInput": {
        "type": "object",
        "required": [
          "started_at",
          "activity_type"
        ],
        "properties": {
          "started_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "activity_type": {
            "type": "string",
            "description": "For example `strength`, `walk`, `run`, `yoga`, `cycling`.",
            "maxLength": 50,
            "example": "strength"
          },
          "duration_min": {
            "type": "integer",
            "minimum": 1,
            "maximum": 600,
            "example": 35
          },
          "completed": {
            "type": "boolean",
            "default": true
          },
          "perceived_effort": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10,
            "example": 6
          },
          "workout_plan_item_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "1b3d5f7a-9c2e-4a6b-8d0f-2e4a6c8e0b2d"
          },
          "sets": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/WorkoutSet"
            }
          },
          "external_id": {
            "$ref": "#/components/schemas/ExternalId",
            "example": "workout-5531"
          }
        }
      },
      "BrandWorkoutLogInput": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WorkoutLogInput"
          },
          {
            "required": [
              "external_id"
            ]
          }
        ]
      },
      "SymptomLogInput": {
        "type": "object",
        "required": [
          "occurred_at",
          "symptom",
          "severity"
        ],
        "properties": {
          "occurred_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "symptom": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "A symptom code, for example `nausea`, `vomiting`, `diarrhea`, `constipation`, `reflux`, `fatigue`, `abdominal_pain`.\nThese codes are red flags at any severity: `chest_pain`, `difficulty_breathing`, `fainting`,\n`severe_abdominal_pain`, `persistent_vomiting`, `blood_in_vomit`, `blood_in_stool`, `yellow_skin_or_eyes`,\n`severe_dehydration`, `allergic_reaction`, `swelling_face_or_throat`, `vision_changes`, `suicidal_thoughts`,\n`self_harm`. Any symptom at severity 5 is one too. A brand's own alert rules can add codes.\n",
            "example": "nausea"
          },
          "severity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "example": 2
          },
          "note": {
            "type": "string",
            "maxLength": 1000,
            "description": "The patient's own words. Read by the care team and, on a clinical flag, the prescriber.",
            "example": "Mild, after dinner"
          },
          "external_id": {
            "$ref": "#/components/schemas/ExternalId",
            "example": "sym-20931"
          }
        }
      },
      "BrandSymptomLogInput": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SymptomLogInput"
          },
          {
            "required": [
              "external_id"
            ]
          }
        ]
      },
      "InjectionLogInput": {
        "type": "object",
        "description": "A dose taken (`injected_at`) or missed (`missed: true`). One of the two is required.",
        "anyOf": [
          {
            "required": [
              "injected_at"
            ]
          },
          {
            "required": [
              "missed"
            ]
          }
        ],
        "properties": {
          "injected_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "missed": {
            "type": "boolean",
            "default": false
          },
          "scheduled_for": {
            "type": "string",
            "format": "date",
            "example": "2026-10-26"
          },
          "dose_mg": {
            "type": "number",
            "exclusiveMinimum": 0,
            "example": 0.5
          },
          "site": {
            "type": "string",
            "description": "For example `abdomen_left`, `abdomen_right`, `thigh_left`, `thigh_right`, `arm_left`, `arm_right`.",
            "example": "abdomen_left"
          },
          "note": {
            "type": "string",
            "maxLength": 1000,
            "example": "Slight redness at site"
          },
          "external_id": {
            "$ref": "#/components/schemas/ExternalId",
            "example": "inj-88213"
          }
        }
      },
      "BrandInjectionLogInput": {
        "allOf": [
          {
            "$ref": "#/components/schemas/InjectionLogInput"
          },
          {
            "required": [
              "external_id"
            ]
          }
        ]
      },
      "meal_plan_item_id": {
        "$ref": "#/components/schemas/Uuid",
        "description": "Set when the patient ate a meal from their plan.",
        "example": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
      },
      "description": {
        "type": "string",
        "maxLength": 1000,
        "example": "Greek yogurt with berries and almonds"
      },
      "photo_upload_id": {
        "$ref": "#/components/schemas/Uuid",
        "writeOnly": true,
        "description": "From `POST /v1/patient/meal-photos`, after the photo was uploaded. Not returned; read `photo_url` instead.",
        "example": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e"
      },
      "entry_method": {
        "type": "string",
        "enum": [
          "manual",
          "photo",
          "photo_ai",
          "text_ai",
          "barcode",
          "plan"
        ],
        "description": "How it was entered. `photo_ai` when the form was pre-filled by `POST /v1/patient/meal-photos/{upload_id}/analysis`\n(send the same `photo_upload_id`); TeraRx then compares what was saved with the estimate.\n",
        "example": "manual"
      },
      "protein_g": {
        "type": "number",
        "minimum": 0,
        "maximum": 500,
        "example": 24
      },
      "calories_kcal": {
        "type": "integer",
        "minimum": 0,
        "maximum": 10000,
        "example": 310
      },
      "carbs_g": {
        "type": "number",
        "minimum": 0,
        "example": 28
      },
      "fat_g": {
        "type": "number",
        "minimum": 0,
        "example": 11
      },
      "fiber_g": {
        "type": "number",
        "minimum": 0,
        "example": 6
      },
      "sugar_g": {
        "type": "number",
        "minimum": 0,
        "example": 14
      },
      "sodium_mg": {
        "type": "integer",
        "minimum": 0,
        "example": 95
      },
      "nutrients": {
        "type": "object",
        "description": "Vitamins, minerals and anything else, keyed by nutrient code.",
        "additionalProperties": {
          "type": "number"
        },
        "example": {
          "calcium_mg": 220
        }
      },
      "ingredients": {
        "type": "array",
        "maxItems": 50,
        "items": {
          "$ref": "#/components/schemas/Ingredient"
        }
      },
      "MealLogUpdate": {
        "type": "object",
        "description": "The meal fields to change. Send only what changes.",
        "minProperties": 1,
        "additionalProperties": false,
        "properties": {
          "eaten_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "meal_type": {
            "$ref": "#/components/schemas/MealType"
          },
          "meal_plan_item_id": {
            "$ref": "#/components/schemas/meal_plan_item_id"
          },
          "description": {
            "$ref": "#/components/schemas/description"
          },
          "photo_upload_id": {
            "$ref": "#/components/schemas/photo_upload_id"
          },
          "entry_method": {
            "$ref": "#/components/schemas/entry_method"
          },
          "protein_g": {
            "$ref": "#/components/schemas/protein_g"
          },
          "calories_kcal": {
            "$ref": "#/components/schemas/calories_kcal"
          },
          "carbs_g": {
            "$ref": "#/components/schemas/carbs_g"
          },
          "fat_g": {
            "$ref": "#/components/schemas/fat_g"
          },
          "fiber_g": {
            "$ref": "#/components/schemas/fiber_g"
          },
          "sugar_g": {
            "$ref": "#/components/schemas/sugar_g"
          },
          "sodium_mg": {
            "$ref": "#/components/schemas/sodium_mg"
          },
          "nutrients": {
            "$ref": "#/components/schemas/nutrients"
          },
          "ingredients": {
            "$ref": "#/components/schemas/ingredients"
          }
        }
      },
      "activity_type": {
        "type": "string",
        "description": "For example `strength`, `walk`, `run`, `yoga`, `cycling`.",
        "maxLength": 50,
        "example": "strength"
      },
      "duration_min": {
        "type": "integer",
        "minimum": 1,
        "maximum": 600,
        "example": 35
      },
      "completed": {
        "type": "boolean",
        "default": true
      },
      "perceived_effort": {
        "type": "integer",
        "minimum": 1,
        "maximum": 10,
        "example": 6
      },
      "workout_plan_item_id": {
        "$ref": "#/components/schemas/Uuid",
        "example": "1b3d5f7a-9c2e-4a6b-8d0f-2e4a6c8e0b2d"
      },
      "sets": {
        "type": "array",
        "maxItems": 100,
        "items": {
          "$ref": "#/components/schemas/WorkoutSet"
        }
      },
      "WorkoutLogUpdate": {
        "type": "object",
        "description": "The workout fields to change. Send only what changes.",
        "minProperties": 1,
        "additionalProperties": false,
        "properties": {
          "started_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "activity_type": {
            "$ref": "#/components/schemas/activity_type"
          },
          "duration_min": {
            "$ref": "#/components/schemas/duration_min"
          },
          "completed": {
            "$ref": "#/components/schemas/completed"
          },
          "perceived_effort": {
            "$ref": "#/components/schemas/perceived_effort"
          },
          "workout_plan_item_id": {
            "$ref": "#/components/schemas/workout_plan_item_id"
          },
          "sets": {
            "$ref": "#/components/schemas/sets"
          }
        }
      },
      "symptom": {
        "type": "string",
        "pattern": "^[a-z][a-z0-9_]*$",
        "description": "A symptom code, for example `nausea`, `vomiting`, `diarrhea`, `constipation`, `reflux`, `fatigue`, `abdominal_pain`.\nThese codes are red flags at any severity: `chest_pain`, `difficulty_breathing`, `fainting`,\n`severe_abdominal_pain`, `persistent_vomiting`, `blood_in_vomit`, `blood_in_stool`, `yellow_skin_or_eyes`,\n`severe_dehydration`, `allergic_reaction`, `swelling_face_or_throat`, `vision_changes`, `suicidal_thoughts`,\n`self_harm`. Any symptom at severity 5 is one too. A brand's own alert rules can add codes.\n",
        "example": "nausea"
      },
      "severity": {
        "type": "integer",
        "minimum": 1,
        "maximum": 5,
        "example": 2
      },
      "note": {
        "type": "string",
        "maxLength": 1000,
        "description": "The patient's own words. Read by the care team and, on a clinical flag, the prescriber.",
        "example": "Mild, after dinner"
      },
      "SymptomLogUpdate": {
        "type": "object",
        "description": "The symptom fields to change. Send only what changes.",
        "minProperties": 1,
        "additionalProperties": false,
        "properties": {
          "occurred_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "symptom": {
            "$ref": "#/components/schemas/symptom"
          },
          "severity": {
            "$ref": "#/components/schemas/severity"
          },
          "note": {
            "$ref": "#/components/schemas/note"
          }
        }
      },
      "missed": {
        "type": "boolean",
        "default": false
      },
      "scheduled_for": {
        "type": "string",
        "format": "date",
        "example": "2026-10-26"
      },
      "dose_mg": {
        "type": "number",
        "exclusiveMinimum": 0,
        "example": 0.5
      },
      "site": {
        "type": "string",
        "description": "For example `abdomen_left`, `abdomen_right`, `thigh_left`, `thigh_right`, `arm_left`, `arm_right`.",
        "example": "abdomen_left"
      },
      "note-2": {
        "type": "string",
        "maxLength": 1000,
        "example": "Slight redness at site"
      },
      "InjectionLogUpdate": {
        "type": "object",
        "description": "The injection fields to change. Send only what changes. The result must still be a dose taken (`injected_at`)\nor missed (`missed: true`).\n",
        "minProperties": 1,
        "additionalProperties": false,
        "properties": {
          "injected_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "missed": {
            "$ref": "#/components/schemas/missed"
          },
          "scheduled_for": {
            "$ref": "#/components/schemas/scheduled_for"
          },
          "dose_mg": {
            "$ref": "#/components/schemas/dose_mg"
          },
          "site": {
            "$ref": "#/components/schemas/site"
          },
          "note": {
            "$ref": "#/components/schemas/note-2"
          }
        }
      },
      "Score": {
        "type": [
          "integer",
          "null"
        ],
        "minimum": 1,
        "maximum": 5
      },
      "DailyLogInput": {
        "type": "object",
        "description": "JSON Merge Patch (RFC 7396) on one day. Values are the day's totals: send the new total, not an increment.\n`null` clears a value. Weight and body measures go here.\n",
        "minProperties": 1,
        "additionalProperties": false,
        "properties": {
          "water_ml": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 20000,
            "example": 1800
          },
          "weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 20,
            "maximum": 400,
            "example": 94.8
          },
          "waist_cm": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 30,
            "maximum": 300,
            "example": 101.5
          },
          "hip_cm": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 30,
            "maximum": 300,
            "example": 112
          },
          "body_fat_pct": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 1,
            "maximum": 80,
            "example": 38.5
          },
          "steps": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 200000,
            "example": 7400
          },
          "sleep_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 1440,
            "example": 430
          },
          "sleep_quality": {
            "$ref": "#/components/schemas/Score"
          },
          "mood": {
            "$ref": "#/components/schemas/Score"
          },
          "stress": {
            "$ref": "#/components/schemas/Score"
          },
          "energy": {
            "$ref": "#/components/schemas/Score"
          },
          "habits_done": {
            "type": "object",
            "description": "Habit check-offs keyed `<protocol_id>:<habit_key>`, from the active protocols.",
            "additionalProperties": {
              "type": "boolean"
            },
            "example": {
              "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90:protein_each_meal": true
            }
          },
          "metrics": {
            "type": "object",
            "description": "Any other daily metric, keyed by a metric code. New codes need no API change.",
            "additionalProperties": {
              "type": [
                "number",
                "string",
                "boolean",
                "null"
              ]
            },
            "example": {
              "resting_heart_rate": 64
            }
          }
        }
      },
      "DailyLogReceipt": {
        "type": "object",
        "required": [
          "log_date",
          "updated_at"
        ],
        "properties": {
          "log_date": {
            "$ref": "#/components/schemas/LocalDate"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "EventType": {
        "type": "string",
        "enum": [
          "enrollment.created",
          "enrollment.stage_changed",
          "enrollment.paused",
          "enrollment.resumed",
          "enrollment.cancelled",
          "care_team.assigned",
          "care_team.changed",
          "care_team.capacity_warning",
          "care_team.feedback_due",
          "form.requested",
          "onboarding.completed",
          "protocol.published",
          "protocol.updated",
          "message.created",
          "clinical.flag_raised",
          "clinical.flag_redelivered",
          "clinical.flag_acknowledged",
          "clinical.flag_resolved",
          "patient.disengaged",
          "patient.milestone_reached",
          "reminder.due",
          "data_request.completed"
        ],
        "example": "enrollment.created"
      },
      "EventEnvelope": {
        "type": "object",
        "required": [
          "id",
          "type",
          "created_at",
          "tenant_id",
          "data"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "description": "Unique per event; the same on every retry. Dedupe on it.",
            "example": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7"
          },
          "type": {
            "$ref": "#/components/schemas/EventType"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "tenant_id": {
            "$ref": "#/components/schemas/Uuid",
            "description": "Your tenant.",
            "example": "a0000000-0000-4000-8000-000000000002"
          },
          "data": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "EnrollmentRef": {
        "type": "object",
        "required": [
          "enrollment_id",
          "external_patient_id"
        ],
        "properties": {
          "enrollment_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "external_patient_id": {
            "$ref": "#/components/schemas/ExternalId"
          }
        }
      },
      "EnrollmentCreatedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "plan_code",
              "status",
              "stage"
            ],
            "properties": {
              "external_order_id": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "ord-2026-10-000123"
              },
              "plan_code": {
                "$ref": "#/components/schemas/PlanCode"
              },
              "status": {
                "$ref": "#/components/schemas/EnrollmentStatus"
              },
              "stage": {
                "$ref": "#/components/schemas/EnrollmentStage"
              }
            }
          }
        ]
      },
      "EnrollmentCreatedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "enrollment.created"
              },
              "data": {
                "$ref": "#/components/schemas/EnrollmentCreatedData"
              }
            }
          }
        ]
      },
      "EnrollmentStageChangedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "from",
              "to"
            ],
            "properties": {
              "from": {
                "$ref": "#/components/schemas/EnrollmentStage"
              },
              "to": {
                "$ref": "#/components/schemas/EnrollmentStage"
              }
            }
          }
        ]
      },
      "EnrollmentStageChangedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "enrollment.stage_changed"
              },
              "data": {
                "$ref": "#/components/schemas/EnrollmentStageChangedData"
              }
            }
          }
        ]
      },
      "EnrollmentPausedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "enrollment.paused"
              },
              "data": {
                "$ref": "#/components/schemas/EnrollmentRef"
              }
            }
          }
        ]
      },
      "EnrollmentResumedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "enrollment.resumed"
              },
              "data": {
                "$ref": "#/components/schemas/EnrollmentRef"
              }
            }
          }
        ]
      },
      "EnrollmentCancelledData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "ended_at",
              "cancel_reason"
            ],
            "properties": {
              "ended_at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "cancel_reason": {
                "type": "string",
                "enum": [
                  "patient_request",
                  "subscription_ended",
                  "payment_failed",
                  "medically_ineligible",
                  "other"
                ],
                "example": "subscription_ended"
              }
            }
          }
        ]
      },
      "EnrollmentCancelledEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "enrollment.cancelled"
              },
              "data": {
                "$ref": "#/components/schemas/EnrollmentCancelledData"
              }
            }
          }
        ]
      },
      "CareTeamAssignedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "care_role",
              "assigned_at"
            ],
            "properties": {
              "care_role": {
                "$ref": "#/components/schemas/CareRole"
              },
              "assigned_at": {
                "$ref": "#/components/schemas/Timestamp"
              }
            }
          }
        ]
      },
      "CareTeamAssignedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "care_team.assigned"
              },
              "data": {
                "$ref": "#/components/schemas/CareTeamAssignedData"
              }
            }
          }
        ]
      },
      "CareTeamChangedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "care_role",
              "change",
              "changed_at"
            ],
            "properties": {
              "care_role": {
                "$ref": "#/components/schemas/CareRole"
              },
              "change": {
                "type": "string",
                "enum": [
                  "reassigned",
                  "ended"
                ],
                "description": "`reassigned` to another coach, or `ended` (for example on a move to `ai_only`).",
                "example": "reassigned"
              },
              "reason_code": {
                "type": "string",
                "enum": [
                  "state_change",
                  "plan_change",
                  "coach_unavailable",
                  "other"
                ],
                "description": "Why: the patient moved to a state the coach isn't licensed in, the plan changed, the coach left or is\nunavailable, or another reason. Check for unknown values: new reasons may be added.\n",
                "example": "state_change"
              },
              "changed_at": {
                "$ref": "#/components/schemas/Timestamp"
              }
            }
          }
        ]
      },
      "CareTeamChangedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "care_team.changed"
              },
              "data": {
                "$ref": "#/components/schemas/CareTeamChangedData"
              }
            }
          }
        ]
      },
      "CareTeamCapacityWarningData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "care_role",
              "state_code",
              "waiting_since"
            ],
            "properties": {
              "care_role": {
                "$ref": "#/components/schemas/CareRole"
              },
              "state_code": {
                "$ref": "#/components/schemas/StateCode"
              },
              "waiting_since": {
                "$ref": "#/components/schemas/Timestamp"
              }
            }
          }
        ]
      },
      "CareTeamCapacityWarningEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "care_team.capacity_warning"
              },
              "data": {
                "$ref": "#/components/schemas/CareTeamCapacityWarningData"
              }
            }
          }
        ]
      },
      "CareTeamFeedbackDueData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "feedback_request_id",
              "care_role"
            ],
            "properties": {
              "feedback_request_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "care_role": {
                "$ref": "#/components/schemas/CareRole"
              },
              "expires_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "example": "2026-11-23T00:00:00Z"
              }
            }
          }
        ]
      },
      "CareTeamFeedbackDueEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "care_team.feedback_due"
              },
              "data": {
                "$ref": "#/components/schemas/CareTeamFeedbackDueData"
              }
            }
          }
        ]
      },
      "FormPurpose": {
        "type": "string",
        "enum": [
          "onboarding",
          "check_in",
          "eligibility"
        ],
        "example": "onboarding"
      },
      "FormRequestedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "form_assignment_id",
              "form_code",
              "purpose"
            ],
            "properties": {
              "form_assignment_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "form_code": {
                "type": "string",
                "example": "glp1_onboarding"
              },
              "purpose": {
                "$ref": "#/components/schemas/FormPurpose"
              },
              "due_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "example": "2026-10-24T15:00:00Z"
              }
            }
          }
        ]
      },
      "FormRequestedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "form.requested"
              },
              "data": {
                "$ref": "#/components/schemas/FormRequestedData"
              }
            }
          }
        ]
      },
      "OnboardingCompletedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "completed_at"
            ],
            "properties": {
              "completed_at": {
                "$ref": "#/components/schemas/Timestamp"
              }
            }
          }
        ]
      },
      "OnboardingCompletedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "onboarding.completed"
              },
              "data": {
                "$ref": "#/components/schemas/OnboardingCompletedData"
              }
            }
          }
        ]
      },
      "ProtocolPublishedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "protocol_id",
              "protocol_type",
              "version",
              "published_at"
            ],
            "properties": {
              "protocol_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "protocol_type": {
                "$ref": "#/components/schemas/ProtocolType"
              },
              "version": {
                "type": "integer",
                "example": 1
              },
              "published_at": {
                "$ref": "#/components/schemas/Timestamp"
              }
            }
          }
        ]
      },
      "ProtocolPublishedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "protocol.published"
              },
              "data": {
                "$ref": "#/components/schemas/ProtocolPublishedData"
              }
            }
          }
        ]
      },
      "ProtocolUpdatedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "protocol.updated"
              },
              "data": {
                "$ref": "#/components/schemas/ProtocolPublishedData"
              }
            }
          }
        ]
      },
      "MessageCreatedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "conversation_id",
              "message_id",
              "conversation_kind",
              "sender_type"
            ],
            "properties": {
              "conversation_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "message_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "conversation_kind": {
                "type": "string",
                "enum": [
                  "care",
                  "ai_coach"
                ],
                "example": "care"
              },
              "sender_type": {
                "type": "string",
                "enum": [
                  "patient",
                  "coach",
                  "ai",
                  "system"
                ],
                "example": "coach"
              }
            }
          }
        ]
      },
      "MessageCreatedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "message.created"
              },
              "data": {
                "$ref": "#/components/schemas/MessageCreatedData"
              }
            }
          }
        ]
      },
      "Severity": {
        "type": "string",
        "enum": [
          "info",
          "warning",
          "critical"
        ],
        "example": "critical"
      },
      "ClinicalFlagRaisedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "flag_id",
              "severity",
              "ack_due_at"
            ],
            "properties": {
              "flag_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "severity": {
                "$ref": "#/components/schemas/Severity"
              },
              "raised_risk_to": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "normal",
                  "elevated",
                  "high",
                  null
                ],
                "example": "high"
              },
              "ack_due_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "example": "2026-10-26T16:05:00Z"
              }
            }
          }
        ]
      },
      "ClinicalFlagRaisedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "clinical.flag_raised"
              },
              "data": {
                "$ref": "#/components/schemas/ClinicalFlagRaisedData"
              }
            }
          }
        ]
      },
      "ClinicalFlagRedeliveredData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "flag_id",
              "severity",
              "ack_due_at",
              "redelivery_count",
              "first_raised_at"
            ],
            "properties": {
              "flag_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "severity": {
                "$ref": "#/components/schemas/Severity"
              },
              "ack_due_at": {
                "$ref": "#/components/schemas/Timestamp",
                "description": "The new deadline."
              },
              "redelivery_count": {
                "type": "integer",
                "minimum": 1,
                "example": 1
              },
              "first_raised_at": {
                "$ref": "#/components/schemas/Timestamp"
              }
            }
          }
        ]
      },
      "ClinicalFlagRedeliveredEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "clinical.flag_redelivered"
              },
              "data": {
                "$ref": "#/components/schemas/ClinicalFlagRedeliveredData"
              }
            }
          }
        ]
      },
      "ClinicalFlagAcknowledgedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "flag_id",
              "acknowledged_at"
            ],
            "properties": {
              "flag_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "acknowledged_at": {
                "$ref": "#/components/schemas/Timestamp"
              }
            }
          }
        ]
      },
      "ClinicalFlagAcknowledgedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "clinical.flag_acknowledged"
              },
              "data": {
                "$ref": "#/components/schemas/ClinicalFlagAcknowledgedData"
              }
            }
          }
        ]
      },
      "ClinicalFlagResolvedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "flag_id",
              "resolved_at",
              "new_risk_level"
            ],
            "properties": {
              "flag_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "resolved_at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "new_risk_level": {
                "$ref": "#/components/schemas/RiskLevel"
              }
            }
          }
        ]
      },
      "ClinicalFlagResolvedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "clinical.flag_resolved"
              },
              "data": {
                "$ref": "#/components/schemas/ClinicalFlagResolvedData"
              }
            }
          }
        ]
      },
      "PatientDisengagedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "last_activity_at",
              "inactive_days"
            ],
            "properties": {
              "last_activity_at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "inactive_days": {
                "type": "integer",
                "description": "At least the brand's `disengaged_after_days` (7 by default).",
                "example": 7
              }
            }
          }
        ]
      },
      "PatientDisengagedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "patient.disengaged"
              },
              "data": {
                "$ref": "#/components/schemas/PatientDisengagedData"
              }
            }
          }
        ]
      },
      "MilestoneCode": {
        "type": "string",
        "description": "What the patient reached. New codes may be added; show a generic celebration for a code you don't know.\n\n| Code | Reached when |\n| --- | --- |\n| `first_meal_logged` | The first meal is logged |\n| `logging_streak_7`, `logging_streak_30` | Something is logged 7 or 30 days in a row |\n| `protein_target_days_7`, `protein_target_days_30` | 7 or 30 days at 80% or more of the protein target |\n| `workouts_10`, `workouts_50` | 10 or 50 workouts logged |\n| `injections_on_time_4`, `injections_on_time_12` | 4 or 12 doses in a row logged on their day |\n| `week_4_completed`, `week_12_completed` | 4 or 12 weeks since enrollment |\n| `weight_loss_5_pct`, `weight_loss_10_pct` | 5% or 10% below the first weight logged |\n| `goal_weight_reached` | At or below the health profile's `goal_weight_kg` |\n",
        "enum": [
          "first_meal_logged",
          "logging_streak_7",
          "logging_streak_30",
          "protein_target_days_7",
          "protein_target_days_30",
          "workouts_10",
          "workouts_50",
          "injections_on_time_4",
          "injections_on_time_12",
          "week_4_completed",
          "week_12_completed",
          "weight_loss_5_pct",
          "weight_loss_10_pct",
          "goal_weight_reached"
        ],
        "example": "protein_target_days_7"
      },
      "PatientMilestoneReachedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "milestone_id",
              "code",
              "achieved_at"
            ],
            "properties": {
              "milestone_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "code": {
                "$ref": "#/components/schemas/MilestoneCode"
              },
              "achieved_at": {
                "$ref": "#/components/schemas/Timestamp"
              }
            }
          }
        ]
      },
      "PatientMilestoneReachedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "patient.milestone_reached"
              },
              "data": {
                "$ref": "#/components/schemas/PatientMilestoneReachedData"
              }
            }
          }
        ]
      },
      "ReminderDueData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "reminder_id",
              "kind",
              "due_at"
            ],
            "properties": {
              "reminder_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "injection",
                  "check_in",
                  "log_nudge",
                  "habit"
                ],
                "example": "injection"
              },
              "due_at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "form_assignment_id": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid",
                "description": "For `check_in` reminders.",
                "example": null
              }
            }
          }
        ]
      },
      "ReminderDueEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "reminder.due"
              },
              "data": {
                "$ref": "#/components/schemas/ReminderDueData"
              }
            }
          }
        ]
      },
      "DataRequestCompletedData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EnrollmentRef"
          },
          {
            "type": "object",
            "required": [
              "data_request_id",
              "kind",
              "status"
            ],
            "properties": {
              "data_request_id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "export",
                  "delete",
                  "amend"
                ],
                "example": "export"
              },
              "status": {
                "type": "string",
                "enum": [
                  "completed",
                  "rejected"
                ],
                "example": "completed"
              }
            }
          }
        ]
      },
      "DataRequestCompletedEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventEnvelope"
          },
          {
            "properties": {
              "type": {
                "const": "data_request.completed"
              },
              "data": {
                "$ref": "#/components/schemas/DataRequestCompletedData"
              }
            }
          }
        ]
      },
      "Event": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/EnrollmentCreatedEvent"
          },
          {
            "$ref": "#/components/schemas/EnrollmentStageChangedEvent"
          },
          {
            "$ref": "#/components/schemas/EnrollmentPausedEvent"
          },
          {
            "$ref": "#/components/schemas/EnrollmentResumedEvent"
          },
          {
            "$ref": "#/components/schemas/EnrollmentCancelledEvent"
          },
          {
            "$ref": "#/components/schemas/CareTeamAssignedEvent"
          },
          {
            "$ref": "#/components/schemas/CareTeamChangedEvent"
          },
          {
            "$ref": "#/components/schemas/CareTeamCapacityWarningEvent"
          },
          {
            "$ref": "#/components/schemas/CareTeamFeedbackDueEvent"
          },
          {
            "$ref": "#/components/schemas/FormRequestedEvent"
          },
          {
            "$ref": "#/components/schemas/OnboardingCompletedEvent"
          },
          {
            "$ref": "#/components/schemas/ProtocolPublishedEvent"
          },
          {
            "$ref": "#/components/schemas/ProtocolUpdatedEvent"
          },
          {
            "$ref": "#/components/schemas/MessageCreatedEvent"
          },
          {
            "$ref": "#/components/schemas/ClinicalFlagRaisedEvent"
          },
          {
            "$ref": "#/components/schemas/ClinicalFlagRedeliveredEvent"
          },
          {
            "$ref": "#/components/schemas/ClinicalFlagAcknowledgedEvent"
          },
          {
            "$ref": "#/components/schemas/ClinicalFlagResolvedEvent"
          },
          {
            "$ref": "#/components/schemas/PatientDisengagedEvent"
          },
          {
            "$ref": "#/components/schemas/PatientMilestoneReachedEvent"
          },
          {
            "$ref": "#/components/schemas/ReminderDueEvent"
          },
          {
            "$ref": "#/components/schemas/DataRequestCompletedEvent"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "enrollment.created": "#/components/schemas/EnrollmentCreatedEvent",
            "enrollment.stage_changed": "#/components/schemas/EnrollmentStageChangedEvent",
            "enrollment.paused": "#/components/schemas/EnrollmentPausedEvent",
            "enrollment.resumed": "#/components/schemas/EnrollmentResumedEvent",
            "enrollment.cancelled": "#/components/schemas/EnrollmentCancelledEvent",
            "care_team.assigned": "#/components/schemas/CareTeamAssignedEvent",
            "care_team.changed": "#/components/schemas/CareTeamChangedEvent",
            "care_team.capacity_warning": "#/components/schemas/CareTeamCapacityWarningEvent",
            "care_team.feedback_due": "#/components/schemas/CareTeamFeedbackDueEvent",
            "form.requested": "#/components/schemas/FormRequestedEvent",
            "onboarding.completed": "#/components/schemas/OnboardingCompletedEvent",
            "protocol.published": "#/components/schemas/ProtocolPublishedEvent",
            "protocol.updated": "#/components/schemas/ProtocolUpdatedEvent",
            "message.created": "#/components/schemas/MessageCreatedEvent",
            "clinical.flag_raised": "#/components/schemas/ClinicalFlagRaisedEvent",
            "clinical.flag_redelivered": "#/components/schemas/ClinicalFlagRedeliveredEvent",
            "clinical.flag_acknowledged": "#/components/schemas/ClinicalFlagAcknowledgedEvent",
            "clinical.flag_resolved": "#/components/schemas/ClinicalFlagResolvedEvent",
            "patient.disengaged": "#/components/schemas/PatientDisengagedEvent",
            "patient.milestone_reached": "#/components/schemas/PatientMilestoneReachedEvent",
            "reminder.due": "#/components/schemas/ReminderDueEvent",
            "data_request.completed": "#/components/schemas/DataRequestCompletedEvent"
          }
        }
      },
      "EventList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Oldest first, in the order they were written.",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "Metric": {
        "type": [
          "number",
          "null"
        ],
        "description": "`null` when fewer than 10 patients are in the group (small-group suppression) or there is no data."
      },
      "ReportMetrics": {
        "type": "object",
        "description": "Aggregates only, no patient-level values. Each metric is suppressed on its own when its group is under 10 patients.",
        "required": [
          "active_enrollments",
          "new_enrollments",
          "cancelled_enrollments",
          "engaged_last_7_days",
          "median_weight_change_kg",
          "protein_target_days_pct",
          "flags_raised",
          "flags_acknowledged_on_time_pct",
          "ai_coach_thumbs_up_pct",
          "retention_90_day_pct",
          "median_hours_to_first_protocol"
        ],
        "properties": {
          "active_enrollments": {
            "$ref": "#/components/schemas/Metric",
            "example": 214
          },
          "new_enrollments": {
            "$ref": "#/components/schemas/Metric",
            "example": 61
          },
          "cancelled_enrollments": {
            "$ref": "#/components/schemas/Metric",
            "example": 12
          },
          "engaged_last_7_days": {
            "$ref": "#/components/schemas/Metric",
            "description": "Patients who logged or messaged in the last 7 days of the period.",
            "example": 168
          },
          "median_weight_change_kg": {
            "$ref": "#/components/schemas/Metric",
            "description": "Median change since enrollment, among patients who logged weight.",
            "example": -4.6
          },
          "protein_target_days_pct": {
            "$ref": "#/components/schemas/Metric",
            "description": "Share of logged days at 80% or more of the protein target.",
            "example": 0.57
          },
          "flags_raised": {
            "$ref": "#/components/schemas/Metric",
            "example": 18
          },
          "flags_acknowledged_on_time_pct": {
            "$ref": "#/components/schemas/Metric",
            "description": "Share of clinical flags acknowledged before `ack_due_at`.",
            "example": 0.94
          },
          "ai_coach_thumbs_up_pct": {
            "$ref": "#/components/schemas/Metric",
            "description": "Thumbs-up share of rated AI Coach replies.",
            "example": 0.88
          },
          "retention_90_day_pct": {
            "$ref": "#/components/schemas/Metric",
            "description": "Enrollments still active 90 days after they started, among those at least 90 days old.",
            "example": null
          },
          "median_hours_to_first_protocol": {
            "$ref": "#/components/schemas/Metric",
            "example": 26.5
          }
        }
      },
      "BrandReport": {
        "type": "object",
        "required": [
          "period",
          "generated_at",
          "min_group_size",
          "totals",
          "plans"
        ],
        "properties": {
          "period": {
            "type": "object",
            "required": [
              "from",
              "to"
            ],
            "properties": {
              "from": {
                "type": "string",
                "format": "date",
                "example": "2026-10-01"
              },
              "to": {
                "type": "string",
                "format": "date",
                "example": "2026-10-31"
              }
            }
          },
          "generated_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "min_group_size": {
            "type": "integer",
            "const": 10,
            "description": "Groups smaller than this are suppressed."
          },
          "totals": {
            "$ref": "#/components/schemas/ReportMetrics"
          },
          "plans": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "plan_code",
                "metrics"
              ],
              "properties": {
                "plan_code": {
                  "$ref": "#/components/schemas/PlanCode"
                },
                "metrics": {
                  "$ref": "#/components/schemas/ReportMetrics"
                }
              }
            }
          }
        }
      },
      "DataRequestStatus": {
        "type": "string",
        "enum": [
          "received",
          "processing",
          "completed",
          "rejected"
        ],
        "example": "processing"
      },
      "DataRequestKind": {
        "type": "string",
        "enum": [
          "export",
          "delete",
          "amend"
        ],
        "description": "* `export`: a copy of the patient's coaching records for your brand, as a download.\n* `delete`: removes the patient's coaching records for your brand, except what the law requires TeraRx to keep (the audit log).\n* `amend`: the HIPAA right to amend. You decide within 60 days of `requested_at`.\n",
        "example": "export"
      },
      "AmendmentDetails": {
        "type": "object",
        "required": [
          "record_type",
          "description",
          "requested_change"
        ],
        "properties": {
          "record_type": {
            "type": "string",
            "enum": [
              "profile",
              "meal_log",
              "workout_log",
              "symptom_log",
              "injection_log",
              "daily_log",
              "protocol",
              "message"
            ],
            "example": "symptom_log"
          },
          "record_id": {
            "type": "string",
            "description": "The record, when the patient can point to one. A date for `daily_log`.",
            "example": "0190f5c9-7f80-7192-8cb4-3d4e5f607182"
          },
          "description": {
            "type": "string",
            "maxLength": 2000,
            "example": "The severity was logged as 5 by mistake."
          },
          "requested_change": {
            "type": "string",
            "maxLength": 2000,
            "example": "Severity should be 2."
          }
        }
      },
      "DataRequest": {
        "type": "object",
        "required": [
          "id",
          "enrollment_id",
          "external_patient_id",
          "kind",
          "status",
          "requested_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13"
          },
          "enrollment_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "external_patient_id": {
            "$ref": "#/components/schemas/ExternalId"
          },
          "kind": {
            "$ref": "#/components/schemas/DataRequestKind"
          },
          "status": {
            "$ref": "#/components/schemas/DataRequestStatus"
          },
          "requested_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          },
          "export": {
            "description": "Export requests, once completed.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "available",
                  "expires_at"
                ],
                "properties": {
                  "available": {
                    "type": "boolean",
                    "example": true
                  },
                  "expires_at": {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "amendment": {
            "description": "Amend requests only.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "details",
                  "respond_by"
                ],
                "properties": {
                  "details": {
                    "$ref": "#/components/schemas/AmendmentDetails"
                  },
                  "respond_by": {
                    "$ref": "#/components/schemas/Timestamp",
                    "description": "60 days after `requested_at`."
                  },
                  "decision": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "accepted",
                      "denied",
                      null
                    ],
                    "example": null
                  },
                  "decision_note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "example": null
                  },
                  "decided_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "example": null
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "DataRequestList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataRequest"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "ExportOrDeleteRequest": {
        "type": "object",
        "required": [
          "enrollment_id",
          "kind"
        ],
        "properties": {
          "enrollment_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "kind": {
            "type": "string",
            "enum": [
              "export",
              "delete"
            ],
            "example": "export"
          }
        }
      },
      "AmendRequest": {
        "type": "object",
        "required": [
          "enrollment_id",
          "kind",
          "details"
        ],
        "properties": {
          "enrollment_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "kind": {
            "type": "string",
            "const": "amend"
          },
          "details": {
            "$ref": "#/components/schemas/AmendmentDetails"
          }
        }
      },
      "DataRequestCreate": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/ExportOrDeleteRequest"
          },
          {
            "$ref": "#/components/schemas/AmendRequest"
          }
        ],
        "discriminator": {
          "propertyName": "kind",
          "mapping": {
            "export": "#/components/schemas/ExportOrDeleteRequest",
            "delete": "#/components/schemas/ExportOrDeleteRequest",
            "amend": "#/components/schemas/AmendRequest"
          }
        }
      },
      "ExportLink": {
        "type": "object",
        "required": [
          "url",
          "expires_at"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Pre-signed download link. Expires within minutes; ask for a new one if needed.",
            "example": "https://exports.example.com/7a2e4c61?signature=example"
          },
          "expires_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "AmendAccepted": {
        "type": "object",
        "required": [
          "decision"
        ],
        "properties": {
          "decision": {
            "type": "string",
            "const": "accepted"
          },
          "decision_note": {
            "type": "string",
            "maxLength": 2000,
            "example": "Corrected the severity to 2."
          }
        }
      },
      "AmendDenied": {
        "type": "object",
        "required": [
          "decision",
          "decision_note"
        ],
        "properties": {
          "decision": {
            "type": "string",
            "const": "denied"
          },
          "decision_note": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "Required on a denial; HIPAA requires the reason.",
            "example": "The record is accurate as reported by the patient at the time."
          }
        }
      },
      "AmendDecision": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/AmendAccepted"
          },
          {
            "$ref": "#/components/schemas/AmendDenied"
          }
        ],
        "discriminator": {
          "propertyName": "decision",
          "mapping": {
            "accepted": "#/components/schemas/AmendAccepted",
            "denied": "#/components/schemas/AmendDenied"
          }
        }
      },
      "CareTeamMember": {
        "type": "object",
        "description": "A coach as the patient sees them. Coach ids are never exposed.",
        "required": [
          "care_role",
          "display_name"
        ],
        "properties": {
          "care_role": {
            "$ref": "#/components/schemas/CareRole"
          },
          "display_name": {
            "type": "string",
            "description": "The name to show, under the brand's naming rules.",
            "example": "Maya C."
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "example": "Health Coach"
          },
          "credentials": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "RD",
              "NBC-HWC"
            ]
          },
          "assigned_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "BrandInfo": {
        "type": "object",
        "required": [
          "display_name"
        ],
        "properties": {
          "display_name": {
            "type": "string",
            "example": "Demo Brand"
          },
          "primary_color": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^#[0-9A-Fa-f]{6}$",
            "example": "#1A5F7A"
          },
          "support": {
            "type": "object",
            "description": "Where the AI Coach sends account, billing and app questions. Coaching is not emergency care.",
            "properties": {
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email",
                "example": "support@example.com"
              },
              "phone": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "+12025550100"
              },
              "url": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri",
                "example": "https://help.example.com"
              }
            }
          }
        }
      },
      "PatientProfile": {
        "type": "object",
        "required": [
          "patient",
          "enrollment",
          "care_team",
          "brand"
        ],
        "properties": {
          "patient": {
            "type": "object",
            "required": [
              "first_name",
              "date_of_birth",
              "sex",
              "state_code",
              "timezone",
              "language",
              "units"
            ],
            "properties": {
              "first_name": {
                "type": "string",
                "example": "Jordan"
              },
              "last_name": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "Rivera"
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email",
                "example": "jordan.rivera@example.com"
              },
              "phone": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "+12025550143"
              },
              "date_of_birth": {
                "type": "string",
                "format": "date",
                "example": "1986-04-12"
              },
              "sex": {
                "$ref": "#/components/schemas/BiologicalSex"
              },
              "height_cm": {
                "type": [
                  "number",
                  "null"
                ],
                "example": 165.1
              },
              "state_code": {
                "$ref": "#/components/schemas/StateCode"
              },
              "timezone": {
                "type": "string",
                "example": "America/New_York"
              },
              "language": {
                "type": "string",
                "example": "en"
              },
              "units": {
                "$ref": "#/components/schemas/UnitSystem"
              },
              "conditions": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "example": [
                  "prediabetes"
                ]
              },
              "health_profile": {
                "$ref": "#/components/schemas/HealthProfile"
              }
            }
          },
          "enrollment": {
            "type": "object",
            "required": [
              "id",
              "plan_code",
              "status",
              "stage",
              "data_sharing"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "plan_code": {
                "$ref": "#/components/schemas/PlanCode"
              },
              "status": {
                "$ref": "#/components/schemas/EnrollmentStatus"
              },
              "stage": {
                "$ref": "#/components/schemas/EnrollmentStage"
              },
              "data_sharing": {
                "type": "boolean",
                "description": "When false, the care team cannot read the patient's logs and AI tools are off for them.",
                "example": true
              }
            }
          },
          "care_team": {
            "type": "array",
            "description": "Empty on `ai_only` and until coaches are assigned.",
            "items": {
              "$ref": "#/components/schemas/CareTeamMember"
            }
          },
          "brand": {
            "$ref": "#/components/schemas/BrandInfo"
          },
          "legal_documents_pending": {
            "type": "integer",
            "description": "Required legal documents not accepted yet. When above 0, show `GET /v1/patient/legal-documents` first.",
            "example": 0
          }
        }
      },
      "PatientProfileUpdate": {
        "type": "object",
        "description": "JSON Merge Patch (RFC 7396). Send only the fields to change.",
        "minProperties": 1,
        "additionalProperties": false,
        "properties": {
          "height_cm": {
            "type": "number",
            "minimum": 50,
            "maximum": 260,
            "description": "The patient's height. Metric, like every measurement; convert from `units` in the app.",
            "example": 167.6
          },
          "timezone": {
            "type": "string",
            "example": "America/Chicago"
          },
          "language": {
            "type": "string",
            "example": "es"
          },
          "units": {
            "$ref": "#/components/schemas/UnitSystem"
          },
          "data_sharing": {
            "type": "boolean",
            "description": "Turning it off hides the patient's logs, protocols and AI tools from the care team.",
            "example": false
          },
          "health_profile": {
            "$ref": "#/components/schemas/HealthProfile"
          }
        }
      },
      "PatientTreatment": {
        "type": "object",
        "description": "The patient's current treatment as the patient sees it.",
        "required": [
          "medication",
          "dose_mg",
          "phase"
        ],
        "properties": {
          "medication": {
            "type": "object",
            "required": [
              "ingredient",
              "product_name",
              "source",
              "route"
            ],
            "properties": {
              "ingredient": {
                "type": "string",
                "enum": [
                  "semaglutide",
                  "tirzepatide"
                ],
                "example": "semaglutide"
              },
              "product_name": {
                "type": "string",
                "example": "Wegovy"
              },
              "source": {
                "type": "string",
                "enum": [
                  "branded",
                  "compounded"
                ],
                "example": "branded"
              },
              "route": {
                "type": "string",
                "example": "injection"
              }
            }
          },
          "dose_mg": {
            "type": "number",
            "example": 0.5
          },
          "dose_amount": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "dose_unit": {
            "type": [
              "string",
              "null"
            ],
            "example": null
          },
          "phase": {
            "$ref": "#/components/schemas/TreatmentPhase"
          },
          "injection_weekday": {
            "type": [
              "integer",
              "null"
            ],
            "example": 1
          },
          "started_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "example": "2026-09-28"
          },
          "treatment_week": {
            "type": [
              "integer",
              "null"
            ],
            "example": 5
          },
          "effective_from": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "SelfReportedTreatment": {
        "type": "object",
        "description": "TeraRx Direct only. The patient reports the GLP-1 they take; brand patients get their treatment from the brand.",
        "required": [
          "medication_id",
          "dose_mg",
          "phase"
        ],
        "properties": {
          "medication_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f"
          },
          "dose_mg": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 100,
            "example": 0.5
          },
          "phase": {
            "$ref": "#/components/schemas/TreatmentPhase"
          },
          "injection_weekday": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6,
            "example": 1
          },
          "started_on": {
            "type": "string",
            "format": "date",
            "example": "2026-09-28"
          }
        }
      },
      "LegalDocument": {
        "type": "object",
        "description": "A legal document version that applies to the patient, with whether they have accepted it.",
        "required": [
          "id",
          "code",
          "version",
          "url",
          "required_on_first_open",
          "effective_at",
          "accepted_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
          },
          "code": {
            "type": "string",
            "example": "coaching_consent"
          },
          "version": {
            "type": "string",
            "example": "2026-01"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Where the full text lives. Show it before asking for acceptance.",
            "example": "https://legal.example.com/coaching-consent/2026-01"
          },
          "required_on_first_open": {
            "type": "boolean",
            "description": "When true and `accepted_at` is null, ask for acceptance before showing coaching screens.",
            "example": true
          },
          "effective_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "accepted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          }
        }
      },
      "LegalDocumentList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LegalDocument"
            }
          }
        }
      },
      "ConsentAccept": {
        "type": "object",
        "required": [
          "legal_document_id"
        ],
        "properties": {
          "legal_document_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
          }
        }
      },
      "FormSummary": {
        "type": "object",
        "required": [
          "code",
          "version",
          "purpose",
          "title"
        ],
        "properties": {
          "code": {
            "type": "string",
            "example": "glp1_onboarding"
          },
          "version": {
            "type": "integer",
            "description": "The version pinned when the form was sent.",
            "example": 1
          },
          "purpose": {
            "$ref": "#/components/schemas/FormPurpose"
          },
          "title": {
            "type": "string",
            "example": "Coaching Onboarding"
          }
        }
      },
      "FormAssignmentSummary": {
        "type": "object",
        "required": [
          "id",
          "form",
          "status",
          "blocks_onboarding"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2"
          },
          "form": {
            "$ref": "#/components/schemas/FormSummary"
          },
          "status": {
            "$ref": "#/components/schemas/FormAssignmentStatus"
          },
          "blocks_onboarding": {
            "type": "boolean",
            "description": "Onboarding completes only when every blocking form is completed.",
            "example": true
          },
          "due_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-24T15:00:00Z"
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-21T15:00:00Z"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          }
        }
      },
      "FormAssignmentList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FormAssignmentSummary"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "FormField": {
        "type": "object",
        "required": [
          "id",
          "type",
          "label"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "The answer key.",
            "example": "weight_kg"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "number",
              "boolean",
              "date",
              "select",
              "multi_select",
              "multi_text",
              "scale"
            ],
            "description": "Answer types: `text` and `select` take a string, `number` and `scale` a number, `boolean` a boolean,\n`date` a `YYYY-MM-DD` string, `multi_select` and `multi_text` an array of strings.\n",
            "example": "number"
          },
          "label": {
            "type": "string",
            "example": "Current weight"
          },
          "required": {
            "type": "boolean",
            "default": false
          },
          "options": {
            "type": "array",
            "description": "Allowed values for `select` and `multi_select`.",
            "items": {
              "type": "string"
            },
            "example": [
              "sedentary",
              "lightly_active",
              "moderately_active",
              "very_active"
            ]
          },
          "unit": {
            "type": "string",
            "description": "Unit of a `number` field. Always metric.",
            "example": "kg"
          },
          "min": {
            "type": "number",
            "example": 1
          },
          "max": {
            "type": "number",
            "example": 5
          }
        }
      },
      "Answers": {
        "type": "object",
        "description": "Answers keyed by field `id`.",
        "additionalProperties": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "number"
            },
            {
              "type": "boolean"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            {
              "type": "null"
            }
          ]
        },
        "example": {
          "weight_kg": 96.2,
          "primary_goal": "preserve_muscle"
        }
      },
      "EligibilityResult": {
        "type": "object",
        "required": [
          "outcome"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "enum": [
              "eligible",
              "needs_review",
              "ineligible"
            ],
            "description": "`eligible` activates the enrollment; `ineligible` ends it; `needs_review` waits for a TeraRx reviewer.",
            "example": "eligible"
          }
        }
      },
      "FormAssignment": {
        "description": "A form sent to the patient, with its fields, prefill and any saved draft.",
        "allOf": [
          {
            "$ref": "#/components/schemas/FormAssignmentSummary"
          },
          {
            "type": "object",
            "required": [
              "fields",
              "prefill"
            ],
            "properties": {
              "fields": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/FormField"
                }
              },
              "prefill": {
                "$ref": "#/components/schemas/Answers",
                "description": "Values the brand's intake already provided. Show them as defaults."
              },
              "draft_answers": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Answers"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "answers": {
                "description": "Submitted answers, once completed.",
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Answers"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "result": {
                "description": "Eligibility forms only, once completed.",
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/EligibilityResult"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        ]
      },
      "FormAnswersInput": {
        "type": "object",
        "required": [
          "answers"
        ],
        "properties": {
          "answers": {
            "$ref": "#/components/schemas/Answers"
          }
        }
      },
      "DailyLog": {
        "type": "object",
        "required": [
          "log_date",
          "habits_done",
          "metrics",
          "sources",
          "updated_at"
        ],
        "properties": {
          "log_date": {
            "$ref": "#/components/schemas/LocalDate"
          },
          "water_ml": {
            "type": [
              "integer",
              "null"
            ],
            "example": 1800
          },
          "weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "example": 94.8
          },
          "waist_cm": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "hip_cm": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "body_fat_pct": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "steps": {
            "type": [
              "integer",
              "null"
            ],
            "example": 7400
          },
          "sleep_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "example": 430
          },
          "sleep_quality": {
            "$ref": "#/components/schemas/Score"
          },
          "mood": {
            "$ref": "#/components/schemas/Score"
          },
          "stress": {
            "$ref": "#/components/schemas/Score"
          },
          "energy": {
            "$ref": "#/components/schemas/Score"
          },
          "habits_done": {
            "type": "object",
            "additionalProperties": {
              "type": "boolean"
            },
            "example": {
              "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90:protein_each_meal": true
            }
          },
          "metrics": {
            "type": "object",
            "additionalProperties": {
              "type": [
                "number",
                "string",
                "boolean",
                "null"
              ]
            },
            "example": {}
          },
          "protein_g": {
            "type": [
              "number",
              "null"
            ],
            "readOnly": true,
            "description": "Rollup of the day's meal logs.",
            "example": 92.5
          },
          "calories_kcal": {
            "type": [
              "integer",
              "null"
            ],
            "readOnly": true,
            "example": 1450
          },
          "fiber_g": {
            "type": [
              "number",
              "null"
            ],
            "readOnly": true,
            "example": 21
          },
          "workout_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "readOnly": true,
            "description": "Rollup of the day's workout logs.",
            "example": 35
          },
          "max_symptom_severity": {
            "type": [
              "integer",
              "null"
            ],
            "readOnly": true,
            "description": "Worst symptom severity logged that day.",
            "example": 2
          },
          "sources": {
            "type": "array",
            "readOnly": true,
            "items": {
              "$ref": "#/components/schemas/RecordSource"
            },
            "example": [
              "brand_app"
            ]
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "DailyLogList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "One entry per day that has any data, newest first.",
            "items": {
              "$ref": "#/components/schemas/DailyLog"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "MetricTarget": {
        "type": "object",
        "required": [
          "metric",
          "label",
          "unit",
          "target",
          "progress"
        ],
        "properties": {
          "metric": {
            "type": "string",
            "description": "The protocol target's metric code, such as `protein_g`, `water_ml`, `fiber_g`, `steps` or `workout_minutes`.",
            "example": "protein_g"
          },
          "label": {
            "type": "string",
            "example": "Protein"
          },
          "unit": {
            "type": "string",
            "example": "g"
          },
          "target": {
            "type": "number",
            "example": 110
          },
          "progress": {
            "type": "number",
            "description": "What the day's logs add up to so far. `0` when nothing is logged.",
            "example": 72
          }
        }
      },
      "TodayMeal": {
        "type": "object",
        "required": [
          "meal_plan_item_id",
          "meal_type",
          "title",
          "logged"
        ],
        "properties": {
          "meal_plan_item_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
          },
          "meal_type": {
            "$ref": "#/components/schemas/MealType"
          },
          "title": {
            "type": "string",
            "example": "Greek yogurt protein bowl"
          },
          "recipe_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "example": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
          },
          "protein_g": {
            "type": [
              "number",
              "null"
            ],
            "example": 31
          },
          "calories_kcal": {
            "type": [
              "integer",
              "null"
            ],
            "example": 320
          },
          "logged": {
            "type": "boolean",
            "description": "True when a meal log links this plan meal today.",
            "example": true
          }
        }
      },
      "TodayWorkout": {
        "type": "object",
        "required": [
          "workout_plan_item_id",
          "title",
          "logged"
        ],
        "properties": {
          "workout_plan_item_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "4d2f9a31-6c8b-4e0d-9f72-1b3c5d7e9f02"
          },
          "title": {
            "type": "string",
            "example": "Full-body strength A"
          },
          "duration_min": {
            "type": [
              "integer",
              "null"
            ],
            "example": 30
          },
          "logged": {
            "type": "boolean",
            "example": false
          }
        }
      },
      "TodayHabit": {
        "type": "object",
        "required": [
          "protocol_id",
          "key",
          "title",
          "done"
        ],
        "properties": {
          "protocol_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90"
          },
          "key": {
            "type": "string",
            "description": "Check it off with `PATCH /v1/patient/daily-logs/{log_date}` as `habits_done[\"<protocol_id>:<key>\"]`.",
            "example": "protein_each_meal"
          },
          "title": {
            "type": "string",
            "example": "Protein at every meal"
          },
          "done": {
            "type": "boolean",
            "example": false
          }
        }
      },
      "Reminder": {
        "type": "object",
        "required": [
          "id",
          "kind",
          "due_at",
          "status"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c5-4a5b-7c61-8d78-9e0f1a2b3c45"
          },
          "kind": {
            "type": "string",
            "enum": [
              "injection",
              "check_in",
              "log_nudge",
              "habit"
            ],
            "example": "injection"
          },
          "ref_key": {
            "type": [
              "string",
              "null"
            ],
            "description": "The habit key or form assignment id the reminder is about.",
            "example": null
          },
          "due_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "sent",
              "cancelled"
            ],
            "example": "scheduled"
          },
          "recurring": {
            "type": "boolean",
            "description": "True when the next occurrence is scheduled after this one is sent.",
            "example": true
          }
        }
      },
      "Milestone": {
        "type": "object",
        "required": [
          "id",
          "code",
          "category",
          "title",
          "message",
          "achieved_at",
          "stats"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5e1-2a3b-7c4d-9e5f-6a7b8c9d0e1f"
          },
          "code": {
            "$ref": "#/components/schemas/MilestoneCode"
          },
          "category": {
            "type": "string",
            "enum": [
              "logging",
              "nutrition",
              "activity",
              "treatment",
              "program",
              "weight"
            ],
            "example": "nutrition"
          },
          "title": {
            "type": "string",
            "description": "A short headline in the patient's language.",
            "example": "7 days at your protein target"
          },
          "message": {
            "type": "string",
            "description": "One personal line built from `stats`.",
            "example": "You averaged 112 g a day, up from 74 g in your first week."
          },
          "achieved_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "stats": {
            "type": "object",
            "description": "The patient's numbers behind the milestone. Keys depend on the code.",
            "additionalProperties": {
              "type": "number"
            },
            "example": {
              "days": 7,
              "avg_protein_g": 112,
              "first_week_avg_protein_g": 74
            }
          }
        }
      },
      "Today": {
        "type": "object",
        "required": [
          "date",
          "treatment_week",
          "injection",
          "targets",
          "meals",
          "workouts",
          "habits",
          "next_reminder",
          "open_forms",
          "unread_care_messages",
          "legal_documents_pending",
          "new_milestones"
        ],
        "properties": {
          "date": {
            "$ref": "#/components/schemas/LocalDate"
          },
          "treatment_week": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The same number as `GET /v1/patient/treatment`. Null before a treatment is set.",
            "example": 6
          },
          "injection": {
            "description": "Null when today is not an injection day.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "due_today",
                  "logged"
                ],
                "properties": {
                  "due_today": {
                    "type": "boolean",
                    "example": true
                  },
                  "logged": {
                    "type": "boolean",
                    "example": false
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "targets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MetricTarget"
            }
          },
          "meals": {
            "type": "array",
            "description": "Today's meals from the meal plan, in plan order. Empty without a meal plan.",
            "items": {
              "$ref": "#/components/schemas/TodayMeal"
            }
          },
          "workouts": {
            "type": "array",
            "description": "Today's workouts from the workout plan. Empty on a rest day or without a plan.",
            "items": {
              "$ref": "#/components/schemas/TodayWorkout"
            }
          },
          "habits": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TodayHabit"
            }
          },
          "next_reminder": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Reminder"
              },
              {
                "type": "null"
              }
            ]
          },
          "open_forms": {
            "type": "integer",
            "description": "Forms waiting for the patient (`sent` or `in_progress`).",
            "example": 1
          },
          "unread_care_messages": {
            "type": "integer",
            "description": "Across care threads. Always 0 on `ai_only`.",
            "example": 2
          },
          "legal_documents_pending": {
            "type": "integer",
            "example": 0
          },
          "new_milestones": {
            "type": "array",
            "description": "Milestones reached in the last 7 days, newest first.",
            "items": {
              "$ref": "#/components/schemas/Milestone"
            }
          }
        }
      },
      "DayTargets": {
        "type": "object",
        "required": [
          "date",
          "targets"
        ],
        "properties": {
          "date": {
            "$ref": "#/components/schemas/LocalDate"
          },
          "targets": {
            "type": "array",
            "description": "One per target in the protocols in force that day. Empty before the first protocol is published.",
            "items": {
              "$ref": "#/components/schemas/MetricTarget"
            }
          }
        }
      },
      "WeekStats": {
        "type": "object",
        "required": [
          "week_number",
          "start_date",
          "end_date",
          "days_logged",
          "logging_streak_days",
          "protein",
          "calories_avg_kcal",
          "water",
          "workouts",
          "steps_avg",
          "weight",
          "injections",
          "symptoms",
          "milestones"
        ],
        "properties": {
          "week_number": {
            "type": "integer",
            "minimum": 1,
            "description": "The treatment week, the same number as `treatment_week` on `GET /v1/patient/treatment`.",
            "example": 6
          },
          "start_date": {
            "$ref": "#/components/schemas/LocalDate"
          },
          "end_date": {
            "$ref": "#/components/schemas/LocalDate"
          },
          "days_logged": {
            "type": "integer",
            "minimum": 0,
            "maximum": 7,
            "description": "Days with anything logged. For the current week, counts up to today.",
            "example": 5
          },
          "logging_streak_days": {
            "type": "integer",
            "description": "Days in a row with anything logged, up to the end of the week (or today).",
            "example": 12
          },
          "protein": {
            "type": "object",
            "required": [
              "target_g",
              "avg_g",
              "days_at_target"
            ],
            "properties": {
              "target_g": {
                "type": [
                  "number",
                  "null"
                ],
                "example": 110
              },
              "avg_g": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Average over the days with meals logged.",
                "example": 96
              },
              "days_at_target": {
                "type": "integer",
                "description": "Days at 80% or more of the target.",
                "example": 4
              }
            }
          },
          "calories_avg_kcal": {
            "type": [
              "integer",
              "null"
            ],
            "example": 1480
          },
          "water": {
            "type": "object",
            "required": [
              "target_ml",
              "avg_ml",
              "days_at_target"
            ],
            "properties": {
              "target_ml": {
                "type": [
                  "integer",
                  "null"
                ],
                "example": 2500
              },
              "avg_ml": {
                "type": [
                  "integer",
                  "null"
                ],
                "example": 2100
              },
              "days_at_target": {
                "type": "integer",
                "example": 3
              }
            }
          },
          "workouts": {
            "type": "object",
            "required": [
              "count",
              "minutes"
            ],
            "properties": {
              "count": {
                "type": "integer",
                "example": 3
              },
              "minutes": {
                "type": "integer",
                "example": 95
              }
            }
          },
          "steps_avg": {
            "type": [
              "integer",
              "null"
            ],
            "example": 7400
          },
          "weight": {
            "type": "object",
            "required": [
              "start_kg",
              "end_kg",
              "change_kg"
            ],
            "properties": {
              "start_kg": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "The first weight logged that week.",
                "example": 96.4
              },
              "end_kg": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "The last weight logged that week.",
                "example": 95.6
              },
              "change_kg": {
                "type": [
                  "number",
                  "null"
                ],
                "example": -0.8
              }
            }
          },
          "injections": {
            "type": "object",
            "required": [
              "taken",
              "missed"
            ],
            "properties": {
              "taken": {
                "type": "integer",
                "example": 1
              },
              "missed": {
                "type": "integer",
                "example": 0
              }
            }
          },
          "symptoms": {
            "type": "object",
            "required": [
              "days",
              "max_severity"
            ],
            "properties": {
              "days": {
                "type": "integer",
                "description": "Days with a symptom logged.",
                "example": 2
              },
              "max_severity": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 1,
                "maximum": 5,
                "example": 2
              }
            }
          },
          "milestones": {
            "type": "array",
            "description": "Milestones reached during the week.",
            "items": {
              "$ref": "#/components/schemas/Milestone"
            }
          }
        }
      },
      "MilestoneList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Newest first. At most one per code.",
            "items": {
              "$ref": "#/components/schemas/Milestone"
            }
          }
        }
      },
      "MealPhotoUploadRequest": {
        "type": "object",
        "required": [
          "content_type",
          "content_length"
        ],
        "properties": {
          "content_type": {
            "type": "string",
            "enum": [
              "image/jpeg",
              "image/png",
              "image/heic"
            ],
            "example": "image/jpeg"
          },
          "content_length": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10485760,
            "description": "Bytes, at most 10 MB.",
            "example": 1843200
          }
        }
      },
      "MealPhotoUpload": {
        "type": "object",
        "required": [
          "upload_id",
          "upload_url",
          "method",
          "headers",
          "expires_at"
        ],
        "properties": {
          "upload_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e"
          },
          "upload_url": {
            "type": "string",
            "format": "uri",
            "description": "Pre-signed URL. Upload the bytes with `method` and `headers` before `expires_at`.",
            "example": "https://uploads.example.com/meal-photos/8e2c4a60?signature=example"
          },
          "method": {
            "type": "string",
            "const": "PUT"
          },
          "headers": {
            "type": "object",
            "description": "Headers to send with the upload, exactly as given.",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "Content-Type": "image/jpeg"
            }
          },
          "expires_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "MealAnalysis": {
        "type": "object",
        "required": [
          "upload_id",
          "ingredients",
          "totals",
          "confidence"
        ],
        "description": "The AI Coach's estimate from a meal photo, to pre-fill the logging form. Nothing is logged until the patient saves.",
        "properties": {
          "upload_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "example": "Grilled chicken salad with quinoa"
          },
          "meal_type": {
            "description": "A guess from the photo and the time; the patient can change it.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MealType"
              },
              {
                "type": "null"
              }
            ]
          },
          "ingredients": {
            "type": "array",
            "description": "Empty when no food was recognized.",
            "items": {
              "$ref": "#/components/schemas/Ingredient"
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "protein_g": {
                "type": "number",
                "example": 38
              },
              "calories_kcal": {
                "type": "integer",
                "example": 480
              },
              "carbs_g": {
                "type": "number",
                "example": 34
              },
              "fat_g": {
                "type": "number",
                "example": 18
              },
              "fiber_g": {
                "type": "number",
                "example": 6
              }
            }
          },
          "confidence": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "description": "Show the estimate as a starting point when `low`.",
            "example": "medium"
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "description": "Something the patient should check, for example a sauce the photo can't show.",
            "example": "The dressing isn't visible; add it if you used one."
          }
        }
      },
      "RecentFood": {
        "type": "object",
        "required": [
          "id",
          "name",
          "times_logged",
          "last_logged_at"
        ],
        "description": "A food the patient logged before, with the amount and macros from the last time. Each ingredient of a meal is a\nfood; a meal logged without ingredients is one food named by its description.\n",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5e2-3b4c-7d5e-8f60-7a8b9c0d1e2f"
          },
          "name": {
            "type": "string",
            "example": "Greek yogurt, plain, nonfat"
          },
          "quantity": {
            "type": [
              "number",
              "null"
            ],
            "example": 170
          },
          "unit": {
            "type": [
              "string",
              "null"
            ],
            "example": "g"
          },
          "protein_g": {
            "type": [
              "number",
              "null"
            ],
            "example": 17
          },
          "calories_kcal": {
            "type": [
              "integer",
              "null"
            ],
            "example": 100
          },
          "carbs_g": {
            "type": [
              "number",
              "null"
            ],
            "example": 6
          },
          "fat_g": {
            "type": [
              "number",
              "null"
            ],
            "example": 0.7
          },
          "fiber_g": {
            "type": [
              "number",
              "null"
            ],
            "example": 0
          },
          "times_logged": {
            "type": "integer",
            "example": 9
          },
          "last_logged_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "RecentFoodList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Most recently logged first.",
            "items": {
              "$ref": "#/components/schemas/RecentFood"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "MealLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MealLogInput"
          },
          {
            "type": "object",
            "required": [
              "id",
              "log_date",
              "source",
              "created_at",
              "updated_at"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/Uuid",
                "example": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60"
              },
              "log_date": {
                "$ref": "#/components/schemas/LocalDate"
              },
              "photo_url": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri",
                "readOnly": true,
                "description": "Short-lived link to the photo (expires within minutes). Do not store it.",
                "example": null
              },
              "source": {
                "$ref": "#/components/schemas/RecordSource"
              },
              "created_at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "updated_at": {
                "$ref": "#/components/schemas/Timestamp",
                "description": "When the log was last corrected; the same as `created_at` until then."
              }
            }
          }
        ]
      },
      "MealLogList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MealLog"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "WorkoutLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WorkoutLogInput"
          },
          {
            "type": "object",
            "required": [
              "id",
              "log_date",
              "source",
              "created_at",
              "updated_at"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/Uuid",
                "example": "0190f5c9-6e7f-7081-9ba3-2c3d4e5f6071"
              },
              "log_date": {
                "$ref": "#/components/schemas/LocalDate"
              },
              "source": {
                "$ref": "#/components/schemas/RecordSource"
              },
              "created_at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "updated_at": {
                "$ref": "#/components/schemas/Timestamp",
                "description": "When the log was last corrected; the same as `created_at` until then."
              }
            }
          }
        ]
      },
      "WorkoutLogList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkoutLog"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "SymptomLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SymptomLogInput"
          },
          {
            "type": "object",
            "required": [
              "id",
              "log_date",
              "is_red_flag",
              "source",
              "created_at",
              "updated_at"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/Uuid",
                "example": "0190f5c9-7f80-7192-8cb4-3d4e5f607182"
              },
              "log_date": {
                "$ref": "#/components/schemas/LocalDate"
              },
              "is_red_flag": {
                "type": "boolean",
                "readOnly": true,
                "description": "Set by TeraRx from the symptom and severity (see `symptom`). When true, show the emergency guidance (911, 988)\nright away; the clinical flag to the care team or prescriber follows.\n",
                "example": false
              },
              "days_since_injection": {
                "type": [
                  "integer",
                  "null"
                ],
                "readOnly": true,
                "example": 2
              },
              "source": {
                "$ref": "#/components/schemas/RecordSource"
              },
              "created_at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "updated_at": {
                "$ref": "#/components/schemas/Timestamp",
                "description": "When the log was last corrected; the same as `created_at` until then."
              }
            }
          }
        ]
      },
      "SymptomLogList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SymptomLog"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "InjectionLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/InjectionLogInput"
          },
          {
            "type": "object",
            "required": [
              "id",
              "log_date",
              "missed",
              "source",
              "created_at",
              "updated_at"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/Uuid",
                "example": "0190f5c9-8091-72a3-9dc5-4e5f60718293"
              },
              "log_date": {
                "$ref": "#/components/schemas/LocalDate"
              },
              "source": {
                "$ref": "#/components/schemas/RecordSource"
              },
              "created_at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "updated_at": {
                "$ref": "#/components/schemas/Timestamp",
                "description": "When the log was last corrected; the same as `created_at` until then."
              }
            }
          }
        ]
      },
      "InjectionLogList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InjectionLog"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "PublishedBy": {
        "type": "string",
        "enum": [
          "coach",
          "ai_coach"
        ],
        "description": "`coach` when a coach approved it; `ai_coach` when the AI Coach published it on its own (`ai_only` with `ai_autonomy = auto`).",
        "example": "coach"
      },
      "ProtocolSummary": {
        "type": "object",
        "required": [
          "id",
          "type",
          "version",
          "status",
          "mode",
          "title",
          "published_at",
          "published_by"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90"
          },
          "type": {
            "$ref": "#/components/schemas/ProtocolType"
          },
          "version": {
            "type": "integer",
            "example": 2
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "superseded"
            ],
            "description": "Drafts are never shown to patients.",
            "example": "active"
          },
          "mode": {
            "type": "string",
            "enum": [
              "guideline",
              "full_plan"
            ],
            "description": "`full_plan` protocols come with a meal or workout plan.",
            "example": "full_plan"
          },
          "title": {
            "type": "string",
            "example": "Protein-first nutrition, titration weeks 5-8"
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "example": "Hit 110 g of protein a day and keep meals small while the dose goes up."
          },
          "published_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "published_by": {
            "$ref": "#/components/schemas/PublishedBy"
          },
          "change_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why this version replaced the one before it. Null on version 1.",
            "example": "Dose increased to 0.5 mg"
          }
        }
      },
      "ProtocolSummaryList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProtocolSummary"
            }
          }
        }
      },
      "ProtocolTarget": {
        "type": "object",
        "required": [
          "metric",
          "value",
          "unit",
          "label"
        ],
        "properties": {
          "metric": {
            "type": "string",
            "example": "protein_g"
          },
          "value": {
            "type": "number",
            "example": 110
          },
          "unit": {
            "type": "string",
            "example": "g"
          },
          "label": {
            "type": "string",
            "example": "Protein per day"
          }
        }
      },
      "ProtocolHabit": {
        "type": "object",
        "required": [
          "key",
          "title",
          "kind"
        ],
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "Stable across versions. Check it off on the daily log as `<protocol_id>:<key>`.",
            "example": "protein_each_meal"
          },
          "title": {
            "type": "string",
            "example": "Protein at every meal"
          },
          "kind": {
            "type": "string",
            "enum": [
              "checkoff",
              "quantity"
            ],
            "example": "checkoff"
          },
          "target_value": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "unit": {
            "type": [
              "string",
              "null"
            ],
            "example": null
          }
        }
      },
      "Protocol": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProtocolSummary"
          },
          {
            "type": "object",
            "required": [
              "content"
            ],
            "properties": {
              "content": {
                "type": "object",
                "required": [
                  "markdown",
                  "targets",
                  "habits"
                ],
                "properties": {
                  "markdown": {
                    "type": "string",
                    "description": "The protocol text (Markdown), written for the patient.",
                    "example": "## This week\nAim for 30 g of protein at each meal and sip water through the day.\n"
                  },
                  "targets": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/ProtocolTarget"
                    }
                  },
                  "habits": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/ProtocolHabit"
                    }
                  },
                  "meal_plan_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "example": "0190f5ca-1a2b-7c3d-8e4f-5a6b7c8d9e01"
                  },
                  "workout_plan_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "example": null
                  }
                }
              },
              "change_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Why this version replaced the previous one.",
                "example": "Dose increased to 0.5 mg"
              }
            }
          }
        ]
      },
      "ProtocolVersionList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Newest version first.",
            "items": {
              "$ref": "#/components/schemas/ProtocolSummary"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "MealDetails": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "ingredients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Ingredient"
            }
          },
          "nutrients": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "example": {
              "fiber_g": 7
            }
          },
          "prep_minutes": {
            "type": "integer",
            "example": 10
          },
          "steps": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "Spoon the yogurt into a bowl",
              "Top with berries and almonds"
            ]
          }
        }
      },
      "MealSwapRecord": {
        "type": "object",
        "description": "Set when the meal was swapped. The original meal is kept.",
        "required": [
          "original_title",
          "swapped_by",
          "swapped_at"
        ],
        "properties": {
          "original_title": {
            "type": "string",
            "example": "Salmon with quinoa"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "example": "Does not like fish"
          },
          "swapped_by": {
            "type": "string",
            "enum": [
              "patient",
              "coach",
              "ai"
            ],
            "example": "ai"
          },
          "swapped_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "MealRating": {
        "type": "object",
        "required": [
          "rating",
          "updated_at"
        ],
        "properties": {
          "rating": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "example": 2
          },
          "comment": {
            "type": [
              "string",
              "null"
            ],
            "example": "Too sweet for me."
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "MealPlanItem": {
        "type": "object",
        "required": [
          "id",
          "day_index",
          "meal_type",
          "sort_order",
          "title",
          "details"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
          },
          "day_index": {
            "type": "integer",
            "minimum": 0,
            "description": "Day in the plan's cycle, starting at 0 on `starts_on`.",
            "example": 0
          },
          "meal_type": {
            "$ref": "#/components/schemas/MealType"
          },
          "sort_order": {
            "type": "integer",
            "example": 0
          },
          "title": {
            "type": "string",
            "example": "Greek yogurt bowl"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "example": "Nonfat Greek yogurt with berries and almonds"
          },
          "protein_g": {
            "type": [
              "number",
              "null"
            ],
            "example": 24
          },
          "calories_kcal": {
            "type": [
              "integer",
              "null"
            ],
            "example": 310
          },
          "details": {
            "$ref": "#/components/schemas/MealDetails"
          },
          "recipe_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "A library recipe, when the meal comes from one. Read it with `GET /v1/patient/library/{library_item_id}`.",
            "example": null
          },
          "swap": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MealSwapRecord"
              },
              {
                "type": "null"
              }
            ]
          },
          "my_rating": {
            "description": "The patient's rating of this meal, or null.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MealRating"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "MealPlan": {
        "type": "object",
        "required": [
          "id",
          "version",
          "status",
          "title",
          "published_by",
          "items"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5ca-1a2b-7c3d-8e4f-5a6b7c8d9e01"
          },
          "protocol_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "example": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90"
          },
          "version": {
            "type": "integer",
            "example": 1
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "superseded"
            ],
            "example": "active"
          },
          "title": {
            "type": "string",
            "example": "Week 5 meal plan"
          },
          "starts_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "example": "2026-10-26"
          },
          "published_by": {
            "$ref": "#/components/schemas/PublishedBy"
          },
          "items": {
            "type": "array",
            "description": "Ordered by `day_index`, then `sort_order`.",
            "items": {
              "$ref": "#/components/schemas/MealPlanItem"
            }
          }
        }
      },
      "WorkoutExercise": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "exercise_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "A library exercise. Read it with `GET /v1/patient/library/{library_item_id}`.",
            "example": "5a7c9e1b-3d5f-4a8c-9e2b-4d6f8a0c2e4f"
          },
          "name": {
            "type": "string",
            "example": "Goblet squat"
          },
          "sets": {
            "type": [
              "integer",
              "null"
            ],
            "example": 3
          },
          "reps": {
            "type": [
              "string",
              "null"
            ],
            "description": "A count or a range, for example `10` or `8-12`.",
            "example": "8-12"
          },
          "rest_s": {
            "type": [
              "integer",
              "null"
            ],
            "example": 60
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "example": "Keep your chest up"
          },
          "media_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Demonstration video or image from the library.",
            "example": "https://media.example.com/exercises/goblet-squat.mp4"
          }
        }
      },
      "WorkoutPlanItem": {
        "type": "object",
        "required": [
          "id",
          "day_index",
          "sort_order",
          "title",
          "exercises"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "1b3d5f7a-9c2e-4a6b-8d0f-2e4a6c8e0b2d"
          },
          "day_index": {
            "type": "integer",
            "minimum": 0,
            "example": 1
          },
          "sort_order": {
            "type": "integer",
            "example": 0
          },
          "title": {
            "type": "string",
            "example": "Full-body strength A"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "example": "Three moves, three sets each. Stop two reps before failure."
          },
          "duration_min": {
            "type": [
              "integer",
              "null"
            ],
            "example": 30
          },
          "exercises": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkoutExercise"
            }
          }
        }
      },
      "WorkoutPlan": {
        "type": "object",
        "required": [
          "id",
          "version",
          "status",
          "title",
          "published_by",
          "items"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5cb-2b3c-7d4e-8f50-6a7b8c9d0e12"
          },
          "protocol_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "example": "0190f5c6-9cad-7e12-8f34-5a6b7c8d9e01"
          },
          "version": {
            "type": "integer",
            "example": 1
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "superseded"
            ],
            "example": "active"
          },
          "title": {
            "type": "string",
            "example": "Muscle-preserving strength, weeks 5-8"
          },
          "starts_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "example": "2026-10-26"
          },
          "published_by": {
            "$ref": "#/components/schemas/PublishedBy"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkoutPlanItem"
            }
          }
        }
      },
      "MealSwapOptionsRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "maxLength": 500,
            "description": "Why the patient wants a swap, in their words. The AI Coach uses it to choose options.",
            "example": "I don't like fish"
          },
          "avoid": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string"
            },
            "example": [
              "fish"
            ]
          }
        }
      },
      "MealSwapOption": {
        "type": "object",
        "required": [
          "option_id",
          "title",
          "details"
        ],
        "properties": {
          "option_id": {
            "type": "string",
            "description": "Pass it to the swap call before `expires_at`.",
            "example": "opt_1"
          },
          "title": {
            "type": "string",
            "example": "Chicken and quinoa bowl"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "example": "Grilled chicken, quinoa, roasted vegetables"
          },
          "protein_g": {
            "type": [
              "number",
              "null"
            ],
            "example": 38
          },
          "calories_kcal": {
            "type": [
              "integer",
              "null"
            ],
            "example": 480
          },
          "details": {
            "$ref": "#/components/schemas/MealDetails"
          }
        }
      },
      "MealSwapOptions": {
        "type": "object",
        "required": [
          "item_id",
          "options",
          "expires_at"
        ],
        "properties": {
          "item_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
          },
          "options": {
            "type": "array",
            "description": "Only options that keep the protocol's targets and the rule-matrix constraints (allergies, foods to avoid,\ncalorie floor). Empty when none does; `note` then says why.\n",
            "items": {
              "$ref": "#/components/schemas/MealSwapOption"
            }
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "example": null
          },
          "expires_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "MealSwapRequest": {
        "type": "object",
        "required": [
          "option_id"
        ],
        "properties": {
          "option_id": {
            "type": "string",
            "example": "opt_1"
          },
          "reason": {
            "type": "string",
            "maxLength": 500,
            "example": "I don't like fish"
          }
        }
      },
      "MealRatingInput": {
        "type": "object",
        "required": [
          "rating"
        ],
        "additionalProperties": false,
        "properties": {
          "rating": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "example": 2
          },
          "comment": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500,
            "example": "Too sweet for me."
          }
        }
      },
      "LibraryKind": {
        "type": "string",
        "enum": [
          "recipe",
          "exercise"
        ],
        "example": "recipe"
      },
      "LibraryTags": {
        "type": "array",
        "description": "Labels for filtering, for example `high_protein`, `fiber_rich`, `low_appetite`, `mild_nausea`,\n`heartburn_friendly` and `dose_day` on recipes. New tags may be added.\n",
        "items": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "example": [
          "high_protein",
          "mild_nausea"
        ]
      },
      "LibraryItemSummary": {
        "type": "object",
        "required": [
          "id",
          "kind",
          "title",
          "tags",
          "favorite"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
          },
          "kind": {
            "$ref": "#/components/schemas/LibraryKind"
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "example": "greek-yogurt-protein-bowl"
          },
          "title": {
            "type": "string",
            "example": "Greek yogurt protein bowl"
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "A meal course for recipes, a body area for exercises.",
            "example": "breakfast"
          },
          "tags": {
            "$ref": "#/components/schemas/LibraryTags"
          },
          "thumbnail_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "example": "https://media.example.com/library/greek-yogurt-protein-bowl-thumb.jpg"
          },
          "calories_kcal": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Recipes only, per serving.",
            "example": 320
          },
          "favorite": {
            "type": "boolean",
            "description": "True when the patient saved it.",
            "example": false
          },
          "protein_g": {
            "type": [
              "number",
              "null"
            ],
            "description": "Recipes only, per serving.",
            "example": 31
          }
        }
      },
      "LibraryItemList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LibraryItemSummary"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "LibraryMedia": {
        "type": "object",
        "required": [
          "kind",
          "url"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "image",
              "video"
            ],
            "example": "image"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Library media is not patient data, so this is a lasting CDN link.",
            "example": "https://media.example.com/library/greek-yogurt-protein-bowl.jpg"
          },
          "thumbnail_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "example": null
          }
        }
      },
      "items": {
        "type": "string",
        "enum": [
          "american",
          "italian",
          "mexican",
          "chinese",
          "japanese",
          "thai",
          "korean",
          "indian",
          "french",
          "middle_eastern"
        ]
      },
      "appliances": {
        "type": "array",
        "uniqueItems": true,
        "items": {
          "type": "string",
          "enum": [
            "stove_range",
            "oven",
            "microwave",
            "air_fryer",
            "slow_cooker",
            "pressure_cooker",
            "blender",
            "food_processor",
            "grill",
            "stand_mixer"
          ]
        },
        "example": [
          "stove_range",
          "microwave",
          "air_fryer"
        ]
      },
      "RecipeNutrients": {
        "type": "object",
        "description": "Per serving.",
        "properties": {
          "calories_kcal": {
            "type": "integer",
            "example": 320
          },
          "protein_g": {
            "type": "number",
            "example": 31
          },
          "carbs_g": {
            "type": "number",
            "example": 30
          },
          "fat_g": {
            "type": "number",
            "example": 9
          },
          "fiber_g": {
            "type": "number",
            "example": 6
          },
          "sugar_g": {
            "type": "number",
            "example": 18
          },
          "sodium_mg": {
            "type": "integer",
            "example": 110
          }
        }
      },
      "RecipeDetails": {
        "type": "object",
        "required": [
          "servings",
          "ingredients",
          "steps",
          "nutrients",
          "allergens",
          "diets"
        ],
        "properties": {
          "servings": {
            "type": "integer",
            "minimum": 1,
            "example": 1
          },
          "serving_size": {
            "type": [
              "string",
              "null"
            ],
            "example": "1 bowl (about 300 g)"
          },
          "prep_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "example": 5
          },
          "cook_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "example": 0
          },
          "difficulty": {
            "type": "string",
            "enum": [
              "easy",
              "medium",
              "hard"
            ],
            "example": "easy"
          },
          "cuisine": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/items"
              },
              {
                "type": "null"
              }
            ],
            "example": null
          },
          "meal_types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MealType"
            },
            "example": [
              "breakfast",
              "snack"
            ]
          },
          "appliances": {
            "$ref": "#/components/schemas/appliances"
          },
          "ingredients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Ingredient"
            },
            "example": [
              {
                "name": "Greek yogurt, plain, nonfat",
                "quantity": 200,
                "unit": "g"
              },
              {
                "name": "Blueberries",
                "quantity": 75,
                "unit": "g"
              },
              {
                "name": "Chia seeds",
                "quantity": 10,
                "unit": "g"
              }
            ]
          },
          "steps": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "Spoon the yogurt into a bowl",
              "Top with the blueberries and chia seeds"
            ]
          },
          "nutrients": {
            "$ref": "#/components/schemas/RecipeNutrients"
          },
          "allergens": {
            "type": "array",
            "description": "The FDA major allergens the recipe contains. Empty when it contains none.",
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/FoodAllergen"
            },
            "example": [
              "milk"
            ]
          },
          "diets": {
            "type": "array",
            "description": "The dietary restrictions the recipe fits.",
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/DietaryRestriction"
            },
            "example": [
              "vegetarian",
              "gluten_free"
            ]
          },
          "why": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why it suits someone on a GLP-1, in one or two sentences.",
            "example": "Small, cold and high in protein, so it is easy to eat on a low-appetite day."
          }
        }
      },
      "ExerciseDetails": {
        "type": "object",
        "required": [
          "instructions"
        ],
        "properties": {
          "focus": {
            "type": [
              "string",
              "null"
            ],
            "example": "Lower body"
          },
          "muscle_groups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "quadriceps",
              "glutes"
            ]
          },
          "equipment": {
            "type": "array",
            "description": "Empty for bodyweight exercises.",
            "items": {
              "type": "string"
            },
            "example": [
              "dumbbell"
            ]
          },
          "difficulty": {
            "type": "string",
            "enum": [
              "beginner",
              "intermediate",
              "advanced"
            ],
            "example": "beginner"
          },
          "starting_position": {
            "type": [
              "string",
              "null"
            ],
            "example": "Stand with feet shoulder-width apart, holding one dumbbell at your chest."
          },
          "instructions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "Sit back and down until your thighs are parallel to the floor",
              "Push through your heels to stand"
            ]
          },
          "key_points": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "Keep your chest up",
              "Knees track over your toes"
            ]
          }
        }
      },
      "LibraryItem": {
        "type": "object",
        "required": [
          "id",
          "kind",
          "title",
          "tags",
          "media",
          "favorite",
          "my_rating"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
          },
          "kind": {
            "$ref": "#/components/schemas/LibraryKind"
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "example": "greek-yogurt-protein-bowl"
          },
          "title": {
            "type": "string",
            "example": "Greek yogurt protein bowl"
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "example": "A no-cook breakfast with 31 g of protein."
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "example": "breakfast"
          },
          "tags": {
            "$ref": "#/components/schemas/LibraryTags"
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LibraryMedia"
            }
          },
          "recipe": {
            "description": "Set when `kind` is `recipe`.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/RecipeDetails"
              },
              {
                "type": "null"
              }
            ]
          },
          "exercise": {
            "description": "Set when `kind` is `exercise`.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ExerciseDetails"
              },
              {
                "type": "null"
              }
            ]
          },
          "favorite": {
            "type": "boolean",
            "example": false
          },
          "my_rating": {
            "description": "The patient's rating of a recipe, or null.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MealRating"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "CareConversation": {
        "type": "object",
        "required": [
          "id",
          "coach",
          "unread_count"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
          },
          "coach": {
            "$ref": "#/components/schemas/CareTeamMember"
          },
          "last_message_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-26T13:40:00Z"
          },
          "unread_count": {
            "type": "integer",
            "example": 1
          },
          "patient_last_read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-26T09:00:00Z"
          },
          "coach_last_read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-26T13:40:00Z"
          }
        }
      },
      "CareConversationList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "One thread per coach on the care team.",
            "items": {
              "$ref": "#/components/schemas/CareConversation"
            }
          }
        }
      },
      "MessageSender": {
        "type": "object",
        "required": [
          "type",
          "display_name"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "patient",
              "coach",
              "ai",
              "system"
            ],
            "example": "coach"
          },
          "display_name": {
            "type": "string",
            "description": "\"AI Coach\" for `ai`; the coach display name for `coach`.",
            "example": "Maya C."
          },
          "care_role": {
            "type": [
              "string",
              "null"
            ],
            "description": "For coaches.",
            "example": "health_coach"
          }
        }
      },
      "MessageAttachment": {
        "type": "object",
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "protocol_card",
              "notice",
              "image"
            ],
            "example": "protocol_card"
          },
          "protocol_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "example": "0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90"
          },
          "text": {
            "type": [
              "string",
              "null"
            ],
            "example": null
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "For `image`. A pre-signed link that expires within minutes; read the message again for a new one.",
            "example": null
          },
          "content_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "For `image`.",
            "example": null
          }
        }
      },
      "Reaction": {
        "type": "object",
        "required": [
          "emoji",
          "by"
        ],
        "properties": {
          "emoji": {
            "type": "string",
            "example": "👍"
          },
          "by": {
            "type": "string",
            "enum": [
              "patient",
              "coach"
            ],
            "example": "patient"
          }
        }
      },
      "MessageFeedback": {
        "type": "object",
        "required": [
          "rating"
        ],
        "properties": {
          "rating": {
            "type": "string",
            "enum": [
              "up",
              "down"
            ],
            "example": "up"
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000,
            "example": "Helpful, thanks"
          }
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "id",
          "conversation_id",
          "sender",
          "body",
          "created_at",
          "deleted",
          "reactions"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23"
          },
          "conversation_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
          },
          "sender": {
            "$ref": "#/components/schemas/MessageSender"
          },
          "body": {
            "type": "string",
            "description": "Empty when the message was deleted.",
            "example": "Great job on your protein yesterday. How is the nausea today?"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "edited_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          },
          "deleted": {
            "type": "boolean",
            "example": false
          },
          "seen_by_other_side": {
            "type": "boolean",
            "description": "True when the other side has read up to this message.",
            "example": true
          },
          "attachment": {
            "description": "A protocol card, a notice in the thread, or a photo the patient sent their coach.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MessageAttachment"
              },
              {
                "type": "null"
              }
            ]
          },
          "reactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Reaction"
            }
          },
          "feedback": {
            "description": "The patient's rating, on the AI Coach's messages only.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MessageFeedback"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "MessageList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Newest first.",
            "items": {
              "$ref": "#/components/schemas/Message"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "CareMessageInput": {
        "type": "object",
        "description": "Text, a photo, or both.",
        "anyOf": [
          {
            "required": [
              "body"
            ]
          },
          {
            "required": [
              "photo_upload_id"
            ]
          }
        ],
        "additionalProperties": false,
        "properties": {
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4000,
            "example": "Nausea is better today. Can I swap dinner?"
          },
          "photo_upload_id": {
            "$ref": "#/components/schemas/Uuid",
            "description": "From `POST /v1/patient/message-photos`, after the photo was uploaded. One photo per message.",
            "example": "9f3d5b71-2a4c-4e6f-8b0d-1c3e5a7b9d2f"
          }
        }
      },
      "ReadMarker": {
        "type": "object",
        "properties": {
          "read_at": {
            "$ref": "#/components/schemas/Timestamp",
            "description": "Defaults to now. Everything sent up to this time counts as read."
          }
        }
      },
      "ReadState": {
        "type": "object",
        "required": [
          "conversation_id",
          "patient_last_read_at",
          "unread_count"
        ],
        "properties": {
          "conversation_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
          },
          "patient_last_read_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "unread_count": {
            "type": "integer",
            "example": 0
          }
        }
      },
      "MessageUpdate": {
        "type": "object",
        "description": "JSON Merge Patch (RFC 7396).",
        "required": [
          "body"
        ],
        "additionalProperties": false,
        "properties": {
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4000,
            "example": "Nausea is better today. Can I swap tonight's dinner?"
          }
        }
      },
      "ReactionsInput": {
        "type": "object",
        "required": [
          "emojis"
        ],
        "properties": {
          "emojis": {
            "type": "array",
            "description": "The patient's full set of reactions on the message. An empty list removes them all.",
            "maxItems": 10,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 16
            },
            "example": [
              "👍"
            ]
          }
        }
      },
      "Reactions": {
        "type": "object",
        "required": [
          "message_id",
          "reactions"
        ],
        "properties": {
          "message_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23"
          },
          "reactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Reaction"
            }
          }
        }
      },
      "FeedbackQuestion": {
        "type": "object",
        "required": [
          "key",
          "kind",
          "label",
          "required"
        ],
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "The key of this question's answer in `answers`.",
            "example": "overall"
          },
          "kind": {
            "type": "string",
            "enum": [
              "rating",
              "thumbs",
              "choice",
              "text"
            ],
            "description": "How to show it and what the answer is:\n\n| Kind | Show | Answer |\n| --- | --- | --- |\n| `rating` | 1 to `scale_max` stars | an integer |\n| `thumbs` | thumbs up and down | `up` or `down` |\n| `choice` | one of `options` | the option's `value` |\n| `text` | a comment box up to `max_length` | a string |\n\nNew kinds may be added; skip a question whose kind you don't know unless it is `required`.\n",
            "example": "rating"
          },
          "label": {
            "type": "string",
            "example": "How would you rate your coach so far?"
          },
          "required": {
            "type": "boolean",
            "example": true
          },
          "scale_max": {
            "type": [
              "integer",
              "null"
            ],
            "description": "For `rating`.",
            "example": 5
          },
          "options": {
            "type": "array",
            "description": "For `choice`.",
            "items": {
              "type": "object",
              "required": [
                "value",
                "label"
              ],
              "properties": {
                "value": {
                  "type": "string",
                  "example": "nutrition"
                },
                "label": {
                  "type": "string",
                  "example": "Nutrition"
                }
              }
            }
          },
          "max_length": {
            "type": [
              "integer",
              "null"
            ],
            "description": "For `text`.",
            "example": null
          }
        }
      },
      "FeedbackSurvey": {
        "type": "object",
        "required": [
          "code",
          "version",
          "title",
          "questions"
        ],
        "properties": {
          "code": {
            "type": "string",
            "example": "coach_feedback"
          },
          "version": {
            "type": "integer",
            "example": 1
          },
          "title": {
            "type": "string",
            "example": "How is coaching going?"
          },
          "intro": {
            "type": [
              "string",
              "null"
            ],
            "example": "It takes less than a minute."
          },
          "questions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeedbackQuestion"
            }
          }
        }
      },
      "FeedbackAnswers": {
        "type": "object",
        "description": "One value per question `key`; leave out questions the patient skipped.",
        "additionalProperties": {
          "oneOf": [
            {
              "type": "integer"
            },
            {
              "type": "string"
            }
          ]
        },
        "example": {
          "overall": 5,
          "helpful": "up",
          "more_help_with": "side_effects",
          "comment": "Maya's tips for nausea made a real difference."
        }
      },
      "FeedbackRequest": {
        "type": "object",
        "required": [
          "id",
          "status",
          "care_role",
          "coach",
          "survey",
          "requested_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6"
          },
          "status": {
            "type": "string",
            "enum": [
              "requested",
              "answered",
              "dismissed",
              "expired"
            ],
            "example": "requested"
          },
          "care_role": {
            "$ref": "#/components/schemas/CareRole"
          },
          "coach": {
            "$ref": "#/components/schemas/CareTeamMember",
            "description": "The coach the feedback is about, as the patient sees them."
          },
          "survey": {
            "$ref": "#/components/schemas/FeedbackSurvey"
          },
          "requested_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "After this the popup can't be answered; don't show it.",
            "example": "2026-11-23T00:00:00Z"
          },
          "answers": {
            "description": "Set once answered.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/FeedbackAnswers"
              },
              {
                "type": "null"
              }
            ]
          },
          "answered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": null
          }
        }
      },
      "FeedbackRequestList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Popups waiting for an answer, oldest first.",
            "items": {
              "$ref": "#/components/schemas/FeedbackRequest"
            }
          }
        }
      },
      "FeedbackResponseInput": {
        "type": "object",
        "required": [
          "answers"
        ],
        "additionalProperties": false,
        "properties": {
          "answers": {
            "$ref": "#/components/schemas/FeedbackAnswers"
          }
        }
      },
      "AiCoachConversation": {
        "type": "object",
        "required": [
          "id",
          "created_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5cc-3c4d-7e5f-8061-7a8b9c0d1e23"
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "example": "Dinner ideas"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "last_message_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "example": "2026-10-26T11:01:30Z"
          }
        }
      },
      "AiCoachConversationList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiCoachConversation"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "AiCoachConversationCreate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 120,
            "example": "Dinner ideas"
          }
        }
      },
      "MessageInput": {
        "type": "object",
        "required": [
          "body"
        ],
        "properties": {
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4000,
            "example": "Nausea is better today. Can I swap dinner?"
          }
        }
      },
      "AiCoachEscalation": {
        "type": "object",
        "description": "The AI Coach handed this message to a human. `notice` is what to show the patient.",
        "required": [
          "to",
          "notice"
        ],
        "properties": {
          "to": {
            "type": "string",
            "enum": [
              "coach",
              "prescriber"
            ],
            "description": "`coach` on the coached plan; `prescriber` (a clinical flag to the brand) on `ai_only`.",
            "example": "prescriber"
          },
          "notice": {
            "type": "string",
            "example": "I've let your prescriber's team know so they can follow up with you."
          }
        }
      },
      "AiCoachReply": {
        "type": "object",
        "required": [
          "reply_to_message_id",
          "status",
          "show_emergency_guidance"
        ],
        "properties": {
          "reply_to_message_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5cc-4d5e-7f60-8172-8b9c0d1e2f34"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed"
            ],
            "example": "completed"
          },
          "message": {
            "description": "The AI Coach's reply, once `completed`.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Message"
              },
              {
                "type": "null"
              }
            ]
          },
          "escalation": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AiCoachEscalation"
              },
              {
                "type": "null"
              }
            ]
          },
          "show_emergency_guidance": {
            "type": "boolean",
            "description": "When true, show the 911 and 988 guidance above the reply.",
            "example": false
          }
        }
      },
      "AiCoachMessageAccepted": {
        "type": "object",
        "required": [
          "message",
          "reply"
        ],
        "properties": {
          "message": {
            "$ref": "#/components/schemas/Message"
          },
          "reply": {
            "$ref": "#/components/schemas/AiCoachReply"
          }
        }
      },
      "FeedbackInput": {
        "type": "object",
        "required": [
          "rating"
        ],
        "properties": {
          "rating": {
            "type": "string",
            "enum": [
              "up",
              "down"
            ],
            "example": "down"
          },
          "note": {
            "type": "string",
            "maxLength": 1000,
            "example": "The swap still had fish in it"
          }
        }
      },
      "Feedback": {
        "type": "object",
        "required": [
          "message_id",
          "rating"
        ],
        "properties": {
          "message_id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5cc-5e6f-7071-9283-9c0d1e2f3a45"
          },
          "rating": {
            "type": "string",
            "enum": [
              "up",
              "down"
            ],
            "example": "down"
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "example": "The swap still had fish in it"
          }
        }
      },
      "AiCoachMemory": {
        "type": "object",
        "required": [
          "id",
          "summary",
          "confirmed",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "6c8e0a2b-4d6f-4a1c-8e3b-5d7f9a1c3e5b"
          },
          "summary": {
            "type": "string",
            "description": "What the AI Coach remembers, in one line.",
            "example": "Doesn't like fish"
          },
          "confirmed": {
            "type": "boolean",
            "description": "The patient confirmed it is right.",
            "example": false
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "AiCoachMemoryList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Newest first.",
            "items": {
              "$ref": "#/components/schemas/AiCoachMemory"
            }
          }
        }
      },
      "AiCoachMemoryUpdate": {
        "type": "object",
        "required": [
          "confirmed"
        ],
        "additionalProperties": false,
        "properties": {
          "confirmed": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "ReminderList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Soonest first.",
            "items": {
              "$ref": "#/components/schemas/Reminder"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "Snooze": {
        "type": "object",
        "required": [
          "minutes"
        ],
        "properties": {
          "minutes": {
            "type": "integer",
            "minimum": 5,
            "maximum": 1440,
            "example": 60
          }
        }
      },
      "LocalTime": {
        "type": "string",
        "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
        "description": "Time of day in the patient's time zone, `HH:MM`.",
        "example": "09:00"
      },
      "ReminderKindSetting": {
        "type": "object",
        "required": [
          "enabled"
        ],
        "additionalProperties": false,
        "properties": {
          "enabled": {
            "type": "boolean",
            "example": true
          },
          "time": {
            "description": "When the reminder is sent. In a `PATCH`, `null` goes back to the brand's default.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/LocalTime"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "CheckInReminderSetting": {
        "type": "object",
        "required": [
          "enabled"
        ],
        "additionalProperties": false,
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Off stops the reminder only; the check-in form stays assigned until it expires.",
            "example": true
          }
        }
      },
      "AiCoachOutreachSetting": {
        "type": "object",
        "required": [
          "enabled"
        ],
        "additionalProperties": false,
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Off stops messages the AI Coach starts itself (after an injection, after a missed dose, after quiet days, the\nweekly recap, or when the brand asks). Replies to the patient's own messages are not affected.\n",
            "example": true
          }
        }
      },
      "QuietHours": {
        "type": "object",
        "required": [
          "start",
          "end"
        ],
        "additionalProperties": false,
        "description": "Nothing is sent between `start` and `end`; a reminder due inside waits until `end`.",
        "properties": {
          "start": {
            "$ref": "#/components/schemas/LocalTime"
          },
          "end": {
            "$ref": "#/components/schemas/LocalTime"
          }
        }
      },
      "ReminderSettings": {
        "type": "object",
        "description": "The settings in force, with the brand's defaults filled in for anything the patient has not set.",
        "required": [
          "injection",
          "check_in",
          "log_nudge",
          "habit",
          "ai_coach_outreach",
          "quiet_hours"
        ],
        "properties": {
          "injection": {
            "$ref": "#/components/schemas/ReminderKindSetting",
            "description": "The day comes from the prescriber's injection schedule; the patient sets only the time."
          },
          "check_in": {
            "$ref": "#/components/schemas/CheckInReminderSetting"
          },
          "log_nudge": {
            "$ref": "#/components/schemas/ReminderKindSetting"
          },
          "habit": {
            "$ref": "#/components/schemas/ReminderKindSetting"
          },
          "ai_coach_outreach": {
            "$ref": "#/components/schemas/AiCoachOutreachSetting"
          },
          "quiet_hours": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QuietHours"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "ReminderSettingsUpdate": {
        "type": "object",
        "description": "JSON Merge Patch (RFC 7396). Send only the kinds to change; `quiet_hours: null` turns quiet hours off.\n",
        "minProperties": 1,
        "additionalProperties": false,
        "properties": {
          "injection": {
            "$ref": "#/components/schemas/ReminderKindSetting"
          },
          "check_in": {
            "$ref": "#/components/schemas/CheckInReminderSetting"
          },
          "log_nudge": {
            "$ref": "#/components/schemas/ReminderKindSetting"
          },
          "habit": {
            "$ref": "#/components/schemas/ReminderKindSetting"
          },
          "ai_coach_outreach": {
            "$ref": "#/components/schemas/AiCoachOutreachSetting"
          },
          "quiet_hours": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QuietHours"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "ClinicalFlagStatus": {
        "type": "string",
        "enum": [
          "open",
          "acknowledged",
          "resolved",
          "dismissed"
        ],
        "description": "`open` until a prescriber acknowledges it; `acknowledged` until resolved. `dismissed` flags were closed by\nTeraRx as raised in error and never change risk.\n",
        "example": "open"
      },
      "TriggeringRecord": {
        "type": "object",
        "required": [
          "type",
          "id",
          "occurred_at"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "symptom_log",
              "meal_log",
              "workout_log",
              "injection_log",
              "daily_log",
              "message"
            ],
            "example": "symptom_log"
          },
          "id": {
            "type": "string",
            "description": "The record id; for `daily_log` the date.",
            "example": "0190f5c9-7f80-7192-8cb4-3d4e5f607182"
          },
          "occurred_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Set when whoever logged the record deleted it later, for example a symptom logged by mistake. The flag stays\nopen until a prescriber resolves it.\n",
            "example": null
          }
        }
      },
      "TimelineEntry": {
        "type": "object",
        "description": "What happened around the flag, oldest first, so the prescriber sees the trend.",
        "required": [
          "occurred_at",
          "kind"
        ],
        "properties": {
          "occurred_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "kind": {
            "type": "string",
            "enum": [
              "symptom",
              "injection",
              "missed_injection",
              "weight",
              "dose_change",
              "ai_coach_escalation",
              "coach_note"
            ],
            "example": "symptom"
          },
          "symptom": {
            "type": [
              "string",
              "null"
            ],
            "example": "vomiting"
          },
          "severity": {
            "type": [
              "integer",
              "null"
            ],
            "example": 4
          },
          "dose_mg": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "text": {
            "type": [
              "string",
              "null"
            ],
            "description": "The patient's note on the log, the AI Coach's escalation summary or the coach's note.",
            "example": "Could not keep water down this morning"
          }
        }
      },
      "Prescriber": {
        "type": "object",
        "description": "The individual prescriber acting through a clinical client. `name` and at least one of `npi` or `prescriber_id`\nare required. Stored on the flag with the client that sent it (`alerts.*_by_prescriber`).\n",
        "required": [
          "name"
        ],
        "anyOf": [
          {
            "required": [
              "npi"
            ]
          },
          {
            "required": [
              "prescriber_id"
            ]
          }
        ],
        "properties": {
          "prescriber_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "The prescriber's id in your system.",
            "example": "dr-00417"
          },
          "npi": {
            "type": "string",
            "pattern": "^[0-9]{10}$",
            "description": "National Provider Identifier. Its check digit is verified (Luhn with the `80840` prefix); a bad one is `422 validation_failed`.",
            "example": "1234567893"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Display name, shown to coaches on the flag.",
            "example": "Dr. Alex Morgan, NP"
          }
        }
      },
      "AcknowledgementRecord": {
        "type": "object",
        "required": [
          "at",
          "by"
        ],
        "properties": {
          "at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "by": {
            "$ref": "#/components/schemas/Prescriber"
          }
        }
      },
      "ResolutionRecord": {
        "type": "object",
        "required": [
          "at",
          "by",
          "resolution_note",
          "new_risk_level"
        ],
        "properties": {
          "at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "by": {
            "$ref": "#/components/schemas/Prescriber"
          },
          "resolution_note": {
            "type": "string",
            "example": "Spoke with patient. Holding at 0.5 mg for two more weeks; antiemetic prescribed."
          },
          "new_risk_level": {
            "$ref": "#/components/schemas/RiskLevel"
          }
        }
      },
      "ClinicalFlag": {
        "type": "object",
        "required": [
          "id",
          "status",
          "severity",
          "title",
          "source",
          "enrollment_id",
          "external_patient_id",
          "plan_code",
          "risk_level",
          "details",
          "triggering_records",
          "timeline",
          "created_at",
          "redelivery_count"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid",
            "example": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6"
          },
          "status": {
            "$ref": "#/components/schemas/ClinicalFlagStatus"
          },
          "severity": {
            "$ref": "#/components/schemas/Severity"
          },
          "title": {
            "type": "string",
            "example": "Acute GI distress"
          },
          "rule_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "The alert rule that raised it, for example `acute_gi`, `red_flag_symptom`, `moderate_side_effects`.",
            "example": "acute_gi"
          },
          "source": {
            "type": "string",
            "enum": [
              "alert_rule",
              "ai_coach_escalation",
              "coach"
            ],
            "description": "An alert rule on the logs, the AI Coach escalating a conversation (`ai_only`), or a coach.",
            "example": "alert_rule"
          },
          "enrollment_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "external_patient_id": {
            "$ref": "#/components/schemas/ExternalId",
            "description": "The brand's patient id, to find the patient in your own system."
          },
          "plan_code": {
            "$ref": "#/components/schemas/PlanCode"
          },
          "risk_level": {
            "$ref": "#/components/schemas/RiskLevel",
            "description": "The enrollment's risk level now."
          },
          "raised_risk_to": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "normal",
              "elevated",
              "high",
              null
            ],
            "description": "The level this flag raised the enrollment to.",
            "example": "high"
          },
          "details": {
            "type": "object",
            "description": "What triggered the flag.",
            "properties": {
              "symptom": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "vomiting"
              },
              "severity_score": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "The symptom severity (1-5) that triggered it.",
                "example": 4
              },
              "escalation_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "red_flag_symptom",
                  "dosing_question",
                  "medication_question",
                  "new_side_effect",
                  "severe_side_effect",
                  null
                ],
                "description": "Why the AI Coach escalated, for `ai_coach_escalation` flags.",
                "example": null
              },
              "values": {
                "type": "object",
                "description": "The values the rule compared, for example `{\"protein_pct\": 0.55}`.",
                "additionalProperties": {
                  "type": [
                    "number",
                    "string",
                    "boolean",
                    "null"
                  ]
                },
                "example": {}
              }
            }
          },
          "triggering_records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TriggeringRecord"
            }
          },
          "timeline": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimelineEntry"
            }
          },
          "treatment": {
            "description": "The treatment when the flag was raised.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/PatientTreatment"
              },
              {
                "type": "null"
              }
            ]
          },
          "coach_note": {
            "type": [
              "string",
              "null"
            ],
            "description": "The coach's note, on the coached plan.",
            "example": null
          },
          "ack_due_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Acknowledge before this time, set from the brand's agreed acknowledgement time. If it passes, `clinical.flag_redelivered` is sent.",
            "example": "2026-10-26T16:05:00Z"
          },
          "redelivery_count": {
            "type": "integer",
            "description": "How many times the flag has been re-delivered for a missed `ack_due_at`.",
            "example": 0
          },
          "acknowledgement": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AcknowledgementRecord"
              },
              {
                "type": "null"
              }
            ]
          },
          "resolution": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ResolutionRecord"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "ClinicalFlagList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClinicalFlag"
            }
          },
          "next_cursor": {
            "$ref": "#/components/schemas/NextCursor"
          }
        }
      },
      "AcknowledgeInput": {
        "type": "object",
        "required": [
          "on_behalf_of"
        ],
        "properties": {
          "on_behalf_of": {
            "$ref": "#/components/schemas/Prescriber"
          }
        }
      },
      "ResolveInput": {
        "type": "object",
        "required": [
          "on_behalf_of",
          "resolution_note",
          "new_risk_level"
        ],
        "properties": {
          "on_behalf_of": {
            "$ref": "#/components/schemas/Prescriber"
          },
          "resolution_note": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4000,
            "description": "What the prescriber decided. Shown to the care team; never sent in webhooks.",
            "example": "Spoke with patient. Holding at 0.5 mg for two more weeks; antiemetic prescribed."
          },
          "new_risk_level": {
            "$ref": "#/components/schemas/RiskLevel",
            "description": "The enrollment's risk level from now on. This is the only way risk goes down."
          }
        }
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer"
        },
        "example": 30
      }
    },
    "responses": {
      "TooManyRequests": {
        "description": "Rate limit or daily cap reached. Wait `Retry-After` seconds.",
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Too Many Requests",
              "status": 429,
              "detail": "Rate limit of 600 requests per minute reached.",
              "code": "rate_limited",
              "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "A dependency (for example the AI model) is temporarily unavailable. Retry after `Retry-After` seconds.",
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Service Unavailable",
              "status": 503,
              "detail": "The AI Coach is temporarily unavailable. Try again shortly.",
              "code": "ai_unavailable",
              "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The access token is missing, expired or revoked.",
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          },
          "WWW-Authenticate": {
            "description": "The scheme to authenticate with.",
            "schema": {
              "type": "string"
            },
            "example": "Bearer error=\"invalid_token\""
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Unauthorized",
              "status": 401,
              "detail": "The access token has expired. Request a new one.",
              "code": "token_expired",
              "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The token is valid but lacks the scope, or the resource is not available on the patient's plan.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Forbidden",
              "status": 403,
              "detail": "This operation needs the enrollments:write scope.",
              "code": "insufficient_scope",
              "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          }
        }
      },
      "UnprocessableEntity": {
        "description": "A path, query or header value, or the body, fails validation (for example an id that isn't a UUID, or a\nfield out of range), or an `Idempotency-Key` was reused with a different body. `errors` lists each problem.\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "validation_failed": {
                "summary": "Field validation",
                "value": {
                  "type": "about:blank",
                  "title": "Unprocessable Content",
                  "status": 422,
                  "detail": "1 field is invalid.",
                  "code": "validation_failed",
                  "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                  "errors": [
                    {
                      "pointer": "/patient/state_code",
                      "code": "invalid_format",
                      "detail": "Must be a two-letter USPS state code."
                    }
                  ]
                }
              },
              "invalid_path_parameter": {
                "summary": "A malformed id in the path",
                "value": {
                  "type": "about:blank",
                  "title": "Unprocessable Content",
                  "status": 422,
                  "detail": "1 parameter is invalid.",
                  "code": "validation_failed",
                  "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b",
                  "errors": [
                    {
                      "pointer": "path:enrollment_id",
                      "code": "invalid_format",
                      "detail": "Must be a UUID."
                    }
                  ]
                }
              },
              "idempotency_key_reused": {
                "summary": "Key reused with a different body",
                "value": {
                  "type": "about:blank",
                  "title": "Unprocessable Content",
                  "status": 422,
                  "detail": "This Idempotency-Key was used with a different request body in the last 24 hours.",
                  "code": "idempotency_key_reused",
                  "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
                }
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          }
        }
      },
      "BadRequest": {
        "description": "The request is malformed (unparseable JSON, wrong content type, unknown query parameter).",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Bad Request",
              "status": 400,
              "detail": "The request body is not valid JSON.",
              "code": "malformed_request",
              "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          }
        }
      },
      "Conflict": {
        "description": "The request conflicts with the resource's current state, or a request with the same `Idempotency-Key` is still running.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Conflict",
              "status": 409,
              "detail": "The enrollment is cancelled and cannot be paused.",
              "code": "invalid_status_transition",
              "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          }
        }
      },
      "NotFound": {
        "description": "No such resource, or it belongs to another tenant or patient. The API does not tell the two apart,\nso ids cannot be probed across brands.\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Not Found",
              "status": 404,
              "detail": "No enrollment with this id is visible to this client.",
              "code": "enrollment_not_found",
              "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          }
        }
      },
      "Gone": {
        "description": "The resource existed but has expired.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Gone",
              "status": 410,
              "detail": "The export has expired. Create a new export request.",
              "code": "export_expired",
              "request_id": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "description": "Unique id of this request. Echoes a valid `X-Request-Id` you sent, otherwise generated. Also in every problem body.",
            "schema": {
              "type": "string"
            },
            "example": "req_019a3b2c-4d5e-7f60-8a1b-2c3d4e5f6a7b"
          },
          "RateLimit-Limit": {
            "description": "Requests allowed per minute for this client (600 by default, set per contract).",
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          "RateLimit-Remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer"
            },
            "example": 587
          },
          "RateLimit-Reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          }
        }
      },
      "WebhookReceived": {
        "description": "Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else (or no answer in time)\nis a failed attempt and is retried with backoff for 24 hours.\n"
      }
    },
    "parameters": {
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "Page size.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        },
        "example": 25
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "description": "The `next_cursor` from the previous page. Omit it for the first page.",
        "schema": {
          "type": "string",
          "maxLength": 512
        },
        "example": "eyJpZCI6IjAxOTBmNWMyIn0"
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body\nwithin 24 hours returns the first response (with `Idempotent-Replayed: true`) instead of creating a duplicate.\nThe same key with a different body is refused with `422 idempotency_key_reused`.\n",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 255
        },
        "example": "7d0c7f4e-1a8b-4c55-9d3e-2f6a1b0c9e84"
      },
      "EnrollmentId": {
        "name": "enrollment_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
      },
      "IdempotencyKeyOptional": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body).",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 255
        },
        "example": "3b9e5a10-6c2f-4d7e-8a41-9f0e2d1c7b36"
      },
      "ExternalLogId": {
        "name": "external_id",
        "in": "path",
        "required": true,
        "description": "Your `external_id` for the log, URL-encoded.",
        "schema": {
          "$ref": "#/components/schemas/ExternalId"
        },
        "example": "meal-77120"
      },
      "LogDate": {
        "name": "log_date",
        "in": "path",
        "required": true,
        "description": "The day, in the patient's time zone.",
        "schema": {
          "type": "string",
          "format": "date"
        },
        "example": "2026-10-26"
      },
      "EventId": {
        "name": "event_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7"
      },
      "DataRequestId": {
        "name": "data_request_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13"
      },
      "FormAssignmentId": {
        "name": "form_assignment_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2"
      },
      "FromDate": {
        "name": "from",
        "in": "query",
        "description": "First day to include, in the patient's time zone.",
        "schema": {
          "type": "string",
          "format": "date"
        },
        "example": "2026-10-20"
      },
      "ToDate": {
        "name": "to",
        "in": "query",
        "description": "Last day to include, in the patient's time zone. At most 92 days after `from`.",
        "schema": {
          "type": "string",
          "format": "date"
        },
        "example": "2026-10-26"
      },
      "MilestoneId": {
        "name": "milestone_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5e1-2a3b-7c4d-9e5f-6a7b8c9d0e1f"
      },
      "UploadId": {
        "name": "upload_id",
        "in": "path",
        "required": true,
        "description": "From `POST /v1/patient/meal-photos`.",
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e"
      },
      "LogId": {
        "name": "log_id",
        "in": "path",
        "required": true,
        "description": "The log's `id`.",
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60"
      },
      "ProtocolTypePath": {
        "name": "protocol_type",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/ProtocolType"
        },
        "example": "nutrition"
      },
      "ProtocolVersion": {
        "name": "version",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 2
      },
      "MealPlanItemId": {
        "name": "item_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
      },
      "LibraryItemId": {
        "name": "library_item_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
      },
      "ConversationId": {
        "name": "conversation_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
      },
      "MessageId": {
        "name": "message_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23"
      },
      "FeedbackRequestId": {
        "name": "feedback_request_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6"
      },
      "MemoryId": {
        "name": "memory_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "6c8e0a2b-4d6f-4a1c-8e3b-5d7f9a1c3e5b"
      },
      "ReminderId": {
        "name": "reminder_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5c5-4a5b-7c61-8d78-9e0f1a2b3c45"
      },
      "ClinicalFlagId": {
        "name": "flag_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6"
      },
      "WebhookTimestamp": {
        "name": "TeraRx-Timestamp",
        "in": "header",
        "required": true,
        "description": "Unix time in seconds when this delivery attempt was signed. Reject deliveries more than 5 minutes old.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9]{10}$"
        },
        "example": "1793023500"
      },
      "WebhookSignature": {
        "name": "TeraRx-Signature",
        "in": "header",
        "required": true,
        "description": "`v1=<hex>` where hex is HMAC-SHA256 over `<TeraRx-Timestamp>.<raw body>` with your webhook secret.\nDuring a secret rotation it carries two signatures, `v1=<new>,v1=<old>`; accept the delivery if any one matches.\n",
        "schema": {
          "type": "string",
          "pattern": "^v1=[0-9a-f]{64}(,v1=[0-9a-f]{64})*$"
        },
        "example": "v1=5e9f492e2cee549f0d1688a9d4a6d0505ea1687e5c293eb28a01bad16ee7aa2a"
      },
      "WebhookEventId": {
        "name": "TeraRx-Event-Id",
        "in": "header",
        "required": true,
        "description": "The event id, the same as `id` in the body. Retries of one event carry the same id; store it and ignore repeats.",
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7"
      }
    }
  },
  "x-tagGroups": [
    {
      "name": "Authentication",
      "tags": [
        "Auth",
        "Tenants"
      ]
    },
    {
      "name": "Brand server",
      "tags": [
        "Enrollments",
        "Treatment",
        "Consent",
        "Brand logs",
        "Events",
        "Reports",
        "Data requests"
      ]
    },
    {
      "name": "Patient app",
      "tags": [
        "Patient",
        "Progress",
        "Forms",
        "Logging",
        "Protocols and plans",
        "Meal swap",
        "Library",
        "Care messaging",
        "Feedback",
        "AI Coach",
        "Reminders"
      ]
    },
    {
      "name": "Prescriber system",
      "tags": [
        "Clinical flags"
      ]
    },
    {
      "name": "Webhooks",
      "tags": [
        "Webhooks"
      ]
    }
  ]
}