Patient $match | Medplum

The $match operation implements Master Patient Index (MPI) patient matching. It accepts a (possibly partial) Patient resource, searches your project for candidates, and returns a Bundle of matches — each annotated with a score and match grade.

Medplum's matching is based on the CMS Patient Matching framework, an evidence-based model that defines a fixed set of identity-attribute combinations strong enough to identify a patient. Rather than an ad-hoc weighted heuristic, matching is grounded in these approved combinations, with consistent normalization and conservative, constrained fuzzy matching.

CMS guidelines are in draft

The CMS Patient Matching framework is a draft proposal and is subject to change as the guidelines evolve. The criteria table and behavior described here reflect the current draft and may be updated in future releases.

Use Cases

Invocation

POST [base]/Patient/$match

Input Parameters

Parameter Cardinality Type Description
resource 1..1 Patient The patient to match against (may be partial). Must include at least one of: identifier, name, birthDate, or telecom.
onlyCertainMatches 0..1 boolean Selects the matching mode. See Matching Modes. Defaults to false.
count 0..1 integer Maximum number of results (discovery mode only). Defaults to the server's default search count.

Matching Modes

The same candidate-gathering and field-comparison pipeline runs in both modes; onlyCertainMatches changes the release rules.

Discovery (onlyCertainMatches: false, default)

Returns a ranked, graded list from the gathered candidate set for human review or triage. Approved CMS combination matches are ranked first with score 1.0; other candidates receive a lightweight FHIR $match discovery score below 1.0. Results are ordered from most to least likely and limited by count.

Disclosure (onlyCertainMatches: true)

Applies a uniqueness gate: the operation returns a patient only if exactly one candidate is a certain match (i.e. satisfies an approved CMS combination). If no candidate qualifies, if two or more distinct candidates qualify (an ambiguous result), or if candidate search is truncated such that uniqueness cannot be proven, the bundle is empty. This is the conservative behavior appropriate for releasing records in cross-organization exchange, where a wrong-patient disclosure is a critical error.

Output

Returns a Bundle of type searchset. Each entry contains a matched Patient with a search element:

Extension URL Value Meaning
http://hl7.org/fhir/StructureDefinition/match-grade code The match grade (see below).
https://medplum.com/fhir/StructureDefinition/cms-match-combination string The CMS combination ID that was satisfied (e.g. "02").
https://medplum.com/fhir/StructureDefinition/cms-match-type code exact or fuzzy — whether the satisfied CMS combination used fuzzy comparison.

Match Grades

The match-grade separates strict CMS combination matches from lower-confidence discovery candidates:

Grade Meaning
certain An approved CMS combination is fully satisfied.
probable A non-CMS discovery candidate with a score greater than or equal to 0.65.
possible A non-CMS discovery candidate with a score greater than or equal to 0.20.
certainly-not A candidate is explicitly blocked, such as by a generational-suffix conflict.

Candidates below the possible threshold, and candidates blocked by a generational-suffix conflict, are excluded from results.

Scoring

The search.score is intentionally not a probability — it is a simple, explainable ranking value:

This non-CMS score is Medplum's FHIR $match discovery ranking aid; it is not part of the CMS Table 2 release rule. Within a single query the denominator is constant, so candidates sort correctly by score; grade carries the human-facing classification.

Identity Factors

Eleven factors are used (gender is not a matching factor):

Identifier factors are matched by their system (issuing-authority namespace) and value, using the FHIR token convention system|value. An identifier with a system outside the CMS-specific namespaces is treated as a namespace-bound unique identifier (for example EMPI, FHIR Patient Identifier, CSP UUID, or project MRN).

Approved CMS Matching Combinations

A candidate is a certain match when its agreeing factors form one of these approved combinations and it is the unique such candidate. Fields marked with * may be satisfied by a fuzzy comparison; at most one field per match may be fuzzy.

