Skip to main content

FHIR Data Model for HealthPass Integration (Alpha)

This document describes the FHIR resources, fields, and data structures required for EMR integration with HealthPass. An EMR system must be able to provide and receive these FHIR resources via a standard FHIR R4 API.

Alpha Release

This API is still in alpha and subject to change. Features, endpoints, and data structures may be modified or removed in future releases.


Table of Contents

  1. Overview
  2. Patient Resource
  3. Observation Resource
  4. Condition Resource
  5. MedicationRequest Resource
  6. Appointment Resource
  7. Practitioner Resource
  8. RelatedPerson Resource
  9. DiagnosticReport Resource
  10. Coding Systems Reference
  11. API Operations Required

Overview

HealthPass uses FHIR R4 resources to exchange patient health data. The integration requires:

  • Read/Search capabilities for retrieving patient records
  • Create/Update capabilities for recording new clinical data
  • Standard FHIR search parameters for filtering results

Supported Backend Types

BackendAuthentication
Google Healthcare APIOAuth 2.0 with service account
Standard FHIR ServerBearer token or custom headers
MedplumOAuth 2.0

Patient Resource

The Patient resource represents individual patients in the system.

Required Fields

FieldTypeDescription
resourceTypestringMust be "Patient"
activebooleanWhether patient record is active
nameHumanName[]Patient name(s)
telecomContactPoint[]Contact information (phone, email)

Optional Fields

FieldTypeDescription
idstringFHIR resource ID
identifierIdentifier[]External identifiers (national ID, MRN)
birthDatedateDate of birth (YYYY-MM-DD)
gendercodemale | female | other | unknown
addressAddress[]Patient addresses

Example Patient Resource

{
"resourceType": "Patient",
"id": "patient-123",
"active": true,
"identifier": [
{
"type": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "NNZAF"
}
]
},
"system": "https://www.gov.za/south-african-id-number",
"value": "9001015009087"
}
],
"name": [
{
"use": "official",
"family": "Smith",
"given": ["John"]
}
],
"telecom": [
{
"system": "phone",
"value": "+27821234567",
"use": "mobile"
}
],
"gender": "male",
"birthDate": "1990-01-01",
"address": [
{
"use": "home",
"line": ["123 Main Street"],
"city": "Cape Town",
"state": "Western Cape",
"postalCode": "8001",
"country": "ZA"
}
]
}

Search Parameters

ParameterTypeDescription
identifiertokenSearch by patient identifier
namestringSearch by patient name
telecomtokenSearch by phone number (used for deduplication)

Observation Resource

Observations capture clinical measurements, vital signs, symptoms, and assessment data.

Required Fields

FieldTypeDescription
resourceTypestringMust be "Observation"
statuscodefinal | amended | corrected | cancelled
codeCodeableConceptWhat was observed (LOINC or SNOMED code)
subjectReference(Patient)Patient reference
effectiveDateTimedateTimeWhen observation was made

Value Fields (one required)

FieldTypeUse Case
valueQuantityQuantityNumeric measurements (vitals, labs)
valueStringstringText descriptions
valueBooleanbooleanYes/No observations
valueCodeableConceptCodeableConceptCoded values
componentBackboneElement[]Panel observations (e.g., blood pressure)

Observation Categories

Vital Signs (LOINC)

TemplateLOINC CodeDisplayUnit
weight29463-7Body weightkg
height8302-2Body heightcm
bmi39156-5Body mass indexkg/m2
blood_pressure_systolic8480-6Systolic blood pressuremmHg
blood_pressure_diastolic8462-4Diastolic blood pressuremmHg
blood_pressure_panel85354-9Blood pressure panel(component)
heart_rate8867-4Heart ratebeats/min
temperature8310-5Body temperatureCel
respiratory_rate9279-1Respiratory rate/min

Laboratory (LOINC)

TemplateLOINC CodeDisplayUnit
glucose_glucometer33747-0Glucose [Mass/volume] in Capillary blood by Glucometermg/dL
hba1c4548-4Hemoglobin A1c/Hemoglobin.total in Blood%

