# Handle FHIR identifiers and match patient data

One benefit of FHIR is that it’s flexible, but that can also be a challenge. Matching patient records to the appropriate data is a critical part of data exchange, but how do you do that with flexible, non-static identifiers?

_Spoiler alert:_ You should use patient identifiers and demographics to match data appropriately.

For more details, let’s break down some of the identifiers you’ll come across in a FHIR schema.

## Identifier vs. ID

An identifier is an external business identifier, meaning it’s created and maintained by a system outside the FHIR server. An identifier has an associated `system` and `value`. The `system` defines the format and interpretation of the `value`. The `system` identifies the external system and should be expressed in a FHIR payload as a URI. For example, a Social Security number is a type of identifier for a patient record, and the external system defines that it should be a numeric value with nine digits, as well as assigns the specific value.

A FHIR ID is an internal identifier for a resource. When a resource is stored in a database, it’s referenced using the resource ID. For data on demand, this is going to be a UUID.

### What Redox or your connection generates

In a FHIR notification, the ID is generated randomly. Any identifiers are pulled from the connection’s system, not Redox.

In a FHIR query, the database or server returning the response provides the ID. Redox may randomly generate this value if there’s any translation from one format to another. Any identifiers are pulled from the connection’s system, not Redox.

## Identifiers for patient data

In FHIR, you’ll come across a lot of identifiers related to clinical data, like identifiers for patients, encounters, labs, practitioners, documents, and more. These are external identifiers that generally stay static throughout the patient care lifecycle. In a FHIR schema, identifiers are your safest option for matching clinical data to the correct patient record. That also means you should include these identifiers when you’re sending your own clinical data to your connection so they can appropriately match the data, too.

We recommend including the `system` with the identifier whenever performing FHIR queries or writeback.

Additionally, there are a couple of other fields in a FHIR schema that help you understand the context of identifiers. These are the `use` and `type` fields. The `use` field describes the identifier’s purpose. If the `use` value is `official`, you can count on that being the primary identifier. All the others are secondary to that one. The `type` field gives context for the system where that identifier is meaningful.

> **Don't make assumptions**
>
> We can't guarantee the order of identifiers in an array. That means that the primary identifier—or the best one for your use case—may not necessarily be the first in the list. 
>
> So don't assume that the first identifier in the array is the one you want. Use the context fields for the identifier to determine if it's the right one. 

## FHIR resource IDs

A FHIR resource ID is an internal identifier within a FHIR server. While a resource may represent data, the resource itself is an independent concept with its own ID. For example, there could be two resources representing the same data because different systems have records for the same data.

You can think of a resource ID as a QR code on a shipping label. The QR code represents a unique package being shipped (i.e., FHIR message), but not necessarily the individual pieces inside the package (i.e., the included data). The resource ID identifies the unique resource (or package) representing clinical data, not any of the data inside.

If the data exchange happens between FHIR servers, you may use the resource ID to query for a specific FHIR resource. Using our shipping label example, the QR code works at different UPS locations, but it won’t work at a FedEx location. So, unless you’re querying a FHIR server directly, you can’t retrieve specific clinical data with a resource ID.

### How resource IDs apply to Redox

Redox isn’t a FHIR server. So resource IDs don’t stay static when you’re querying via Redox. A query response contains a resource ID, but you shouldn’t plan to use it to query for the same data later.

> **Data on demand**
>
> You may be able to successfully query for data with the resource ID if you're querying a data on demand instance. However, it's only likely to work if you've recently received or queried for the same data. 
>
> The resource ID may change in the case of a patient merge or other patient updates. So a resource ID isn't guaranteed to work with data on demand.

Within FHIR notifications, resource IDs are generated randomly for each message, so they’re not consistent across notifications. Those resource IDs in a bundle will be consistent within that message itself, and may be used to reference another resource only within that bundle.

## Full URLs

A full URL is a randomly generated UUID that identifies a FHIR resource. If you see a full URL instead of a resource ID, it typically means the resource doesn’t have an ID. Or if it does, the destination ignores the value.