ID Field Combination
01 First Name* + Last Name* + DOB + Street Line*
02 First Name + Last Name* + DOB + Phone
03 First Name* + Last Name* + DOB + Email
04 First Name* + Last Name + DOB + SSN (last 4)
05 First Name + Last Name* + DOB + SSN (last 4)
06 First Name* + Last Name + DOB + ITIN (last 4)
07 First Name + Last Name* + DOB + ITIN (last 4)
08 First Name + DOB + MBI
09 First Name + DOB + Legal ID
10 Last Name* + DOB + Legal ID
11 First Name + DOB + Phone
12 First Name + DOB + Email
13 Last Name + Phone + SSN (last 4)
14 Last Name + Phone + ITIN (last 4)
15 Last Name* + Email + SSN (last 4)
16 Last Name* + Email + ITIN (last 4)
17 First Name + Phone + SSN (last 4)
18 First Name + Phone + ITIN (last 4)
19 First Name + Email + SSN (last 4)
20 First Name + Email + ITIN (last 4)
21 Phone + MBI
22 Phone + Legal ID
23 Email + MBI
24 Email + Legal ID
25 Legal ID + MBI
26 Namespace-bound Unique Identifier

Normalization

Every field represents the set of all known values (current and historical — e.g. maiden/previous names, all addresses, all phone numbers), and matching compares against all of them. Before comparison, values are normalized:

Matching is intentionally limited to these mechanical, deterministic normalizations. Medplum ships no opinionated nickname equivalence table (BobRobert) or placeholder/test-value suppression table, so behavior is transparent and reproducible.

Fuzzy Matching

Fuzzy matching is constrained: it applies only to First Name, Last Name, and Street Line, only where a combination permits it (* above), only to values at least 5 characters long, and tolerates a Damerau–Levenshtein distance of 1 (one insertion, deletion, substitution, or adjacent transposition). At most one field per match may be fuzzy. Phonetic matching (e.g. Soundex) is not used.

Candidate Search

Before scoring, candidates are gathered with selective FHIR searches anchored on the query's exact identifiers, telecom, and name + birthdate:

Results are deduplicated by patient ID, then compared and scored in memory. Discovery mode ranks the gathered candidate set; it is intended for review and is not an exhaustive population scan. In disclosure mode, if a search hits its result cap (uniqueness cannot be proven), the match is suppressed.

Example

Request

POST /fhir/R4/Patient/$match

Content-Type: application/fhir+json

{

"resourceType": "Parameters",

"parameter": [

{

"name": "resource",

"resource": {

"resourceType": "Patient",

"name": [{ "family": "Smith", "given": ["John"] }],

"birthDate": "1970-03-15",

"telecom": [{ "system": "phone", "value": "555-867-5309" }]

}

},

{ "name": "onlyCertainMatches", "valueBoolean": false }

]

}

Response

{

"resourceType": "Bundle",

"type": "searchset",

"total": 1,

"entry": [

{

"resource": {

"resourceType": "Patient",

"id": "patient-abc",

"name": [{ "family": "Smith", "given": ["John"] }],

"birthDate": "1970-03-15",

"telecom": [{ "system": "phone", "value": "5558675309" }]

},

"search": {

"mode": "match",

"score": 1.0,

"extension": [

{

"url": "http://hl7.org/fhir/StructureDefinition/match-grade",

"valueCode": "certain"

},

{

"url": "https://medplum.com/fhir/StructureDefinition/cms-match-combination",

"valueString": "02"

},

{

"url": "https://medplum.com/fhir/StructureDefinition/cms-match-type",

"valueCode": "exact"

}

]

}

}

]

}

Here First Name + Last Name + DOB + Phone match after U.S. phone normalization, satisfying combination 02 — a certain match with score 1.0. In disclosure mode (onlyCertainMatches: true) this same single unique match would be returned; if a second patient also satisfied a combination, the bundle would instead be empty.

Error Responses

Status Code Description
400 Bad Request resource parameter is missing or is not a Patient
400 Bad Request Input Patient has no matchable fields (identifier, name, birthDate, or telecom)
403 Forbidden Insufficient permissions to search Patient resources