Assessment (LOINC)

TemplateLOINC CodeDisplayValue Type
sex_at_birth76689-9Sex assigned at birthCodeableConcept
gestational_dm66157-9History of gestational diabetesboolean
family_hx_diabetes97063-2Family history of diabetesboolean
high_blood_pressure_history54686-6History of high blood pressureboolean
race_ethnicity32624-7Racestring
diabetes_risk_score94560-0Diabetes risk scoreQuantity (points)
physically_active68516-4Physically activeboolean
diabetes_history44877-9History of diabetesboolean
diabetes_duration77983-4Duration of diabetesQuantity (years)
hypertension_history54686-6History of hypertensionboolean
hypertension_duration77984-2Duration of hypertensionQuantity (years)
current_symptoms75322-8Symptomsstring
current_medications10160-0History of Medication usestring
selected_medication67540-8Selected medicationstring
symptom_duration88878-4Duration of symptomsQuantity (days)
symptoms75322-8Complaintsstring

Respiratory Symptoms (SNOMED CT)

TemplateSNOMED CodeDisplay
cough49727002Cough
productive_cough28743005Productive cough
wheezing56018004Wheezing
chills43724002Chills
pleuritic_pain2237002Pleuritic pain
anosmia44169009Loss of sense of smell

Other Symptoms (SNOMED CT)

TemplateSNOMED CodeDisplay
fatigue84229001Fatigue
myalgia68962001Muscle pain
headache25064002Headache
sneezing76067001Sneezing
sinus_pain5056003Sinus pain
otalgia16001004Ear pain
chest_pain29857009Chest pain
rigor38880002Rigor
nasal_congestion68235000Nasal congestion
fever386661006Fever
other_symptoms418799008Other symptom

Reporter Method Extension

Observations include a method field indicating who reported the data:

ReporterSNOMED CodeDisplay
self1156040003Self reported
provider1156041004Healthcare professional reported

Example Observation (Vital Sign)

{
"resourceType": "Observation",
"status": "final",
"category": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "vital-signs",
"display": "Vital Signs"
}
]
}
],
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8310-5",
"display": "Body temperature"
}
]
},
"subject": {
"reference": "Patient/patient-123"
},
"effectiveDateTime": "2024-01-15T10:30:00Z",
"valueQuantity": {
"value": 37.2,
"unit": "Cel",
"system": "http://unitsofmeasure.org",
"code": "Cel"
},
"method": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "1156040003",
"display": "Self reported"
}
]
}
}

Example Observation (Blood Pressure Panel)

{
"resourceType": "Observation",
"status": "final",
"category": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "vital-signs"
}
]
}
],
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "85354-9",
"display": "Blood pressure panel"
}
]
},
"subject": {
"reference": "Patient/patient-123"
},
"effectiveDateTime": "2024-01-15T10:30:00Z",
"component": [
{
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8480-6",
"display": "Systolic blood pressure"
}
]
},
"valueQuantity": {
"value": 120,
"unit": "mmHg",
"system": "http://unitsofmeasure.org",
"code": "mm[Hg]"
}
},
{
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8462-4",
"display": "Diastolic blood pressure"
}
]
},
"valueQuantity": {
"value": 80,
"unit": "mmHg",
"system": "http://unitsofmeasure.org",
"code": "mm[Hg]"
}
}
]
}

Search Parameters

ParameterTypeDescription
patientreferenceFilter by patient
codetokenFilter by LOINC/SNOMED code (comma-separated for multiple)
_sortstringSort order (use -_lastUpdated for most recent)
_countnumberMaximum results to return

Condition Resource

Conditions represent patient diagnoses and health problems.

Required Fields

FieldTypeDescription
resourceTypestringMust be "Condition"
clinicalStatusCodeableConceptactive | recurrence | relapse | inactive | remission | resolved
verificationStatusCodeableConceptunconfirmed | provisional | differential | confirmed | refuted | entered-in-error
codeCodeableConceptCondition code (SNOMED + ICD-10)
subjectReference(Patient)Patient reference
recordedDatedateTimeWhen condition was documented