Generally, the full URL links related resources together in a bundle. All the resources in the bundle will contain that same URL. However, the URL will be static throughout the bundle for that one-time message, not for the lifecycle of that message or for related data outside of the bundle.

So, a FHIR notification bundle has a consistent `fullURL` across the resources in that bundle. If the notification were re-sent, though, the `fullURL` would be different.

### How full URLs apply to Redox

Redox typically uses `message` bundles with randomly generated full URLs. They’re not consistent across messages, even if we’re sending the same resource again later.

> **A bundle story**
>
> For a bedtime story of how bundles work, keep reading!
>
> A FHIR bundle with a `message` or `document` type is like a package Redox ships to a customer. The package contains a bunch of items (<u>resources</u>) that go in the box with a packing list (`MessageHeader`) on top. Since the items in the box are related, we package each item with one or more strands (<u>references</u> and `fullUrls`) tied to the related item. If you pull on just the packing list (`MessageHeader`), you’ll end up with an entire “tree” of items all tied together.
>
> When you receive the package, we don’t know how you’re going to use the items inside. You might just pull out the wad of items still tied together and store it as-is on a shelf (_i.e., saving the bundle as a standalone message_).
>
> More likely, you'll use the items inside the package to stock your warehouse (<u>data store</u>). It's up to you to hire an inventory manager (<u>FHIR API engine</u>), whose job is to unpack and organize the packages. This involves checking the UPC/SKU on each item (<u>identifier</u>) to see if you already have this item in stock. If so, you'd add its contents to the same shelf location (<u>ID</u>) as the existing item. If it’s a new item, you'll find an empty shelf in the correct aisle (<u>resourceType</u>), put a local barcode sticker (<u>ID</u>) on that new shelf, and store it there. You'll cut the strands and replace them with another barcode sticker that points to the item it was tied to (_i.e., update the references to the newly stored IDs_)_._ In this case, you'll likely convert temporary URIs to permanent IDs when storing the data.
>
> For technical details, [see HL7's docs on bundles](https://www.hl7.org/fhir/bundle.html#references).

## For saving data

Don’t worry about including a resource ID unless your connection specifies that you should include a specific one when writing data to their system.

To handle references between resources, it’s better to use a full URL with the format of `urn:uuid:<example-uuid>`, where `<example-uuid>` is a placeholder for a real UUID string.

> When you write data back to an EHR system, you should always include whatever data points you have. You can think of this like including a patient’s demographics for a new patient record; the demographics give useful context for the patient’s chart. 
>
> This “demographics” concept is the same for any new “thing” you’re saving to an EHR system. Whenever you send a writeback message, be sure to include any relevant identifiers, codes, or context to tell the EHR system about the data you’re saving, like the following data points: 
>
> - patient first name
> - patient last name
> - patient date of birth
> - any patient identifiers
> - encounter identifier (if applicable)
> - encounter department/location (if applicable)
> - any unique record identifiers for the triggering event (e.g., order, result, medication admin ID)
> - relevant provider IDs and names (for orders)
> - procedure code (for orders)
>
> Make sure to include the contextual FHIR resources you reference in your writeback message. For example, if you reference a practitioner in an <u>Encounter</u> resource, also include the <u>Practitioner</u> resource so that the reference works in your connection's system.

### Patient identifiers for saving

Work with your connection to understand which patient identifiers will be the most meaningful to them.

For more guidance, [review FHIR’s known identifier systems](https://hl7.org/fhir/R4B/identifier-registry.html).

If using an identifier outside the known systems, [follow the FHIR identifier guide](https://hl7.org/fhir/R4B/datatypes.html#Identifier) by using one of the following:

- a custom URL, ideally pointing to a web page with information about the identifier system or a NamingSystem resource.
- a globally unique URN, such as an OID registered to the HL7 OID Registry.
- the global URI system defined as `urn:ietf:rfc:3986` (_only if_ the `identifier.value` is already a globally unique URI by itself).

Otherwise, leave the system undefined. In this case, you should at least include `identifier.type` with `text` and/or `coding` to give context. Without context, the identifier won’t be useful to the destination’s system.
