# Healthie Post-Enrollment Workflow Notes **Status:** VALIDATED — GraphQL API tested in sandbox (July 2026). --- ## Daily Check-in Workflow ### Creation & Delivery - **Recurring prompts:** `createRequestedFormCompletion` mutation with `is_recurring: true`, `frequency: "Daily"`, `hour`, `minute` - **Onboarding integration:** Forms associated with `OnboardingFlow` → `OnboardingItem` for new patients - **Completion tracking:** `CompletedOnboardingItem` objects; missed check-ins inferred via `requestedFormCompletions(status: "Incomplete")` ### Ingestion (Healthie → Core DB) 1. **Webhook:** `form_answer_group.created` fires with pointer (`resource_id`, `event_type`) 2. **Fetch:** `formAnswerGroups(custom_module_form_id: $id, user_id: $id)` query returns `form_answers[]` 3. **Normalize:** Each `FormAnswerGroup` → `daily_checkin_submissions` + `daily_checkin_responses` 4. **Safety:** Parse answers against safety rules → create `safety_signal_events` if flagged ### Two Complementary Mechanisms | Mechanism | Best For | Mutation | Query | Webhook | |---|---|---|---|---| | **FormAnswerGroup** | Multi-field daily check-ins | `createFormAnswerGroup` | `formAnswerGroups(form_id, date, user_id)` | `form_answer_group.created` | | **MetricEntry** | Single-value data points (BP, weight, A1C) | `createEntry(type: "MetricEntry", category: "...")` | `entries(category, type, client_id, date range)` | `metric_entry.created` | | **JournalEntry** | Symptoms, notes, food, workouts, sleep | `createEntry(type: "SymptomEntry", ...)` | `entry(id, type, client_id)` | `entry.created` (all types) | ### Safety Signal Detection | Trigger | Mechanism | Target Table | |---|---|---| | Symptom reported | `SymptomEntry` via `createEntry` → `entry.created` webhook | `safety_signal_events` | | Metric out of range | `metric_entry.created` → threshold check → `createTask` mutation | `safety_signal_events`, `care_team_review_tasks` | | Custom safety form | `CustomModuleForm` with safety questions → `form_answer_group.created` | `safety_signal_events` | --- ## Care Plan Workflow ### Core DB → Healthie (Outbound) - **Create:** `createCarePlan(name, patient_id, is_hidden)` — returns `carePlan.id` - **Update:** `updateCarePlan(id, name, description, new_patient_id, is_template, is_hidden)` - **Activate/Deactivate:** `updateCarePlan` with `is_active` field - **List:** `carePlans(patient_id, sort_by: "newest")` — sort: oldest, newest, name, status - **Get:** `carePlan(id)` — returns full plan with `recommendations[]` - **Delete:** `deleteCarePlan(id)` — soft delete ### Webhook Events | Event | Action | |---|---| | `care_plan.created` | Store `carePlan.id` in `external_system_identifiers` | | `care_plan.updated` | Sync `changed_fields` to `monitoring_plans` | | `care_plan.activated` | Set `monitoring_plans.status = active` | | `care_plan.deactivated` | Set `monitoring_plans.status = inactive` | --- ## Patient Lifecycle ### Status Events | Status | Webhook | Trigger | |---|---|---| | Patient created | `patient.created` | `createClient`, `completeCheckout` | | Patient updated | `patient.updated` | `updateClient`, `bulkUpdateClients`, form submissions | | Patient merged | `patient.merged` | `mergeClients` — payload: `source_user_id`, `destination_user_id` | | Patient archived | `patient.updated` via `bulkUpdateClients` | `active_status: false` | ### Active Status Values - `"active"` or `"archived"` (query via `users(active_status: "active")`) ### Missed Check-in Detection Healthie does NOT emit a "missed check-in" webhook. Must be inferred server-side: ``` poll requestedFormCompletions(status: "Incomplete") OR poll entries query to check for missing data on expected dates ``` --- ## Document Workflow 1. **Webhook:** `document.created` / `document.updated` fires with pointer 2. **Fetch:** `documents(private_user_id: $resource_id)` query returns list with `expiring_url` 3. **Download:** GET `expiring_url` → save to S3 4. **Store:** Reference in `clinical_documents` table with `storage_path` --- ## API Authentication ``` Authorization: Basic YOUR_API_KEY_HERE AuthorizationSource: API AuthorizationShard: YOUR_SHARD_AUTHORIZATION_ID # if sharded ``` ### Webhook Signature Verification - Headers: `Content-Digest`, `Signature-Input`, `Signature` - HMAC-SHA256 with key format `whsec_` - Data string: `"{method} {path} {query} {contentDigest} {contentType} {contentLength}"` --- ## See Also - `docs/healthie/Healthie_Integration_Mapping.md` — full GraphQL API examples, data flow matrix, source-of-truth decisions - `docs/architecture/Healthie_Forms_Vs_Cognito.md` — form migration spec from Cognito