Optional Fields

FieldTypeDescription
onsetDateTimedateTimeWhen condition started
categoryCodeableConceptproblem-list-item | encounter-diagnosis

Condition Templates

TemplateSNOMED CodeICD-10 CodeDisplay
pneumonia233604007J18.9Pneumonia
covid19840539006U07.1COVID-19
asthma195967001J45.909Asthma
bronchitis10509002J20.9Acute bronchitis
hypertension38341003I10Hypertensive disorder
diabetes_type244054006E11.9Type 2 diabetes mellitus
diabetes_type146635009E10.9Type 1 diabetes mellitus
influenza6142004J11.1Influenza
strep_throat43878008J02.0Streptococcal pharyngitis
depression35489007F32.9Major depressive disorder
anxiety48694002F41.9Anxiety disorder
fever386661006R50.9Fever
headache25064002R51.9Headache

Example Condition

{
"resourceType": "Condition",
"clinicalStatus": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/condition-clinical",
"code": "active"
}
]
},
"verificationStatus": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/condition-ver-status",
"code": "confirmed"
}
]
},
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "233604007",
"display": "Pneumonia"
},
{
"system": "http://hl7.org/fhir/sid/icd-10-cm",
"code": "J18.9",
"display": "Pneumonia, unspecified organism"
}
]
},
"subject": {
"reference": "Patient/patient-123"
},
"recordedDate": "2024-01-15T10:30:00Z"
}

Search Parameters

ParameterTypeDescription
patientreferenceFilter by patient
clinical-statustokenFilter by clinical status
_sortstringSort order
_countnumberMaximum results

MedicationRequest Resource

MedicationRequests represent prescriptions and medication orders.

Required Fields

FieldTypeDescription
resourceTypestringMust be "MedicationRequest"
statuscodeactive | on-hold | cancelled | completed | entered-in-error | stopped | draft | unknown
intentcodeproposal | plan | order | original-order | reflex-order | filler-order | instance-order | option
medicationCodeableConceptCodeableConceptMedication code (RxNorm)
subjectReference(Patient)Patient reference
authoredOndateTimeWhen prescription was written

Optional Fields

FieldTypeDescription
requesterReference(Practitioner)Prescribing provider
dosageInstructionDosage[]How medication should be taken

Medication Templates (RxNorm)

Antibiotics

TemplateRxNorm CodeDisplay
amoxicillin_500mg308182Amoxicillin 500 MG Oral Capsule
amoxicillin_250mg308180Amoxicillin 250 MG Oral Capsule
azithromycin_250mg308460Azithromycin 250 MG Oral Tablet
ciprofloxacin_500mg309043Ciprofloxacin 500 MG Oral Tablet

Pain Medications

TemplateRxNorm CodeDisplay
acetaminophen_500mg313782Acetaminophen 500 MG Oral Tablet
ibuprofen_600mg310965Ibuprofen 600 MG Oral Tablet
tramadol_50mg836395Tramadol Hydrochloride 50 MG Oral Tablet

Cardiovascular

TemplateRxNorm CodeDisplay
lisinopril_10mg314076Lisinopril 10 MG Oral Tablet
metoprolol_50mg866514Metoprolol Succinate 50 MG Extended Release Oral Tablet
atorvastatin_20mg617312Atorvastatin 20 MG Oral Tablet

Diabetes

TemplateRxNorm CodeDisplay
metformin_500mg860975Metformin Hydrochloride 500 MG Oral Tablet
insulin_glargine274783Insulin Glargine 100 UNT/ML Injectable Solution

Respiratory

TemplateRxNorm CodeDisplay
albuterol_inhaler329498Albuterol 0.083 MG/ACTUAT Metered Dose Inhaler
prednisone_20mg312615Prednisone 20 MG Oral Tablet

Mental Health

