Category Archives: v2

Interconversion between #FHIR and HL7 v2


What advice do you give for introducing FHIR in new software, while continuing to maintain HL7v2 interoperability with client applications that do not speak FHIR?

For example, are FHIR resources the way to go as an internal representation of an application’s health care data?

If yes, is it practical to convert HL7 messages into FHIR resources (e.g. Patient, Practitioner, ProcedureRequest, ReferralRequest, Appointment…)? What open source software do you recommend for converting HL7 messages into FHIR resources (and vice-versa)?

Or is it better to use FHIR for external information exchange only (with outside FHIR clients)?


I’ve worked with several projects rebuilding their products around FHIR resources. Like all development methodologies, this has pros and  cons. What you get out of the box is a highly interoperable system, and you get a lot of stuff for free. But when your requirements go beyond what’s in the specification, it starts to get hard – FHIR is an interoperability standard, that focuses on the lowest common denominator: what everyone agrees with. Whether that’s a net benefit depends on how far beyond common agreement your going to go. (This, btw, is a demonstration of my 3rd law of interoperability).

It is practical to convert HL7 messages to FHIR resources and vice versa, yes. We’ve seen plenty of that going on. But there’s no canned solution, because to do the conversion, you have to do two things:

  • Figure out all the arcane business logic and information variants and code this into the conversion
  • Figure out how to integrate your conversion logic into your application framework

The upshot of this is that you have a programming problem, and most people solve this by taking a open source libraries for v2 and FHIR in the language of their choice (most languages have one of those) and writing the business logic and application integration in their development language of choice. Hence, there’s no particular open source library to do the job other than the parsers etc. There are some commercial middleware engines that include FHIR as one of the formats that can be supported.

In the FHIR spec, we’ve defined a mapping language that tries to abstract this – so you can separate the business logic from the application integration, and a platform independent business logic that has libraries for whatever platform. That’s an idea that is gradually starting to gather some interest, but is still a long way from maturity.

With regard to using FHIR for external exchange only… what I usually say about this that is that it makes sense to implement FHIR for new things first, and then to replace old things only when they become a problem. And most new stuff is on the periphery, where the architectural advantages to FHIR are really big. But internally, v2 will increasingly become a major service limitation in time, and will have to be replaced. The open question is how long that timeline is. We don’t know yet.


Question: where did the v2 messages and events go in FHIR?


I’m relatively new to the HL7 scene having implemented a few V2 messaging solutions (A08 , A19, ORU) and the V3/CDA work on PCEHR.  I am trying to get my head around FHIR.  So far I am stumped in how I would go about for example implementing the various trigger/messages I have done in V2.  Is there any guidance?  I cant find much.  Is that because the objective of FHIR is implementers are free to do it anyway they like?  If you could send me some links that would be a good starting point that would be great


Most implementers of FHIR use the RESTful interface. In this approach, there’s no messaging events: you just post the Patient, Encounter etc resources directly to the server. The resources contain the new state of the Patient/Encounter etc, and the server (or any system subscribed to the server) infers the events as needed.

