The HL7 standard is often jokingly referred to as the “non-standard standard.” This is not very fair but it does reflect the fact that almost every hospital, clinic, imaging center, lab, and care facility is “special” in terms of how it implements HL7 (really?, why?). The reason is primarily because there is no such thing as a standard business or clinical process for interacting with patients, clinical data, or related personnel.
The HL7 messaging protocol was designed to facilitate high volumes of pre-defined data to be shared across many applications reliably. The protocol selected to make this happen was a traditional file transfer or a TCP/IP socket in both a real-time and batched fashion. HL7 v2 message structure is complex, flat, and delimited. HL7 has obviously evolved over time. The current version of HL7 is v3, however, older versions exist and make up the bulk of the standard used today primarily because of the large number customizations that have been done to each HL7 message.
The key differences between an HL7 v2 and HL7 v3 message are as follows:
- v2.x was primarily meant for clinical communications — medical orders, patient registration etc. whereas v3.x has additional features for use by informaticists and for government reporting requirements.
- v2.x was a custom format (barebones text - all coded and separated by a pipe with headers and multiple segments etc.) v2.x looks like this:
whereas an HL7 v3.0 message is an XML format (I’m not sure if that’s an improvement) - very verbose and detailed - like this:
- All v2.x formats are backward compatible. v3.x is a wholly separate format and not backwards compatible.
Any technology solution in healthcare has to support both v2.x and v3.x formats. Open source parsing solutions exist to help with processing HL7 (see section below on Parsing HL7 messages). However, in this author’s humble opinion, the 3.x standards are unlikely to be implemented given the investments already made in the 2.x versions. The FHIR standards, which are still under active development, are more likely to be implemented rather than the v3.0 standards. See this Figure for some data supporting this hypothesis. (source: Corepoint)
Every conversation that you’ve ever overheard about HL7 usually includes customizations to be accounted for and associated implementation costs. When I was starting in this space, I heard the same things but wasn’t really sure what it meant.
So here’s a summary of what I’ve learned. I will caveat this by saying that I am not an HL7 expert - there are folks out there who have much more extensive experience than I do; Keith Boone for one, whose blog is worth subscribing to if you have any interest in healthcare standards for one. Given that I’m not an expert, if you see any errors in this document, please let me know (and also let us know if you’re looking for an interesting change in careers).
More about custom formats… HL7 messages are indeed customized but this does not imply, as an example, that every ADT (admission, discharge, transfer) message is different between different hospitals; ADT is ubiquitous so it’s an HL7 message type you should know. Customization came about when certain message types, like ADT, could not support sending all the data elements that needed to be sent. For example, a message might be able to handle only 50 data elements but an EKG reading might need to send over 200. The extra data elements were then sent over using the notorious Z segment - a miscellaneous segment into which pretty much any key value pair could be jammed in. This custom blob of data in the Z segment would then need to be parsed and mapped etc. for automated processing and use, creating impressive levels of customization in data exchange.
Before you get too excited, the true customization comes in the form of the content of the HL7 message. The HL7 organization has defined code sets to be used to translate the terse codes sent over within the HL7 message. See here for a listing of some v2.3 code sets or here for a more comprehensive listing from the “horse’s mouth.” The purpose of the code sets, as you can imagine, is to codify the content to reduce the size of the message. ANT, as an example, stands for Anterior in the context of body sites and so on. And, by the way, these code sets for HL7 have also evolved / been added to / modified with each version of HL7. However, these code sets, which are released and maintained as part of the standard, aren’t often adhered to. EHRs (usually) and hospitals have defined their own code sets. So the content sent over within the HL7 message needs to be “looked up” against that specific code set before it can be made useful. An Epic code set is unique (although common across Epic deployments) and different from an AllScripts code set. This is the uniqueness that must be addressed by any solution in this space and the reason why HL7 implementations can sometimes be expensive - they need to take into account not only the Z segments and map them to the appropriate data models but the code sets have to be taken into account as well.
So, in practice, HL7 can be perhaps best described as a messaging protocol and format standard in most implementations rather than as a comprehensive messaging standard.
HL7 Message Types (most common)
There are more than 80 message types, a whole host of segments and codes for pretty much anything you can think of. See this document for a pretty comprehensive listing. But the following are the most common HL7 message types:
|ACK||General acknowledgement message. This is the ack sent when a message is received by the destination system. ACKs are automated responses. However, you could use ACKs as a way to modulate the speed at which messages come through as the sending system will not send the next message until the ACK is received|
|ADT||Admission, Discharge and Transfer message. Created whenever a patient goes through any of those states. There are a whole list of these possible states. See below for a sampling of a few more|
|ORM||Pharmacy/treatment order message|
|ORU||Observation message (unsolicited). Unsolicited because the destination systems are not asking for it, it is fired off and the source systems will take it in and process it if needed or discard it if not.|
|BAR||Add or change the billing account.|
|SIU||Schedule information (unsolicited) usually patient specific. This is used to create, modify and delete patient appointments and other schedules.|
|MDM||Medical document management. This often acts as a workhorse. It is meant to handle documents like notes, reports etc. But often is used to capture a whole host of other data for which there is no easy mapping. In which case, the incoming data gets converted into a PDF and pushed into the EHR via this MDM message|
|DFT||Detailed financial transactions. This data is used to capture the details of procedures etc. so that claims can be generated.|
|MFN||Master files notification - changes to core data elements are sent through this.|
|QRY||Query - as the name implies is used to query source systems for data on things like patient demographics etc.|
|RAS||Pharmacy/treatment administration message|
|RDE||Pharmacy/treatment encoded order message|
|RGV||Pharmacy/treatment give message|
It should also be noted that each of these message types have different types (sub-types) as well. For example, there are 51 (yep, that’s right) different types of ADT messages that are used for various trigger events. Some of the most commonly used ADT messages include:
- ADT-A01 – patient admit
- ADT-A02 – patient transfer
- ADT-A03 – patient discharge
- ADT-A04 – patient registration
- ADT-A05 – patient pre-admission
- ADT-A08 – patient information update
- ADT-A11 – cancel patient admit
- ADT-A12 – cancel patient transfer
- ADT-A13 – cancel patient discharge
The important thing to remember is that the content of the message doesn’t change all that much between all these sub-types. The message is still about the specific patient (PID segment - see segment section below).
A segment is a group of fields that then contain different types of data. Each segment exists independently and can be utilized in multiple messages, in different sequences. Segments may be required for a particular message or in other cases, they may be optional.
A unique three-character code called the “Segment ID” identifies each segment. Segment ID codes beginning with the letter Z are reserved for the “custom” Z-segments (key value pairs) that are not part of the HL7 standard.
You can remove one or more segments from a message if desired. But because HL7 rules state that unexpected or unused segments should be ignored, most systems will ignore the unexpected segments without issue (therefore, manually removing these segments is unnecessary). Segments should be removed only if one of the receiving systems will not have problems when unexpected segments are received.
These are the most common segment types that will be used across multiple message types.
|NTE||Notes and comments|
|FT1||For DFT messages — Financial transactions|
At a high level, that’s HL7. Look for further articles delving into more details on HL7 message structures and the common message types.
If you’re looking to integrate EHR data with your application without becoming an HL7 expert, Datica can help. Learn more about Datica Compliant Managed Integration for HL7.