TemplateRxNorm CodeDisplay
sertraline_50mg312940Sertraline 50 MG Oral Tablet
lorazepam_1mg197589Lorazepam 1 MG Oral Tablet

Gastrointestinal

TemplateRxNorm CodeDisplay
omeprazole_20mg312681Omeprazole 20 MG Delayed Release Oral Capsule
ondansetron_4mg312836Ondansetron 4 MG Oral Tablet

Allergy

TemplateRxNorm CodeDisplay
cetirizine_10mg1014678Cetirizine Hydrochloride 10 MG Oral Tablet
diphenhydramine_25mg1014599Diphenhydramine Hydrochloride 25 MG Oral Capsule

Example MedicationRequest

{
"resourceType": "MedicationRequest",
"status": "active",
"intent": "order",
"medicationCodeableConcept": {
"coding": [
{
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
"code": "308182",
"display": "Amoxicillin 500 MG Oral Capsule"
}
]
},
"subject": {
"reference": "Patient/patient-123"
},
"authoredOn": "2024-01-15T10:30:00Z",
"requester": {
"reference": "Practitioner/practitioner-456",
"display": "Dr. Jane Smith"
},
"dosageInstruction": [
{
"sequence": 1,
"text": "Take 1 capsule (500mg) by mouth three times a day for 7 days",
"timing": {
"repeat": {
"frequency": 3,
"period": 1,
"periodUnit": "d",
"boundsDuration": {
"value": 7,
"unit": "days",
"system": "http://unitsofmeasure.org",
"code": "d"
}
}
},
"doseAndRate": [
{
"doseQuantity": {
"value": 500,
"unit": "mg",
"system": "http://unitsofmeasure.org",
"code": "mg"
}
}
]
}
]
}

Search Parameters

ParameterTypeDescription
patientreferenceFilter by patient
statustokenFilter by status
_sortstringSort order
_countnumberMaximum results

Appointment Resource

Appointments represent scheduled healthcare visits.

Required Fields

FieldTypeDescription
resourceTypestringMust be "Appointment"
statuscodeproposed | pending | booked | arrived | fulfilled | cancelled | noshow | entered-in-error | checked-in | waitlist
participantBackboneElement[]Appointment participants
startinstantStart datetime (ISO 8601)
endinstantEnd datetime (ISO 8601)

Optional Fields

FieldTypeDescription
appointmentTypeCodeableConceptType of appointment (e.g., CONSULT)
descriptionstringReason for appointment
serviceTypeCodeableConcept[]Service being scheduled

Example Appointment

{
"resourceType": "Appointment",
"status": "booked",
"appointmentType": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0276",
"code": "CONSULT",
"display": "Consultation"
}
]
},
"description": "Follow-up consultation",
"start": "2024-01-20T09:00:00Z",
"end": "2024-01-20T09:30:00Z",
"participant": [
{
"actor": {
"reference": "Patient/patient-123",
"display": "John Smith"
},
"status": "accepted"
},
{
"actor": {
"reference": "Practitioner/practitioner-456",
"display": "Dr. Jane Smith"
},
"status": "accepted"
},
{
"actor": {
"reference": "Location/location-city-center",
"display": "City Center Clinic"
},
"status": "accepted"
}
]
}

Search Parameters

ParameterTypeDescription
patientreferenceFilter by patient
statustokenFilter by status
datedateFilter by date
actorreferenceFilter by participant
_sortstringSort order (use -start for most recent)

Practitioner Resource

Practitioners represent healthcare providers.

Fields Used

FieldTypeDescription
idstringPractitioner ID
nameHumanName[]Provider name
qualificationBackboneElement[]Specialty/qualifications

Example Practitioner

{
"resourceType": "Practitioner",
"id": "practitioner-456",
"name": [
{
"family": "Smith",
"given": ["Jane"],
"prefix": ["Dr."]
}
],
"qualification": [
{
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "394802001",
"display": "General medicine"
}
]
}
}
]
}

Search Parameters

