Skip to Content
Health Ai PlatformIntegrationsPatient Graph Integration

Patient Graph Integration

The Patient Graph is the primary source of patient context for the Health AI Platform.

In this repository, the integration has three layers:

  1. Service routes in apps/patient-graph
  2. Repository and domain helpers in packages/patient-graph
  3. Typed HTTP consumption in packages/patient-graph-client

What Patient Graph provides

The service mounts routes for:

  • profiles
  • labs
  • protocols
  • adherence
  • events
  • treatments
  • prescriptions
  • conversation history
  • check-ins
  • notifications
  • orders
  • affiliates
  • attribution
  • Rimo webhooks
import { PatientGraphClientImpl } from '@loop/patient-graph-client'; const patientGraph = new PatientGraphClientImpl({ baseUrl: process.env.PATIENT_GRAPH_API_URL!, getAuthToken: async () => process.env.PATIENT_GRAPH_API_KEY!, });

Fetch patient context

The simplest platform integration is to load a profile and then normalize the fields you need into workflow input.

const profileResult = await patientGraph.getPatientContext('user_123'); if (!profileResult.ok) { throw new Error(profileResult.error.message); } const context = { patientId: profileResult.data.externalId, data: { age: 38, medications: ['metformin'], biomarker: { TSH: 4.2 }, }, };

Fetch protocol and event context

Many workflows need more than a profile.

const [protocols, timeline] = await Promise.all([ patientGraph.getPatientProtocols('user_123', { status: 'active', limit: 10 }), patientGraph.getPatientTimeline('user_123', { type: 'protocol_started', limit: 20 }), ]);

That pattern works well when you want to derive:

  • currently active protocols
  • recent adherence events
  • treatment milestones
  • timeline-based triggers

Example: build workflow context from Patient Graph

import { WorkflowEngine } from '@loop/workflow-engine'; import { PatientGraphClientImpl } from '@loop/patient-graph-client'; const patientGraph = new PatientGraphClientImpl({ baseUrl: process.env.PATIENT_GRAPH_API_URL!, getAuthToken: async () => process.env.PATIENT_GRAPH_API_KEY!, }); const workflow = WorkflowEngine.load(` id: thyroid-follow-up-v1 name: Thyroid Follow-Up version: 1.0.0 steps: - id: check-tsh type: check_biomarker action: type: check_value params: biomarker: TSH threshold: 2.5 operator: ">" - id: notify type: send_notification condition: "check-tsh.result === true" action: type: notify params: channel: email message: "A thyroid follow-up may be needed." `); const profile = await patientGraph.getPatientContext('user_123'); if (profile.ok) { const result = await workflow.execute({ patientId: profile.data.externalId, data: { biomarker: { TSH: 4.2 }, medications: ['metformin'], }, }); console.log(result.stepResults); }

Route example

The service exposes profile reads through the /profiles/:id route.

curl -X GET "https://patient-graph.loop.health/profiles/user_123" \ -H "Authorization: Bearer $CLERK_JWT"

The typed client wraps that behind a safer API:

const profile = await patientGraph.getPatientContext('user_123');

Access control and ownership

Patient Graph routes are protected by middleware for:

  • authentication
  • RBAC access checks
  • ownership validation
  • rate limiting
  • audit logging

That makes Patient Graph the right integration layer for platform logic that needs reviewable access to patient state.

Data-shaping guidance

Keep your workflow context small. Pull from Patient Graph, then reduce to the fields the workflow actually needs.

const workflowContext = { patientId: 'user_123', data: { biomarker: { TSH: 4.2, hsCRP: 1.8, }, medications: ['metformin'], protocolStatus: 'active', }, };

That makes workflows easier to test and avoids coupling a DSL definition to a full API response shape.

Best practices

  • Treat Patient Graph as the system of record for patient runtime context.
  • Normalize API responses before passing them into workflows.
  • Keep auth and ownership checks in the service layer, not in workflow definitions.
  • Use the typed client instead of ad hoc fetch calls where possible.

Next steps