{
  "info": {
    "name": "TeraRx API v1",
    "description": "Every /v1 operation with the examples from the contract. Point base_url at the sandbox or the local mock; the pre-request script gets each caller its token. Synthetic data only.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "(() => {",
          "const path = pm.request.url.getPath();",
          "if (path.endsWith('/v1/oauth/token')) return;",
          "const caller = path.startsWith('/v1/patient') ? 'patient' : path.startsWith('/v1/clinical-flags') ? 'clinical' : 'brand';",
          "const tokenVar = caller + '_token';",
          "const expiresAt = Number(pm.environment.get(tokenVar + '_expires_at') || 0);",
          "if (pm.environment.get(tokenVar) && Date.now() < expiresAt - 30000) return;",
          "",
          "const form = (fields) => ({ mode: 'urlencoded', urlencoded: Object.entries(fields).map(([key, value]) => ({ key, value })) });",
          "const request = { url: pm.environment.get('base_url') + '/v1/oauth/token', method: 'POST', header: [] };",
          "if (caller === 'patient') {",
          "  // Sign a fresh assertion on your server (examples/node/sign-patient-jwt.mjs) and paste it in patient_assertion.",
          "  request.body = form({",
          "    grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',",
          "    subject_token: pm.environment.get('patient_assertion'),",
          "    subject_token_type: 'urn:ietf:params:oauth:token-type:jwt',",
          "  });",
          "} else {",
          "  const id = pm.environment.get(caller + '_client_id');",
          "  const secret = pm.environment.get(caller + '_client_secret');",
          "  request.header.push({ key: 'Authorization', value: 'Basic ' + btoa(id + ':' + secret) });",
          "  request.body = form({ grant_type: 'client_credentials' });",
          "}",
          "pm.sendRequest(request, (err, res) => {",
          "  if (err || res.code !== 200) throw new Error('Token request for ' + caller + ' failed: ' + (err || res.code));",
          "  const token = res.json();",
          "  pm.environment.set(tokenVar, token.access_token);",
          "  pm.environment.set(tokenVar + '_expires_at', String(Date.now() + token.expires_in * 1000));",
          "});",
          "})();"
        ]
      }
    }
  ],
  "item": [
    {
      "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",
      "item": [
        {
          "name": "Get an access token",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/x-www-form-urlencoded"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/oauth/token",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "oauth",
                "token"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                {
                  "key": "grant_type",
                  "value": "client_credentials"
                },
                {
                  "key": "scope",
                  "value": "enrollments:read enrollments:write logs:write"
                }
              ]
            },
            "auth": {
              "type": "basic",
              "basic": [
                {
                  "key": "username",
                  "value": "{{brand_client_id}}"
                },
                {
                  "key": "password",
                  "value": "{{brand_client_secret}}"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "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",
      "item": [
        {
          "name": "List the brands this client may act for",
          "request": {
            "method": "GET",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/tenants",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "tenants"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "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.",
      "item": [
        {
          "name": "List enrollments",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Your brand's enrollments, newest first. Filter by `external_patient_id` to find one patient's enrollments.",
            "url": {
              "raw": "{{base_url}}/v1/enrollments",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments"
              ],
              "query": [
                {
                  "key": "external_patient_id",
                  "value": "brand-pt-48213",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "active",
                  "disabled": true
                },
                {
                  "key": "risk_level",
                  "value": "high",
                  "disabled": true
                },
                {
                  "key": "plan_code",
                  "value": "ai_only",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Enroll a patient",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"plan_code\": \"ai_health_fitness\",\n  \"external_patient_id\": \"brand-pt-48213\",\n  \"external_order_id\": \"ord-2026-10-000123\",\n  \"purchased_at\": \"2026-10-21T14:58:00Z\",\n  \"patient\": {\n    \"first_name\": \"Jordan\",\n    \"last_name\": \"Rivera\",\n    \"email\": \"jordan.rivera@example.com\",\n    \"phone\": \"+12025550143\",\n    \"date_of_birth\": \"1986-04-12\",\n    \"sex\": \"female\",\n    \"height_cm\": 165.1,\n    \"state_code\": \"NY\",\n    \"timezone\": \"America/New_York\",\n    \"units\": \"imperial\",\n    \"conditions\": [\n      \"prediabetes\"\n    ],\n    \"health_profile\": {\n      \"goal_weight_kg\": 72.5,\n      \"activity_level\": \"lightly_active\",\n      \"food_allergies\": [\n        \"peanuts\"\n      ],\n      \"dietary_restrictions\": [\n        \"dairy_free\"\n      ],\n      \"food_dislikes\": [\n        \"mushrooms\"\n      ],\n      \"cooking\": {\n        \"skill\": \"beginner\",\n        \"appliances\": [\n          \"stove_range\",\n          \"microwave\",\n          \"air_fryer\"\n        ],\n        \"meal_preparer\": \"mostly_myself\"\n      },\n      \"lifestyle\": {\n        \"sleep_hours\": 6.5,\n        \"alcohol\": \"occasional\",\n        \"smoking\": \"never\"\n      }\n    }\n  },\n  \"intake\": {\n    \"weight_kg\": 96.2,\n    \"goal_weight_kg\": 72.5,\n    \"activity_level\": \"lightly_active\"\n  },\n  \"consents\": [\n    {\n      \"document_code\": \"coaching_consent\",\n      \"version\": \"2026-01\",\n      \"accepted_at\": \"2026-10-21T14:57:30Z\",\n      \"evidence\": {\n        \"ip\": \"203.0.113.24\",\n        \"checkout_id\": \"chk_2026_10_000123\"\n      }\n    }\n  ],\n  \"treatment\": {\n    \"medication_id\": \"6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f\",\n    \"dose_mg\": 0.25,\n    \"phase\": \"titration\",\n    \"injection_weekday\": 1,\n    \"started_on\": \"2026-09-28\"\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get an enrollment",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Stage, care team status, form status, protocol timestamps and risk level. No clinical content.",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Update the patient's details",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/patient",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "patient"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"phone\": \"+12025550178\",\n  \"state_code\": \"NJ\",\n  \"health_profile\": {\n    \"food_allergies\": [\n      \"peanuts\",\n      \"sesame\"\n    ]\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Change plan",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/plan",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "plan"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"plan_code\": \"ai_only\",\n  \"reason\": \"Patient downgraded at renewal\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Pause",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/pause",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "pause"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"Patient travelling\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Resume",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              }
            ],
            "description": "Back to `active`. Fires `enrollment.resumed`. Error code: `invalid_status_transition` (409) unless the enrollment is `paused`.\n",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/resume",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "resume"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Cancel",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/cancel",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "cancel"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"subscription_ended\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Ask the AI Coach to reach out",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/ai-coach-outreach",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "ai-coach-outreach"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Treatment",
      "description": "The GLP-1 medication, dose and schedule the brand's prescriber set, mirrored by TeraRx and never changed.",
      "item": [
        {
          "name": "List medications",
          "request": {
            "method": "GET",
            "header": [],
            "description": "The GLP-1 products you can name in a treatment. The platform catalogue plus any added for your brand.",
            "url": {
              "raw": "{{base_url}}/v1/medications",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "medications"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List treatment versions",
          "request": {
            "method": "GET",
            "header": [],
            "description": "The mirrored treatment history, newest first. Use it to reconcile with your own records.",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/treatments",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "treatments"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Update the treatment mirror",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/treatments",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "treatments"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"medication_id\": \"6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f\",\n  \"dose_mg\": 0.5,\n  \"phase\": \"titration\",\n  \"injection_weekday\": 1,\n  \"started_on\": \"2026-09-28\",\n  \"effective_from\": \"2026-10-26T00:00:00Z\",\n  \"note\": \"Step up to 0.5 mg per titration schedule\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Consent",
      "description": "Proof of the legal documents a patient accepted at the brand's checkout.",
      "item": [
        {
          "name": "List consent records",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Every document the patient has accepted for this enrollment, from your checkout or from the app.",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/consents",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "consents"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Record consent proof",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/consents",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "consents"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"consents\": [\n    {\n      \"document_code\": \"terms\",\n      \"version\": \"2026-01\",\n      \"accepted_at\": \"2026-10-21T14:57:30Z\",\n      \"evidence\": {\n        \"ip\": \"203.0.113.24\",\n        \"user_agent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X)\",\n        \"checkout_id\": \"chk_2026_10_000123\"\n      }\n    }\n  ]\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "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",
      "item": [
        {
          "name": "Send a meal log",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/meals",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "meals"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"eaten_at\": \"2026-10-26T12:30:00Z\",\n  \"meal_type\": \"lunch\",\n  \"description\": \"Chicken salad\",\n  \"entry_method\": \"manual\",\n  \"protein_g\": 35,\n  \"calories_kcal\": 420,\n  \"external_id\": \"meal-77120\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Send a workout log",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "description": "A workout your app already recorded. A repeated `external_id` returns the first receipt with `200`.",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/workouts",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "workouts"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"started_at\": \"2026-10-26T07:00:00Z\",\n  \"activity_type\": \"walk\",\n  \"duration_min\": 30,\n  \"external_id\": \"workout-5531\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Send a symptom log",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/symptoms",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "symptoms"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"occurred_at\": \"2026-10-26T19:45:00Z\",\n  \"symptom\": \"constipation\",\n  \"severity\": 3,\n  \"external_id\": \"sym-20931\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Send an injection log",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "description": "A dose taken or missed, as your app recorded it. A repeated `external_id` returns the first receipt with `200`.",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/injections",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "injections"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"injected_at\": \"2026-10-26T08:00:00Z\",\n  \"scheduled_for\": \"2026-10-26\",\n  \"dose_mg\": 0.5,\n  \"site\": \"thigh_right\",\n  \"external_id\": \"inj-88213\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete a meal log",
          "request": {
            "method": "DELETE",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/meals/:external_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "meals",
                ":external_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "external_id",
                  "value": "meal-77120",
                  "description": "Your `external_id` for the log, URL-encoded."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Correct a meal log",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/meals/:external_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "meals",
                ":external_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "external_id",
                  "value": "meal-77120",
                  "description": "Your `external_id` for the log, URL-encoded."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"protein_g\": 30,\n  \"calories_kcal\": 360\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete a workout log",
          "request": {
            "method": "DELETE",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/workouts/:external_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "workouts",
                ":external_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "external_id",
                  "value": "meal-77120",
                  "description": "Your `external_id` for the log, URL-encoded."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Correct a workout log",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/workouts/:external_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "workouts",
                ":external_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "external_id",
                  "value": "meal-77120",
                  "description": "Your `external_id` for the log, URL-encoded."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"duration_min\": 45\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete a symptom log",
          "request": {
            "method": "DELETE",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/symptoms/:external_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "symptoms",
                ":external_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "external_id",
                  "value": "meal-77120",
                  "description": "Your `external_id` for the log, URL-encoded."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Correct a symptom log",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/symptoms/:external_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "symptoms",
                ":external_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "external_id",
                  "value": "meal-77120",
                  "description": "Your `external_id` for the log, URL-encoded."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"severity\": 3,\n  \"note\": \"Worse after dinner than I first logged\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete an injection log",
          "request": {
            "method": "DELETE",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/injections/:external_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "injections",
                ":external_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "external_id",
                  "value": "meal-77120",
                  "description": "Your `external_id` for the log, URL-encoded."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Correct an injection log",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/injections/:external_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "injections",
                ":external_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "external_id",
                  "value": "meal-77120",
                  "description": "Your `external_id` for the log, URL-encoded."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"missed\": false,\n  \"injected_at\": \"2026-10-26T08:00:00Z\",\n  \"dose_mg\": 0.5\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Send daily values",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "description": "Weight, body measures, water, steps, sleep and other daily values your app recorded. Only the fields sent change.",
            "url": {
              "raw": "{{base_url}}/v1/enrollments/:enrollment_id/daily-logs/:log_date",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "enrollments",
                ":enrollment_id",
                "daily-logs",
                ":log_date"
              ],
              "query": [],
              "variable": [
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5"
                },
                {
                  "key": "log_date",
                  "value": "2026-10-26",
                  "description": "The day, in the patient's time zone."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"weight_kg\": 94.8,\n  \"steps\": 7400\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Events",
      "description": "Replay of the webhook events for the last 30 days, in order.",
      "item": [
        {
          "name": "Replay events",
          "request": {
            "method": "GET",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/events",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "events"
              ],
              "query": [
                {
                  "key": "since",
                  "value": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7",
                  "description": "Start after this event id (exclusive). Omit to start at the oldest event kept.",
                  "disabled": true
                },
                {
                  "key": "type",
                  "value": "clinical.flag_raised,clinical.flag_redelivered",
                  "description": "Only these event types, comma-separated.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get an event",
          "request": {
            "method": "GET",
            "header": [],
            "description": "One event by id, within the 30-day window.",
            "url": {
              "raw": "{{base_url}}/v1/events/:event_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "events",
                ":event_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "event_id",
                  "value": "0190f5d8-4b2d-7e6f-8a21-c2d3e4f5a6b7"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Reports",
      "description": "The aggregate brand report. Groups under 10 patients are suppressed.",
      "item": [
        {
          "name": "Get the brand report",
          "request": {
            "method": "GET",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/reports/brand?from=2026-10-01&to=2026-10-31",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "reports",
                "brand"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "2026-10-01",
                  "disabled": false
                },
                {
                  "key": "to",
                  "value": "2026-10-31",
                  "disabled": false
                },
                {
                  "key": "plan_code",
                  "value": "ai_only",
                  "description": "Only this plan.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "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",
      "item": [
        {
          "name": "List data requests",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Your brand's data requests, newest first.",
            "url": {
              "raw": "{{base_url}}/v1/data-requests",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "data-requests"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "processing",
                  "disabled": true
                },
                {
                  "key": "kind",
                  "value": "amend",
                  "disabled": true
                },
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Create a data request",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/data-requests",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "data-requests"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"enrollment_id\": \"0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5\",\n  \"kind\": \"export\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a data request",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Status, and for exports whether the download is ready.",
            "url": {
              "raw": "{{base_url}}/v1/data-requests/:data_request_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "data-requests",
                ":data_request_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "data_request_id",
                  "value": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a download link",
          "request": {
            "method": "POST",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/data-requests/:data_request_id/export-link",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "data-requests",
                ":data_request_id",
                "export-link"
              ],
              "query": [],
              "variable": [
                {
                  "key": "data_request_id",
                  "value": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Decide an amendment",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/data-requests/:data_request_id/decision",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "data-requests",
                ":data_request_id",
                "decision"
              ],
              "query": [],
              "variable": [
                {
                  "key": "data_request_id",
                  "value": "7a2e4c61-0b3d-4f58-9a17-2c4e6f8a0b13"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"decision\": \"accepted\",\n  \"decision_note\": \"Corrected the severity to 2.\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{brand_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Patient",
      "description": "The patient's profile, settings, treatment and legal documents.",
      "item": [
        {
          "name": "Get my profile",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Update my profile",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"height_cm\": 167.6,\n  \"units\": \"metric\",\n  \"health_profile\": {\n    \"dietary_restrictions\": [\n      \"dairy_free\",\n      \"gluten_free\"\n    ],\n    \"cooking\": {\n      \"skill\": \"intermediate\"\n    }\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get my treatment",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/treatment",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "treatment"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Report my treatment (TeraRx Direct)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/treatments",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "treatments"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"medication_id\": \"6f1d2c3b-4a59-4e8f-9d7c-1b2a3c4d5e6f\",\n  \"dose_mg\": 0.5,\n  \"phase\": \"titration\",\n  \"injection_weekday\": 1,\n  \"started_on\": \"2026-09-28\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List my legal documents",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/legal-documents",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "legal-documents"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Accept a legal document",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/consents",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "consents"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"legal_document_id\": \"4f6a8c0e-2b1d-4e3f-8a5b-9c1d3e5f7a9b\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Forms",
      "description": "Onboarding, check-in and eligibility forms, pinned to the version they were sent with.",
      "item": [
        {
          "name": "List my forms",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/forms",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "forms"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "sent,in_progress",
                  "description": "Filter by one or more statuses, comma-separated.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a form",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/forms/:form_assignment_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "forms",
                ":form_assignment_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "form_assignment_id",
                  "value": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Save a draft",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/forms/:form_assignment_id/draft",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "forms",
                ":form_assignment_id",
                "draft"
              ],
              "query": [],
              "variable": [
                {
                  "key": "form_assignment_id",
                  "value": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"answers\": {\n    \"primary_goal\": \"preserve_muscle\"\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Submit a form",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/forms/:form_assignment_id/submit",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "forms",
                ":form_assignment_id",
                "submit"
              ],
              "query": [],
              "variable": [
                {
                  "key": "form_assignment_id",
                  "value": "0190f5c3-7e21-7a40-9b11-5d6e7f8091a2"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"answers\": {\n    \"weight_kg\": 96.2,\n    \"primary_goal\": \"preserve_muscle\"\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "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",
      "item": [
        {
          "name": "List my daily logs",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/daily-logs",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "daily-logs"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "2026-10-20",
                  "description": "First day to include, in the patient's time zone.",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "2026-10-26",
                  "description": "Last day to include, in the patient's time zone. At most 92 days after `from`.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Log daily values",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/daily-logs/:log_date",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "daily-logs",
                ":log_date"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_date",
                  "value": "2026-10-26",
                  "description": "The day, in the patient's time zone."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"water_ml\": 1800,\n  \"weight_kg\": 94.8,\n  \"mood\": 4,\n  \"habits_done\": {\n    \"0190f5c6-8b9c-7d01-8e23-4f5a6b7c8d90:protein_each_meal\": true\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Start a meal photo upload",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meal-photos",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meal-photos"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"content_type\": \"image/jpeg\",\n  \"content_length\": 1843200\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Analyze a meal photo",
          "request": {
            "method": "POST",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meal-photos/:upload_id/analysis",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meal-photos",
                ":upload_id",
                "analysis"
              ],
              "query": [],
              "variable": [
                {
                  "key": "upload_id",
                  "value": "8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e",
                  "description": "From `POST /v1/patient/meal-photos`."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List my recent foods",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/recent-foods",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "recent-foods"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List my meals",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Meal logs in a date range, newest first.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meals",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meals"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "2026-10-20",
                  "description": "First day to include, in the patient's time zone.",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "2026-10-26",
                  "description": "Last day to include, in the patient's time zone. At most 92 days after `from`.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Log a meal",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meals",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meals"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"eaten_at\": \"2026-10-26T12:30:00Z\",\n  \"meal_type\": \"lunch\",\n  \"description\": \"Greek yogurt with berries and almonds\",\n  \"photo_upload_id\": \"8e2c4a60-1f3b-4d5e-9a7c-0b2d4f6a8c1e\",\n  \"entry_method\": \"photo\",\n  \"protein_g\": 24,\n  \"calories_kcal\": 310,\n  \"fiber_g\": 6\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete a meal log",
          "request": {
            "method": "DELETE",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meals/:log_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meals",
                ":log_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_id",
                  "value": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "description": "The log's `id`."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Correct a meal log",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meals/:log_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meals",
                ":log_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_id",
                  "value": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "description": "The log's `id`."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"protein_g\": 30,\n  \"calories_kcal\": 360\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List my workouts",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Workout logs in a date range, newest first.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/workouts",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "workouts"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "2026-10-20",
                  "description": "First day to include, in the patient's time zone.",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "2026-10-26",
                  "description": "Last day to include, in the patient's time zone. At most 92 days after `from`.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Log a workout",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/workouts",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "workouts"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"started_at\": \"2026-10-26T07:00:00Z\",\n  \"activity_type\": \"strength\",\n  \"duration_min\": 35,\n  \"perceived_effort\": 6,\n  \"workout_plan_item_id\": \"1b3d5f7a-9c2e-4a6b-8d0f-2e4a6c8e0b2d\",\n  \"sets\": [\n    {\n      \"exercise_id\": \"5a7c9e1b-3d5f-4a8c-9e2b-4d6f8a0c2e4f\",\n      \"name\": \"Goblet squat\",\n      \"reps\": 10,\n      \"weight_kg\": 12\n    }\n  ]\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete a workout log",
          "request": {
            "method": "DELETE",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/workouts/:log_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "workouts",
                ":log_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_id",
                  "value": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "description": "The log's `id`."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Correct a workout log",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/workouts/:log_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "workouts",
                ":log_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_id",
                  "value": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "description": "The log's `id`."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"duration_min\": 45\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List my symptoms",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Symptom logs in a date range, newest first.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/symptoms",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "symptoms"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "2026-10-20",
                  "description": "First day to include, in the patient's time zone.",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "2026-10-26",
                  "description": "Last day to include, in the patient's time zone. At most 92 days after `from`.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Log a symptom",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/symptoms",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "symptoms"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"occurred_at\": \"2026-10-26T19:45:00Z\",\n  \"symptom\": \"nausea\",\n  \"severity\": 2,\n  \"note\": \"Mild, after dinner\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete a symptom log",
          "request": {
            "method": "DELETE",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/symptoms/:log_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "symptoms",
                ":log_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_id",
                  "value": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "description": "The log's `id`."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Correct a symptom log",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/symptoms/:log_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "symptoms",
                ":log_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_id",
                  "value": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "description": "The log's `id`."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"severity\": 3,\n  \"note\": \"Worse after dinner than I first logged\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List my injections",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Injection logs in a date range, newest first.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/injections",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "injections"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "2026-10-20",
                  "description": "First day to include, in the patient's time zone.",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "2026-10-26",
                  "description": "Last day to include, in the patient's time zone. At most 92 days after `from`.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Log an injection",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/injections",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "injections"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"injected_at\": \"2026-10-26T08:00:00Z\",\n  \"scheduled_for\": \"2026-10-26\",\n  \"dose_mg\": 0.5,\n  \"site\": \"abdomen_left\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete an injection log",
          "request": {
            "method": "DELETE",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/injections/:log_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "injections",
                ":log_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_id",
                  "value": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "description": "The log's `id`."
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Correct an injection log",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/injections/:log_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "injections",
                ":log_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "log_id",
                  "value": "0190f5c9-5d6e-7f70-8a92-1b2c3d4e5f60",
                  "description": "The log's `id`."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"missed\": false,\n  \"injected_at\": \"2026-10-26T08:00:00Z\",\n  \"dose_mg\": 0.5\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Protocols and plans",
      "description": "Published protocols, meal plans and workout plans, read only. Drafts are never visible to patients.",
      "item": [
        {
          "name": "List my active protocols",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/protocols",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "protocols"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get my active protocol of a type",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/protocols/:protocol_type",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "protocols",
                ":protocol_type"
              ],
              "query": [],
              "variable": [
                {
                  "key": "protocol_type",
                  "value": "nutrition"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List versions of a protocol",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/protocols/:protocol_type/versions",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "protocols",
                ":protocol_type",
                "versions"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "protocol_type",
                  "value": "nutrition"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get one version of a protocol",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Any published version, active or superseded.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/protocols/:protocol_type/versions/:version",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "protocols",
                ":protocol_type",
                "versions",
                ":version"
              ],
              "query": [],
              "variable": [
                {
                  "key": "protocol_type",
                  "value": "nutrition"
                },
                {
                  "key": "version",
                  "value": "2"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get my meal plan",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meal-plan",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meal-plan"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get my workout plan",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/workout-plan",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "workout-plan"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Rate a meal on my plan",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meal-plan/items/:item_id/rating",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meal-plan",
                "items",
                ":item_id",
                "rating"
              ],
              "query": [],
              "variable": [
                {
                  "key": "item_id",
                  "value": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"rating\": 4,\n  \"comment\": \"Filling, but I'd like it less spicy.\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Clear a meal rating",
          "request": {
            "method": "DELETE",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meal-plan/items/:item_id/rating",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meal-plan",
                "items",
                ":item_id",
                "rating"
              ],
              "query": [],
              "variable": [
                {
                  "key": "item_id",
                  "value": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Meal swap",
      "description": "The AI Coach swaps a meal for one that stays within the protocol and the brand's rule matrix.",
      "item": [
        {
          "name": "Ask the AI Coach for swap options",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meal-plan/items/:item_id/swap-options",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meal-plan",
                "items",
                ":item_id",
                "swap-options"
              ],
              "query": [],
              "variable": [
                {
                  "key": "item_id",
                  "value": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"I don't like fish\",\n  \"avoid\": [\n    \"fish\"\n  ]\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Swap a meal",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/meal-plan/items/:item_id/swap",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "meal-plan",
                "items",
                ":item_id",
                "swap"
              ],
              "query": [],
              "variable": [
                {
                  "key": "item_id",
                  "value": "3c1e8f20-5b7a-4d9c-8e61-0a2b4c6d8e01"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"option_id\": \"opt_1\",\n  \"reason\": \"I don't like fish\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Library",
      "description": "Recipes and exercises that plans link to, that the patient can browse, save and rate.",
      "item": [
        {
          "name": "Browse recipes and exercises",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/library",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "library"
              ],
              "query": [
                {
                  "key": "kind",
                  "value": "recipe",
                  "description": "Omit for both.",
                  "disabled": true
                },
                {
                  "key": "meal_type",
                  "value": "breakfast",
                  "description": "Recipes for this meal.",
                  "disabled": true
                },
                {
                  "key": "tag",
                  "value": "mild_nausea",
                  "description": "Items with this tag, for example `high_protein`.",
                  "disabled": true
                },
                {
                  "key": "q",
                  "value": "yogurt",
                  "description": "Words in the title.",
                  "disabled": true
                },
                {
                  "key": "favorites",
                  "value": "true",
                  "description": "Only the items the patient saved, most recently saved first.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a recipe or exercise",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/library/:library_item_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "library",
                ":library_item_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "library_item_id",
                  "value": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Save a recipe or exercise",
          "request": {
            "method": "PUT",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/library/:library_item_id/favorite",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "library",
                ":library_item_id",
                "favorite"
              ],
              "query": [],
              "variable": [
                {
                  "key": "library_item_id",
                  "value": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Remove a favorite",
          "request": {
            "method": "DELETE",
            "header": [],
            "description": "Removing one that isn't saved changes nothing.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`), AI only (`ai_only`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/library/:library_item_id/favorite",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "library",
                ":library_item_id",
                "favorite"
              ],
              "query": [],
              "variable": [
                {
                  "key": "library_item_id",
                  "value": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Rate a recipe",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/library/:library_item_id/rating",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "library",
                ":library_item_id",
                "rating"
              ],
              "query": [],
              "variable": [
                {
                  "key": "library_item_id",
                  "value": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"rating\": 2,\n  \"comment\": \"Too sweet for me.\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Clear a recipe rating",
          "request": {
            "method": "DELETE",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/library/:library_item_id/rating",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "library",
                ":library_item_id",
                "rating"
              ],
              "query": [],
              "variable": [
                {
                  "key": "library_item_id",
                  "value": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Care messaging",
      "description": "Threads with the coaches on the coached plan, photos, editing the last message, read state and reactions.",
      "item": [
        {
          "name": "List my care threads",
          "request": {
            "method": "GET",
            "header": [],
            "description": "One thread per coach on the care team, with unread counts.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/care/conversations",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "care",
                "conversations"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List messages in a care thread",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Newest first. New messages are announced by `message.created`; fetch them here.\n\n**Plans:** AI + health and fitness coaches (`ai_health_fitness`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/care/conversations/:conversation_id/messages",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "care",
                "conversations",
                ":conversation_id",
                "messages"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "conversation_id",
                  "value": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Message my coach",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/care/conversations/:conversation_id/messages",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "care",
                "conversations",
                ":conversation_id",
                "messages"
              ],
              "query": [],
              "variable": [
                {
                  "key": "conversation_id",
                  "value": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"body\": \"Nausea is better today. Can I swap dinner?\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Mark a care thread read",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/care/conversations/:conversation_id/read",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "care",
                "conversations",
                ":conversation_id",
                "read"
              ],
              "query": [],
              "variable": [
                {
                  "key": "conversation_id",
                  "value": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"read_at\": \"2026-10-26T14:05:00Z\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Edit my last message",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/messages/:message_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "messages",
                ":message_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "message_id",
                  "value": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"body\": \"Nausea is better today. Can I swap tonight's dinner?\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Set my reactions on a message",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/messages/:message_id/reactions",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "messages",
                ":message_id",
                "reactions"
              ],
              "query": [],
              "variable": [
                {
                  "key": "message_id",
                  "value": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"emojis\": [\n    \"👍\"\n  ]\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Start a photo upload for my coach",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/message-photos",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "message-photos"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"content_type\": \"image/jpeg\",\n  \"content_length\": 2097152\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Feedback",
      "description": "Popups that ask the patient about their coach. TeraRx writes the questions and decides when to ask.",
      "item": [
        {
          "name": "List open feedback popups",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/feedback-requests",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "feedback-requests"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a feedback popup",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/feedback-requests/:feedback_request_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "feedback-requests",
                ":feedback_request_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "feedback_request_id",
                  "value": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Answer a feedback popup",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/feedback-requests/:feedback_request_id/response",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "feedback-requests",
                ":feedback_request_id",
                "response"
              ],
              "query": [],
              "variable": [
                {
                  "key": "feedback_request_id",
                  "value": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"answers\": {\n    \"overall\": 5,\n    \"helpful\": \"up\",\n    \"more_help_with\": \"side_effects\",\n    \"comment\": \"Maya's tips for nausea made a real difference.\"\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Dismiss a feedback popup",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/feedback-requests/:feedback_request_id/dismiss",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "feedback-requests",
                ":feedback_request_id",
                "dismiss"
              ],
              "query": [],
              "variable": [
                {
                  "key": "feedback_request_id",
                  "value": "0190f5e3-4c5d-7e6f-8a90-b1c2d3e4f5a6"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "AI Coach",
      "description": "Chat with the AI Coach on every plan, and what it remembers. Replies stream or can be polled.",
      "item": [
        {
          "name": "List my AI Coach chats",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/conversations",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "conversations"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Start an AI Coach chat",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/conversations",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "conversations"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\": \"Dinner ideas\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List messages in an AI Coach chat",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/conversations/:conversation_id/messages",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "conversations",
                ":conversation_id",
                "messages"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "conversation_id",
                  "value": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Message the AI Coach",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "A unique key per logical request, for example a UUID. Retrying with the same key and the same body"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/conversations/:conversation_id/messages",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "conversations",
                ":conversation_id",
                "messages"
              ],
              "query": [],
              "variable": [
                {
                  "key": "conversation_id",
                  "value": "0190f5c4-1d2e-7f30-8a45-6b7c8d9e0f12"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"body\": \"What can I eat tonight instead of salmon?\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get the AI Coach's reply",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/messages/:message_id/reply",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "messages",
                ":message_id",
                "reply"
              ],
              "query": [],
              "variable": [
                {
                  "key": "message_id",
                  "value": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Rate an AI Coach reply",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/messages/:message_id/feedback",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "messages",
                ":message_id",
                "feedback"
              ],
              "query": [],
              "variable": [
                {
                  "key": "message_id",
                  "value": "0190f5c4-2e3f-7a41-9b56-7c8d9e0f1a23"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"rating\": \"down\",\n  \"note\": \"The swap still had fish in it\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List what the AI Coach remembers",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/memories",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "memories"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Forget a memory",
          "request": {
            "method": "DELETE",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/memories/:memory_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "memories",
                ":memory_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "memory_id",
                  "value": "6c8e0a2b-4d6f-4a1c-8e3b-5d7f9a1c3e5b"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Confirm a memory",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/ai-coach/memories/:memory_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "ai-coach",
                "memories",
                ":memory_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "memory_id",
                  "value": "6c8e0a2b-4d6f-4a1c-8e3b-5d7f9a1c3e5b"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"confirmed\": true\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "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",
      "item": [
        {
          "name": "List my reminders",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/reminders",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "reminders"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "scheduled",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Snooze a reminder",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/reminders/:reminder_id/snooze",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "reminders",
                ":reminder_id",
                "snooze"
              ],
              "query": [],
              "variable": [
                {
                  "key": "reminder_id",
                  "value": "0190f5c5-4a5b-7c61-8d78-9e0f1a2b3c45"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"minutes\": 60\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get my reminder settings",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/reminder-settings",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "reminder-settings"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Change my reminder settings",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/merge-patch+json"
              }
            ],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/reminder-settings",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "reminder-settings"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"habit\": {\n    \"enabled\": false\n  },\n  \"quiet_hours\": {\n    \"start\": \"21:30\",\n    \"end\": \"07:30\"\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Progress",
      "description": "Today at a glance, targets for a day, a week's stats and the milestones the patient reached.",
      "item": [
        {
          "name": "Get today",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/today",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "today"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get targets and progress for a day",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/targets",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "targets"
              ],
              "query": [
                {
                  "key": "date",
                  "value": "2026-10-27",
                  "description": "A day in the patient's time zone. Defaults to today.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a week's stats",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/week-stats",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "week-stats"
              ],
              "query": [
                {
                  "key": "week_number",
                  "value": "6",
                  "description": "Omit for the current week.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "List my milestones",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/milestones",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "milestones"
              ],
              "query": [],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a milestone",
          "request": {
            "method": "GET",
            "header": [],
            "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`).",
            "url": {
              "raw": "{{base_url}}/v1/patient/milestones/:milestone_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "patient",
                "milestones",
                ":milestone_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "milestone_id",
                  "value": "0190f5e1-2a3b-7c4d-9e5f-6a7b8c9d0e1f"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{patient_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "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",
      "item": [
        {
          "name": "List clinical flags",
          "request": {
            "method": "GET",
            "header": [],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/clinical-flags",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "clinical-flags"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "open",
                  "description": "One or more statuses, comma-separated.",
                  "disabled": true
                },
                {
                  "key": "severity",
                  "value": "critical",
                  "disabled": true
                },
                {
                  "key": "enrollment_id",
                  "value": "0190f5c2-3a1b-7c4d-8e9f-a0b1c2d3e4f5",
                  "disabled": true
                },
                {
                  "key": "external_patient_id",
                  "value": "brand-pt-48213",
                  "disabled": true
                },
                {
                  "key": "updated_since",
                  "value": "2026-10-26T00:00:00Z",
                  "description": "Only flags changed after this time.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "eyJpZCI6IjAxOTBmNWMyIn0",
                  "description": "The `next_cursor` from the previous page. Omit it for the first page.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{clinical_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a clinical flag",
          "request": {
            "method": "GET",
            "header": [],
            "description": "Symptom, severity, the triggering records, a timeline around them, the treatment and any coach note.",
            "url": {
              "raw": "{{base_url}}/v1/clinical-flags/:flag_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "clinical-flags",
                ":flag_id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "flag_id",
                  "value": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6"
                }
              ]
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{clinical_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Acknowledge a flag",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/clinical-flags/:flag_id/acknowledge",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "clinical-flags",
                ":flag_id",
                "acknowledge"
              ],
              "query": [],
              "variable": [
                {
                  "key": "flag_id",
                  "value": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"on_behalf_of\": {\n    \"npi\": \"1234567893\",\n    \"name\": \"Dr. Alex Morgan, NP\"\n  }\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{clinical_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        },
        {
          "name": "Resolve a flag",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Optional on this action. When sent, it works as on creating requests (24 hours, same body)."
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "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",
            "url": {
              "raw": "{{base_url}}/v1/clinical-flags/:flag_id/resolve",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "clinical-flags",
                ":flag_id",
                "resolve"
              ],
              "query": [],
              "variable": [
                {
                  "key": "flag_id",
                  "value": "0190f5d8-4b2c-7d5e-9f10-b1c2d3e4f5a6"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"on_behalf_of\": {\n    \"npi\": \"1234567893\",\n    \"name\": \"Dr. Alex Morgan, NP\"\n  },\n  \"resolution_note\": \"Spoke with patient. Holding at 0.5 mg for two more weeks; antiemetic prescribed.\",\n  \"new_risk_level\": \"elevated\"\n}"
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{clinical_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('answers with a 2xx', () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