ParameterTypeDescription
name:containsstringSearch by name
specialty:textstringSearch by specialty
_countnumberMaximum results
_sortstringSort order (default: name)

RelatedPerson Resource

RelatedPersons represent family members or caregivers linked to patients. HealthPass uses a bidirectional linking pattern that requires two RelatedPerson resources to fully represent a parent-child relationship.

Bidirectional Linking Pattern

To enable navigation in both directions (parent → children AND child → parent), two RelatedPerson resources are created for each relationship:

┌─────────────────────┐                      ┌─────────────────────┐
│ Patient (Parent) │ │ Patient (Child) │
│ id: parent-123 │ │ id: child-456 │
└─────────────────────┘ └─────────────────────┘
│ │
│ RelatedPerson #1 │ RelatedPerson #2
│ (attached to parent) │ (attached to child)
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ RelatedPerson │ │ RelatedPerson │
│ patient: Patient/parent-123 │ │ patient: Patient/child-456 │
│ relationship: CHILD │ │ relationship: PRN (parent) │
│ identifier: child-456 │ │ identifier: parent-123 │
└─────────────────────────────┘ └─────────────────────────────┘

Why Two Resources?

Use CaseSearch QueryRelatedPerson Used
Find all children of a parentpatient=Patient/parent-123&relationship=CHILD#1 (attached to parent)
Find the parent of a childpatient=Patient/child-456&relationship=PRN#2 (attached to child)

The identifier field stores the other patient's ID, enabling the system to fetch the related Patient resource after finding the RelatedPerson.

Required Fields

FieldTypeDescription
resourceTypestringMust be "RelatedPerson"
patientReference(Patient)The patient this resource is "attached to" (the search anchor)
relationshipCodeableConcept[]Type of relationship from this patient's perspective

Optional Fields

FieldTypeDescription
nameHumanName[]Name of the related person
identifierIdentifier[]Critical: Stores the other patient's ID for cross-reference

Relationship Codes

CodeSystemDisplayUse
CHILDhttp://terminology.hl7.org/CodeSystem/v3-RoleCodeChildWhen attached to parent, points to child
PRNhttp://terminology.hl7.org/CodeSystem/v3-RoleCodeParentWhen attached to child, points to parent

Identifier System

The identifier storing the linked patient ID uses:

FieldValue
systemhttp://example.org/fhir/related-person-patient
valueThe FHIR Patient ID of the linked person

Example: Complete Parent-Child Relationship

Given two patients:

  • Parent: John Smith (Patient/parent-123)
  • Child: Junior Smith (Patient/child-456)

RelatedPerson #1: Attached to Parent (enables "find my children")

{
"resourceType": "RelatedPerson",
"patient": {
"reference": "Patient/parent-123",
"display": "John Smith"
},
"relationship": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode",
"code": "CHILD",
"display": "Child"
}
]
}
],
"name": [
{
"family": "Smith",
"given": ["Junior"]
}
],
"identifier": [
{
"system": "http://example.org/fhir/related-person-patient",
"value": "child-456"
}
]
}

RelatedPerson #2: Attached to Child (enables "find my parent")

{
"resourceType": "RelatedPerson",
"patient": {
"reference": "Patient/child-456",
"display": "Junior Smith"
},
"relationship": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode",
"code": "PRN",
"display": "Parent"
}
]
}
],
"name": [
{
"family": "Smith",
"given": ["John"]
}
],
"identifier": [
{
"system": "http://example.org/fhir/related-person-patient",
"value": "parent-123"
}
]
}

Search Parameters

ParameterTypeDescription
patientreferenceFilter by the patient this RelatedPerson is attached to
relationshiptokenFilter by relationship code (CHILD, PRN, etc.)
_countnumberMaximum results

API Operations

OperationDescription
get_children(patient_id)Searches patient=Patient/{id}&relationship=CHILD, extracts child IDs from identifier
get_parent(patient_id)Searches patient=Patient/{id}&relationship=PRN, extracts parent ID from identifier
get_related_persons(patient_id)Returns all RelatedPerson resources attached to a patient
create_related_person(spec)Creates a new RelatedPerson resource