A few implementers use the messaging approach. In this case, the architecture works like v2 messaging, with triggers, and events. However, because the resources are inherently richer than the equivalent v2 segments (e.g. see, we didn’t need to define a whole set of A** messages, like in V3. Instead, there’s just “admin-notify” in the event list.

For XDS users (HIE or the PCEHR in Australia), see IHE’s Mobile Health Document Specification.


(When) Will #FHIR replace HL7 v2 messaging?


I’m working in the healthcare domain and has been hearing the FHIR developments for a while. In my hospital setting, we typically have a Patient Registration System, a EMR system, a LIS and RIS system, and some machine interface (Vital Signs, BMI). We are communicating with each other using HL7 V2 standard and is working fine.

My question is, how does the development of FHIR helps in existing interfaces? Do we need to eventually replace these interfaces with FHIR? If yes, all vendors of the respective systems needs to be FHIR ready.

I like to believe that FHIR is for a future expansion packs, and not a move to replace all existing interfaces. Meaning HL7 V2 are expected to stay.  Another question: In HL7, we dealt with messaging in asynchronous mode. But the FHIR standards, we are moving from the messaging world?


This is a pretty frequently asked question – I got it fairly often at HIMSS last week. My standard answer is:

You don’t fix what isn’t broken, so initially, no one will replace v2 messaging interfaces with FHIR interfaces. Instead, institutions will use FHIR on their perimeter, for integration between enterprises.

I say that because FHIR is able to leverage all sorts of web standards, so it’s naturally a better choice than v2 from that point of view alone, and also because this is where all the action currently is, and why would you use v2 now? Most people I hear from are using FHIR in preference to v2 even though FHIR is still a moving target.

But once that’s in place, institutions will increasingly find that what they can do on the perimeter interfaces is constrained by what the internal services can provide – and then they’ll start gradually replacing their v2 interfaces with FHIR interfaces.


Question: Entering the #FHIR Bandwagon


HL7 v1 came first, followed by V2, followed by CDA, V3. For newer entrants into Standards and Interoperability is the central dogma of S&I is something like Learn V2 first, then CDA, then V3 and then FHIR and then SMART on FHIR and then Newer or a person can just straightaway buy an FHIR textbok or Collect all FHIR blogs at one place and start reading from scratch?


V2, CDA, FHIR+Smart on FHIR are all different approaches to solving various healthcare interoperability problems. If you’re deeply invested in the standards process, then learning all of v2, CDA, and FHIR will give you deeper perspective about what has and hasn’t worked, and what ideas last across the various specifications. But if you’re just solving a particular problem, then you just pick one, learn it, and give into the job.

Which one to learn? 

  • Actually, this is simple. If you have to use one, because of legal requirements, or because your trading partners have already chosen one – that’s by the far the most likely situation – then you don’t have to decide. Otherwise, you’d use FHIR

How to learn? From a previous post, these are the books I recommend:

None of these cover FHIR. But, in fact, Tim invited me to join with him for the forthcoming 3rd edition of his book, to cover FHIR, and this should be available soon. In the meantime, as you say, there’s the FHIR blogs.

Question: HL7 v2 message processing rules


I have a question on patient registration message A04. We process the A04 message in the following way:

When our system receives A04 for processing, we contruct a QBP and send to MPI and wait for an RSP message response from the MPI. Based on the RSP response we either register the patient by sending an AA or reject by sending an AR.

We notice that sometimes this process may take up to 45 minutes to complete and within this time we receive mpi updates for this patient.

If our system received mpi updates for this patient while this patients registration is in process

  1. should we return patient not found as patient is not registered yet.
  2. should we Wait for the patient registration to complete before processing mpi update message.

Is the above requirement in any of the hl7 document?


No. there is no specific rules about stuff like this in the base HL7 v2 standard. You have to get specific agreement on a site to site basis. Some specific national or vendor implementation guides do include specific messaging processing rules of this nature, but I’m not aware of any implementation guide that’s relevant to your question.

So you’ll have to make a decision based on customer desires. 45 minutes does sound like a really long time – that’s the kind of delay that clearly calls for business rules, and these are going to vary from installation to installation.

Question: PRD segment in ORM and ORU messages?


Can the PRD segment be included in the HL7 ORM message and ORU messages?This would allow clear identification of Referring Provider and Consulting Provider.


The PRD segment is not part of the base HL7 definition for either the ORM or ORU messages.

I think that the intent is that you’d exchange the full details of Referring and Consulting Providers via some other means of transfer, such as Master File Messages (see chapter 8 of the HL7 v2 standard).

Of course, that kind of approach won’t work for some of the ways in which ORM and ORU messages are used – e.g. where the sender and receiver aren’t tightly bound in a single institution. So you can add the PRD segement if you want, but you’ll have to ensure that all the parties involved in the exchange know that it will be there and why it’s there. I’d add it after the ORC segment.


A JSON representation for HL7 v2?

Several weeks ago, I was in Amsterdam for the Furore FHIR DevDays. While there, Nikolay from Health Samurai showed off a neat javascript based framework for sharing scripts that convert from HL7 v2 to FHIR.

Sharing these scripts, however, requires a standard JSON representation for HL7 v2 messages, and that turns out to have it’s challenges. Let’s start with what looks like a nice simple representation:

 "MSH" : ["|", null, "HC", "HC1456", "ATI", "ATI1001", "200209100000",
    null, null, [ "ACK", "ACK" ], "11037", "P", "2.4"],
 "MSA" : [ "AA", "345345" ]

This is a pretty natural way to represent a version 2 message in JSON, but it has a number of deficiencies. The first is that a message can contain more than one segment of the same type, and JSON property names must be unique (actually, JSON doesn’t explicitly say this, but Tim Bray’s clarification does). So the first thing we need to do is make the segments an array:

 "v2" : [
  [ "MSH", "|", null, "HC", "HC1456", "ATI", "ATI1001", "200209100000",
     null, null, [ "ACK", "ACK" ], "11037", "P", "2.4"],
  [ "MSA", "AA", "345345" ]

This format – where the segment code is item 0 in the array of values that represent the segment – has the useful property that field “1” in the HL7 definitions becomes item 1 in the array.

Btw, alert readers will note that the { “v2”: } part is pure syntax, and could potentially be dropped, but my experience is that many JSON parsers can only accept an object, not an array (arrays must be properties of objects), so we really should have an object wrapper. At the DevDays, we discussed pulling out some data from the MSH, and making it explicit:

 "event" : "ACK",
 "msg" : "ACK",
 "structure" : "ACK",
 "segments" : [

I’m not sure whether that’s justified or not. The information is in the MSH segments, so it’s straight duplication.


However this nice simple to grasp format turns out to be relatively unstable – the actual way that an item is represented depends on the values around it, and so scripts won’t be shareable across different implementations. As an example, take the representation of MSH-3, of type HD (ST from 2.1 to 2.2). In the example above, it’s represented as “HC” – just a simple string, to correspond to |HC|. If, however, the source message uses one of the other components from the HD data type, then it would change to a JSON representation of e.g. |^HC^L|, to, say:

 { "Universal ID" : "HC", "Universal ID Type" : "L" }

So the first problem is that whether or not subsequent components appear changes the representation of the first component. Note that this is an ambiguity built into v2 itself, and is handled in various different ways by the many existing HL7 v2 libraries. The second problem with this particular format is that the names given to the fields have varied across the different versions of HL7 v2, as they have never been regarded as signficant. Universal ID is known as “universal ID” from v2.3 to 2.4 – other fields have much more variation than that. So it’s better to avoid names altogether, especially since implementers regularly just use additional components that are not yet defined:

 { "2" : "HC", "3" : "L" }

but if all we’re going to do is have index values, then let’s just use an array:

 [ null, "HC", "L" ]

Though this does have the problem that component 2 is element 01 We could fix that with this representation:

 [ "HD", null, "HC", "L" ]

where the first item in the array has it’s type; this would be variable across versions, and could be omitted (e.g. replaced with null) – I’m not sure whether that’s a value addition or not. Below, I’m not going to add the type to offset the items in the array, but it’s still an option.

The general structure for a version 2 message (or batch) is:

  • A list of segments.
  • Each segment has a code, and a number of data elements
  • Each data element can occur more than once


  • Each Data element has a type, which is either a simple text value, or one or more optional components
  • Each component has a type, which is either a simple text value, or one or more optional sub-components
  • Each subcomponent has a text value of some type


  • Each Data element has one or more components
  • Each component has one or more subcomponents
  • Each subcomponent has a text value of some type

Aside: where’s the abstract message syntax? Well, we tried to introduce it into the wire format in v2.xml – this was problematic for several reasons (names vary, people don’t follow the structure, the structures are ambiguous in some commonly used versions, and most of all, injecting the names into the wire format was hard), and it didn’t actually give you much validation, which was the original intent, since people don’t always follow them. That’s why it’s called “abstract message syntax”. Here, we’re dealing with concrete message syntax.

The first is what the specification describes, but the wire format hides the difference between the various forms, and you can only tell them apart if you have access to the definitions. The problem is, often you don’t, since the formats are often extended informally or formally, and implementers make a mess of this across versions. And this practice is fostered by the way the HL7 committees change things. I’ve found, after much experimentation, that the best way to handle this is to hide the difference behind an API – then it doesn’t matter. But we don’t have an API to hide our JSON representation behind, and therefore we have to decide.

That gives us a poisoned chalice: we can decide for a more rigorous format that follows my second list. This makes for more complicated conversion scripts that get written against the wire format, and are much more re-usable, or we can decide for a less rigorous format that’s easier to work with, that follows the v2 definitions more naturally, but that is less robust and less re-useable.

Option #1: Rigor

In this option, there’s an array for every level, and following the second list:

  1. Array for segments
  2. Array for Data Elements
  3. Array for repeats
  4. Array for components
  5. Array for sub-components

And our example message looks like this:

 "v2" : [
  [ [[["MSH"]]], [[["|"]]], null, [[["HC"]]], [[["HC1456"]]], [[["ATI"]]], 
    [[["ATI1001"]]], [[["200209100000"]]], null, null, [[["ACK"], ["ACK"]]], 
    [[["11037"]]], [[["P"]]], [[["2.4"]]] ],
  [ [[["MSA"]]], [[["AA"]]], [[["345345"]]] ]

This doesn’t look nice, and writing accessors for data values means accessing at the sub-component level always, which would be a chore, but it would be very robust across implementations and versions. I’m not sure how to evaluate whether that’s worthwhile – mostly, but not always, it’s safe to ignore additional components that are added across versions, or in informal extensions.

Option 2: Simplicity

In this option, there’s a choice of string or array:

  1. Array for segments
  2. Array for Data Elements
  3. Array for repeats
  4. String or Array for components
  5. String or Array for sub-components

And our example message looks like this:

 "v2" : [
  [ "MSH", ["|"], null, ["HC"], ["HC1456"], ["ATI"], ["ATI1001"], ["200209100000"],
     null, null, [[ "ACK", "ACK" ]], ["11037"], ["P"], ["2.4"]],
  [ "MSA", ["AA"], ["345345"] ]

The annoying thing here is that we haven’t achieved the simplicity that we really wanted (what we had at the top) because of repeating fields. I can’t figure out a way to remove that layer without introducing an object (more complexity), or introducing ambiguity.


Which is better? That depends, and I don’t know how to choose. For the FHIR purpose, I think that the robust format is probably better, because it would allow for more sharing of conversion scripts. But for other users, the simpler format might be more appropriate.

p.s. Nikolay watched the discussion between James Agnew and myself on this with growing consternation, and decided to cater for multiple JSON formats. That’s probably a worse outcome, but I could understand his thinking.



Observation of Titers in HL7 Content

Several important diagnostic measures take the form of a Titer. Quoting from Wikipedia:

A titer (or titre) is a way of expressing concentration. Titer testing employs serial dilution to obtain approximate quantitative information from an analytical procedure that inherently only evaluates as positive or negative. The titer corresponds to the highest dilution factor that still yields a positive reading. For example, positive readings in the first 8 serial twofold dilutions translate into a titer of 1:256 (i.e., 2−8). Titers are sometimes expressed by the denominator only, for example 1:256 is written 256.

A specific example is a viral titer, which is the lowest concentration of virus that still infects cells. To determine the titer, several dilutions are prepared, such as 10−1, 10−2, 10−3, … 10−8.

So the higher the titer, the higher the concentration. 1:2 means a lower concentration than 1:128 (note that this means the clinical intent is the opposite of the literal numeric intent – as the titre gets lower, the concentration gets higher).

Titers are pretty common in clinical diagnostics – I found about 2600 codes for titer type tests in LOINC v2.48 (e.g. Leptospira sp Ab.IgG).

Representing Titers in HL7 Content

In diagnostic reports, titers are usually presented in the text narrative (or the printed form) using the form 1:64, since this makes clear the somewhat arbitrary nature of the numbers in the value. However it’s not unusual for labs to report just the denominator (e.g. “64”) and the person interpreting the reports is required to understand that this is a titer test (this is usually stated in the name).

When it comes to reporting a Titer in structured computable content, there’s several general options:

  • represent it as a string, and leave it up to the recipient to parse that if they really want
  • represent it as an integer, the denominator
  • use a structured form for representing the content

Each of the main HL7 versions (v2, CDA, and FHIR) offer options for each of these approaches:

String Integer Structured
V2 OBX||ST|{test}||1:64 OBX||NM|{test}||64 OBX||SN|{test}||^1^:^64
CDA <value xsi:type=”ST”> 1:64 </value> <value xsi:type=”INT”> 1:64 </value> <value xsi:type=”RTO_INT_INT”> <numerator value=”1”/> <denominator value=”64”> </value>
FHIR “valueString “ : “1:64” “valueInteger” : ”64” “valueRatio”: { “numerator” : { “value” : “1” }, “denominator” : { “value” : “64” } }

(using the JSON form for FHIR here)

One of the joys of titres is that there’s no consistency between the labs – some use one form, some another. A few even switch between representations for the same test (e.g. one LOINC code, different forms, for the same lab).

This is one area where there would definitely be some benefit – to saying that all labs should use the same form. That’s easy to say, but it would be really hard to get the labs to agree, and I don’t know what the path to pushing for conformance would be (in the US, it might be CLIA; in Australia, it would be PITUS; for other countries, I don’t know).

One of the problems here is that v2 (in particular) is ambiguous about whether OBX-5 is for presentation or not. It depends on the use case. And labs are much more conservative about changing human presentation than changing computable form – because of good safety considerations. (Here in Australia, the OBX05 should not be used for presentation, if both sender and receiver are fully conformant to AS 4700.2, but I don’t think anyone would have any confidence in that). In FHIR and CDA, the primary presentation is the narrative form, but the structured data would become the source of presentation for any derived presentation; this is not the primary attested presentation, which generally allays the lab’s safety concerns around changing the content.

If that’s not enough, there’s a further issue…

Incomplete Titers

Recently I came across a set of lab data that included the titer “<1:64”. Note that because the intent of the titre is reversed, it’s not perfectly clear what this means. Does this mean that titre was <64? or that the dilution was greater than 64. Well, fortunately, it’s the first. Quoting from the source:

There are several tests (titers for Rickettsia rickettsii, Bartonella, certain strains of Chlamydia in previously infected individuals, and other tests) for which a result that is less than 1:64 is considered Negative.  For these tests the testing begins at the 1:64 level and go up, 1:128, 1:256, etc.   If the 1:64 is negative then the titer is reported as less than this.

The test comes with this sample interpretation note:

Rickettsia rickettsii (Rocky Mtn. Spotted Fever) Ab, IgG:

  • Less than 1:64: Negative – No significant level of Rickettsia rickettsii IgG Antibody detected.
  • 1:64 – 1:128: Low Positive – Presence of Rickettsia rickettsii IgG Antibody detected
  • 1:256 or greater: Positive – Presence of Rickettsia rickettsii IgG Antibody, suggestive of recent or current infection.

So, how would you represent this one in the various HL7 specifications?

String Integer Structured
V2 OBX||ST|{test}||<1:64 {can’t be done} OBX||SN|{test}||<^1^:^64
CDA <value xsi:type=”ST”> &lt;1:64 </value>  {can’t be done} <value xsi:type=”IVL_RTO_INT_INT”> <high> <numerator value=”1”/> <denominator value=”64”> </high> </value>
FHIR “valueString “ : “<1:64” {can’t be done} “valueRatio”: { “numerator” : { “comparator” : “<”, “value” : “1” }, “denominator” : { “value” : “64” } }

This table shows how the stuctured/ratio form is better than the simple numeric – but there’s a problem: the CDA example, though legal in general v3, is illegal in CDA because CDA documents are required to be valid against the CDA schema, and IVL_RTO_INT_INT was not generated into the CDA schema. I guess that means that the CDA form will have to be the string form?



Question: sending PDFs via HL7 v2

This question is a follow up to one asked on Stack Overflow


On stack overflow you asked me to look at MDM message type. My question is that I know some systems can’t handle MDM message types so if this is the case how could sending of a url for a pdf be handle in that case?

What is the best way(appropriate message/event type) to put a url for a pdf in an hl7 message(ie what are the message types and segment, etc.. that are appropriate)?

Also does the HL7 standard allow for the unsolicited pushing of pdf messages whether it be a url to a message or an actual pdf document encoded in hl7? For example if an ADT message came in and was successfully loaded into my system and I wanted to create an hl7 message to send out with the link or embeded pdf that i created. What hl7 message would i use to send?


Most systems would have no concept of why they’d accept an unsolicited PDF – where would it go? what’s it’s workflow? If they do know the answer to that question, and they can accept it, then they should implement the MDM messages (T12, T14, T15 maybe), since that’s the correct message type for that functionality.

If the destination system doesn’t handle MDM messages, then it most likely doesn’t handle unsolicited PDF messages, but you’d have to ask (or consult the documentation if it exists). It’s going to be a per system thing – but it is anyway, since systems vary so much.

You can send an ORU message with an OBX segment with an RP data type in OBX-5 which is a reference to a PDF(or even an ED data type with the entire PDF in it). But whether systems can accept ORU messages like this, and whether they can correctly represent an RP/ED like this… again, that’s a question for each individual system.

Question: NEHTA CDA & GP referrals


Is there any example of NEHTA compliant CDA document that I can look at from a perspective of a GP referral form ( )? Is there a tool that can be used to navigate and generate the CDA from a HL7 v2 message?


There’s been a lot of discussion over the last decade or so about creating a CDA document for these kind of referral forms. I saw a pretty near complete set of functional requirements at one point. But for various reasons, the project to build this has got any funding, either as a NEHTA project, or a standards Australia project (it’s actually been on the IT-14-6-6 project list for a number of years, mostly with my name on it).

So right now, there’s no NEHTA compliant document. As a matter of fact, I don’t know of anything quite that like that from any of the national programs, though no doubt one of my readers will – please comment if you do. There is a project investigating this in the US National Program (S&I framework( but they’re not using CDA.

On the other part of the question, no, unfortunately not. NEHTA provides both C# and java libraries that implement the NEHTA described CDA documents, but it’s an exercise left to the implementer to convert from a v2 message to a CDA document. That’s primarily because there’s so much variability between v2 messages that there’s no safe way to write a single converter

I tried to do that with just AS 4700.2 messages, which are much more constrained than the general case, and it wasn’t really successful; the PITUS project is working on the fundamental alignment needed to get ti right in the future.