Ingest and Query a Patient
Full walkthrough: ingest a FHIR bundle and a CDA document, browse the virtual file system, and read a condition story end-to-end.
Ingest and Query a Patient
In this tutorial you will:
- Ingest a FHIR R4 bundle for a patient
- Ingest a CDA document for the same patient
- Check ingest status and confirm entity resolution ran
- Browse the virtual file system to discover what was extracted
- Read a condition story
By the end you will have a working Patient Memory workflow and understand how source records become a navigable clinical graph.
Time: ~15 minutes.
Prerequisites
- A Patient Memory workspace with a workspace ID and an OAuth access token. See Manage Credentials for how to obtain one. Replace
<workspace-id>and<access-token>in the commands below.
Steps
Ingest a FHIR R4 bundle
Pick a registry key for the patient. This is the identifier you control. It does not need to match Patient.id inside the bundle.
No PHI? Use the synthetic bundle
Download the
Jeanne Tremblay synthetic FHIR R4 bundle
to follow along without real patient data. It covers 10 encounters spanning 2017–2026: COPD GOLD stage 3, hypertension, dyslipidemia, knee osteoarthritis, and an acute COPD exacerbation.
curl -X POST "https://<workspace-id>.w.clinia.cloud/v1/patients/demo-patient/ingest/fhir" \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: application/json" \
-d @fhir-bundle.jsonA successful response confirms how many entities and events were extracted:
{
"ok": true,
"source": "fhir",
"stats": { "itemsScanned": 42, "entitiesExtracted": 12, "eventsExtracted": 8 },
"warnings": 0,
"patient": { "id": "jeanne-72f-copd", "name": "Jeanne Tremblay" }
}If warnings is greater than zero, some resources were skipped, usually because of missing required codes or unsupported resource types. They do not fail the ingest.
Ingest a CDA document
Multiple ingest calls for the same registry key accumulate sources. The pipeline re-runs entity resolution after each one, merging what it can across all sources.
curl -X POST "https://<workspace-id>.w.clinia.cloud/v1/patients/demo-patient/ingest/cda" \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: text/plain" \
--data-binary @summary.xml{
"ok": true,
"source": "cda",
"stats": { "itemsScanned": 28, "entitiesExtracted": 9, "eventsExtracted": 4 },
"warnings": 1,
"patient": { "id": "jeanne-72f-copd", "name": "Jeanne Tremblay" }
}The patient demographics (id, name) are resolved from whichever source contains a Patient resource or CDA recordTarget.
Check ingest status
Confirm that both sources have been processed and the graph is ready to query:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/demo-patient/ingest/status" \
-H "Authorization: Bearer <access-token>"When ready is true, the pipeline has finished:
{
"ready": true,
"sources": [
{
"label": "FHIR Bundle",
"stats": { "itemsScanned": 42, "entitiesExtracted": 12, "eventsExtracted": 8 }
},
{
"label": "Summary_20230907.xml",
"stats": { "itemsScanned": 28, "entitiesExtracted": 9, "eventsExtracted": 4 }
}
],
"patient": { "id": "jeanne-72f-copd", "name": "Jeanne Tremblay" },
"loadStats": { "entitiesExtracted": 18, "eventsExtracted": 11, "relationshipsExtracted": 22 },
"loadMs": 1340
}Notice loadStats.entitiesExtracted (18) is fewer than the sum of the two individual ingest calls (12 + 9 = 21). That gap is entity resolution working — three entity pairs were recognised as duplicates across the FHIR and CDA sources and merged into single nodes.
Browse the virtual file system
Navigate the resolved graph through the VFS. Start at the root to see what categories were populated:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/demo-patient/vfs?path=/" \
-H "Authorization: Bearer <access-token>"Then drill into active conditions:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/demo-patient/vfs?path=/conditions/active" \
-H "Authorization: Bearer <access-token>"{
"path": "/patient/jeanne-72f-copd/conditions/active",
"type": "directory",
"children": [
{
"name": "chronic_obstructive_lung_disease",
"type": "directory",
"preview": "GOLD stage 3, active since 2014"
},
{ "name": "hypertension", "type": "directory", "preview": "Active since 2011" },
{ "name": "dyslipidemia", "type": "directory", "preview": "Active since 2013" }
]
}The path in the response uses the VFS patient ID (jeanne-72f-copd) extracted from the ingested record. It is not the registry key (jeanne-tremblay) used in the request URL. These are the same value only if your FHIR bundle's Patient.id matches the registry key you chose.
Each condition slug is derived from the primary display name: lowercased, spaces and special characters replaced with underscores. If the same condition appeared in both the FHIR bundle and the CDA document, it is a single entry here, not two.
Inspect what files are available under a condition:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/demo-patient/vfs?path=/conditions/active/type_2_diabetes_mellitus" \
-H "Authorization: Bearer <access-token>"{
"path": "/patient/jeanne-72f-copd/conditions/active/chronic_obstructive_lung_disease",
"type": "directory",
"children": [
{ "name": "_story.md", "type": "file", "preview": "longitudinal condition narrative" },
{ "name": "_raw.json", "type": "file", "preview": "structured entity + relationships" }
]
}Read a condition story
Read the full narrative for the condition. The story assembles onset, current medications, monitoring labs, and complications from the merged entity graph:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/demo-patient/read?path=/conditions/active/type_2_diabetes_mellitus/_story.md" \
-H "Authorization: Bearer <access-token>"{
"content": "# Chronic Obstructive Lung Disease\n\n**Status:** Active since 2014, GOLD stage 3\n**Codes:** SNOMED 13645005 · ICD-10 J44.1\n**Sources:** 2 sources (FHIR Bundle, Spirometry_2025.xml)\n\n## Current Treatment\n| Medication | Dose | Since |\n|-----------|------|-------|\n| Tiotropium | 18mcg daily | 2015 |\n| Budesonide/Formoterol | 200/6mcg BID | 2018 |\n| Albuterol | 100mcg PRN | 2014 |\n..."
}For a shorter summary, pass format=compact:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/demo-patient/read?path=/conditions/active/type_2_diabetes_mellitus/_story.md&format=compact" \
-H "Authorization: Bearer <access-token>"What you built
You ingested two sources for the same patient, let the pipeline resolve and merge duplicate entities across them, and retrieved a unified clinical narrative, without writing any custom parsing logic.
The key concepts at play:
- Registry key (
jeanne-tremblay) is the identifier you control; it's used in all REST ingest and metadata routes - VFS patient ID (
patient.idfrom the ingest response) is what appears in VFS paths. It comes from the ingested record and may differ from the registry key - Entity resolution merged duplicate conditions, medications, and labs across sources
- VFS slugs are stable across re-ingests of the same data
- Condition stories assemble cross-entity context (medications, labs, complications) into a single readable document
Next steps
- Connect an AI Agent to let a language model query this patient through MCP tools
- Entity Resolution to understand how the 4-layer cascade decides what to merge
- Audit entity resolution decisions for a focused recipe on reading provenance traces