FHIR Patient Resource Integration: Search, Matching, and Common Pitfalls
The FHIR Patient resource looks simple - name, birth date, identifiers - until you try to reliably find the right patient across systems that don't share a common ID, which is where most real Patient-resource integration work actually lives.
What's actually in a FHIR Patient resource
Core fields include identifiers (often multiple - an EHR's internal ID, an MRN, sometimes an SSN reference), name, birth date, gender, address, telecom (phone/email), and a `link` field that can point to other Patient resources representing the same person (used for merged or related records). In practice, which of these are reliably populated varies significantly by source system and even by individual patient record within the same system.
Why Patient.Search doesn't always work the way the spec implies
Demographic search (searching by name and birth date) is supported by the FHIR spec, but real-world behavior varies significantly by access model - we've found, through direct testing against Epic's sandbox, that Backend Systems (system-to-system, no interactive user) apps specifically can return no results from demographic search even for a patient confirmed to exist, while Patient.Read by a known FHIR ID works immediately (see our companion piece on this specific finding). Don't assume demographic search will work reliably for your access model without testing it directly against your specific target system.
The more robust pattern, where available, is resolving a patient's FHIR ID once - from a referral, an order, a prior lookup, or a matching process run through data your organization already controls - and using Patient.Read by ID for all subsequent access, rather than re-searching by demographics on every request.
Identity matching across systems without a shared ID
When two systems don't share a common patient identifier, matching is a probabilistic problem: combining name, birth date, and partial identifiers (phone, address) with a confidence-scored matching algorithm, rather than expecting an exact match on any single field. Some FHIR servers expose a `$match` operation specifically for this purpose; where it's not available, matching logic needs to be built explicitly, with a clear policy for what confidence threshold triggers an automatic match versus a manual review queue - silently auto-matching low-confidence pairs is a real patient-safety risk, not just a data-quality inconvenience.
Common pitfalls
Assuming `entry[0]` in a search Bundle is always a Patient resource - some servers return an OperationOutcome (a warning/error object) in that position when a search matches nothing, which naive code can misinterpret as a valid patient. Treating a patient's identifiers as stable and unique across systems when they frequently aren't (the same MRN format can exist independently in two unrelated systems). Not handling the `link` field, which can mean your integration is working with an outdated or merged record without realizing it.
FAQ