Implementation Notes

  1. Creating a relationship: When linking a parent and child, create BOTH RelatedPerson resources in a single transaction to ensure consistency.

  2. Deleting a relationship: Remove BOTH RelatedPerson resources to fully unlink.

  3. The patient field is the "anchor" - it determines which patient this resource appears under when searching.

  4. The identifier field stores the cross-reference to the OTHER patient, enabling bidirectional traversal.


DiagnosticReport Resource

DiagnosticReports represent lab results and diagnostic test reports.

Fields Used

FieldTypeDescription
codeCodeableConceptTest type
subjectReference(Patient)Patient reference
effectiveDateTimedateTimeWhen test was performed
resultReference(Observation)[]Observation results

Search Parameters

ParameterTypeDescription
subjectreferenceFilter by patient
_sortstringSort order (use -date for most recent)
_countnumberMaximum results

Coding Systems Reference

Primary Coding Systems

SystemURLUse
LOINChttp://loinc.orgObservations (40+ codes)
SNOMED CThttp://snomed.info/sctConditions, symptoms
RxNormhttp://www.nlm.nih.gov/research/umls/rxnormMedications (23 codes)
ICD-10-CMhttp://hl7.org/fhir/sid/icd-10-cmCondition diagnoses

HL7 Terminology Systems

SystemURL
Condition Clinical Statushttp://terminology.hl7.org/CodeSystem/condition-clinical
Condition Verification Statushttp://terminology.hl7.org/CodeSystem/condition-ver-status
MedicationRequest Statushttp://hl7.org/fhir/CodeSystem/medicationrequest-status
MedicationRequest Intenthttp://hl7.org/fhir/CodeSystem/medicationrequest-intent
Observation Categoryhttp://terminology.hl7.org/CodeSystem/observation-category
Units of Measurehttp://unitsofmeasure.org

API Operations Required

Minimum Required Operations

ResourceCreateReadSearchUpdate
PatientYesYesYesYes
ObservationYesYesYesNo
ConditionYesYesYesNo
MedicationRequestYesYesYesNo
AppointmentYesYesYesYes
PractitionerNoYesYesNo
RelatedPersonYesYesYesNo
DiagnosticReportNoYesYesNo

Bundle/Transaction Support

The system uses FHIR Bundle transactions for creating multiple resources atomically:

{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"resource": { ... },
"request": {
"method": "POST",
"url": "Observation"
}
}
]
}

Conditional Create (Deduplication)

Patient resources are created with If-None-Exist headers to prevent duplicates:

If-None-Exist: telecom=+27821234567

Data Flow Summary

┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│ WhatsApp │────▶│ HealthPass │────▶│ FHIR Server │
│ User Input │ │ Platform │ │ (EMR API) │
└─────────────────┘ └──────────────────┘ └─────────────────┘


┌──────────────────────┐
│ Resources Created: │
│ - Patient │
│ - Observations │
│ - Conditions │
│ - MedicationRequests│
│ - Appointments │
└──────────────────────┘

Patient Registration Flow

  1. User provides demographics via WhatsApp
  2. HealthPass creates Patient resource with conditional create (telecom-based deduplication)
  3. Patient ID stored in contact fields for future reference
  4. Demographic Observations created (sex at birth, ethnicity, etc.)

Clinical Encounter Flow

  1. User books appointment → Appointment resource created
  2. User reports symptoms → Observation resources created (self-reported)
  3. Provider makes diagnosis → Condition resource created
  4. Provider prescribes medication → MedicationRequest resource created

Health Data Access Flow

  1. User requests health records via HealthPass
  2. System queries Observations, Conditions, MedicationRequests for patient
  3. Most recent record per type is returned (deduplication)
  4. Data displayed in WhatsApp template or generates shareable PIN

Contact Information

For integration questions, please contact the HealthPass team.