Tuesday, 18 August 2026

Comparing HL7 messages in a browser

I had two ADT^A04 messages this week. Same EMR, same hospital, same patient. One registered Sam Brown without a fuss. The other got rejected. If you put them side by side in Notepad they looked the same until you got to the street.

Firstly, what does that actually mean?

The one that worked had this PID:

PID|1||74232^^^MRN||Brown^Sam||19780429|M|||19 High \T\ Main St^^Albany^NY^12207||555-555-2004

The one that failed had this:

PID|1||74232^^^MRN||Brown^Sam||19780429|M|||19 High & Main St^^Albany^NY^12207

The simple answer is that one of them escaped the ampersand in "High & Main", and the other one typed it in raw. But that raises the next question: isn't that just a different way of writing the same street?

No. In HL7, & is the subcomponent separator. You can see it declared right there in MSH-2 as part of ^~\&. It is not a letter in the address. It is punctuation that splits a field into smaller pieces.

So when the sending system wrote High & Main and left the & alone, the parser stopped treating Main as part of the street. Main, or the rest of that street, now sits in a different location than it does in the working message. The working one wrote \T\, which is the official escape for an ampersand. Same letters on the screen. Different place in the message.

To me it feels like an awkward leftover from the original delimiter design. I can picture a perfectly ordinary street sign, and some interface from the early '90s treating the & as structure. However, it is what it is...

But then the important question is how to deal with it?

Well, now that I do this in HL7 Soup, things have become simpler (yeah, like everything else). Open the message you already have. Then Tools, Compare.

The left pane is the current message. Paste the other one on the right. That is the usual job. I put the working ADT on the left and the rejected one on the right.



The list on the left is SEMANTIC DIFFERENCES. Each row has a path, a tag, and a short description.

The street is the interesting one. The working message kept High \T\ Main St as a single street value. The rejected one split it. PID-11.1.1 Street or Mailing Address is ONLY ON RIGHT, value 19 High. PID-11.1.2 Street Name is ONLY ON RIGHT, value Main St. Those paths do not exist on the left, because \T\ never created the subcomponents. Same street on the screen. Different place in the message. That is the row that explains the rejection.

Click PID-11.1.1. The top bar says Street or Mailing Address. Left: (not present). Right: 19 High. You stop saying "something in the PID" and start saying Main is sitting in a different location.



The other differences are real too. The working message has a home phone in PID-13, 555-555-2004. The failing one stops the PID after the address, so that field is only on one side. I would mention it on the vendor call. PID-12 is empty on the left and not present on the right. That is a real difference as well. Some systems treat empty and missing as the same thing. Some do not. MSH-10 is just the two control IDs, OK001 versus BAD001. None of that is why the second one failed. The ampersand is.

The right side is EDITABLE TEXT COMPARE. Side by side, both sides editable, the usual red and green. Useful when you want to stare at the raw PID line. I still start with the semantic list. That is the bit that understands HL7 paths instead of characters.

Why start there?

Because a text compare will happily tell you that & and \T\ are different characters, then leave you to work out what that does to every field after it. I have counted those pipes in Mirth exports more times than I want to admit. One extra delimiter and you are staring at the wrong slot. Click PID-11.1.1 and it tells you the street moved. You do not have to remember which number the street is, and you do not have to re-count after someone stuffed an extra caret into the name.

If you want to try the same two messages, here they are. Working first, then the one that failed.

MSH|^~\&|EMR|CITYHOSP|ADT|CITYHOSP|202608191000||ADT^A04^ADT_A01|OK001|P|2.5
EVN|A04|202608191000
PID|1||74232^^^MRN||Brown^Sam||19780429|M|||19 High \T\ Main St^^Albany^NY^12207||555-555-2004
PV1|1|O
MSH|^~\&|EMR|CITYHOSP|ADT|CITYHOSP|202608191000||ADT^A04^ADT_A01|BAD001|P|2.5
EVN|A04|202608191000
PID|1||74232^^^MRN||Brown^Sam||19780429|M|||19 High & Main St^^Albany^NY^12207
PV1|1|O

Anyway. Two messages, one works, one doesn't, and Compare points at the unescaped street ampersand. That is the whole trick.

Next time I will cover the little << and >> buttons on each difference. Those let you cherry-pick a field from one message into the other without counting a single pipe.

Monday, 10 August 2026

 

Comparing HL7 Integration Engines: 2026 Review

Updated July 2026

Last year I compared some of the main HL7 interface engines and ended up choosing HL7 Soup Integration Host. A lot has changed since then. Mirth has completed its move away from open source, iNTERFACEWARE has taken a rather unusual new direction, and HL7 Soup Integration Host has a new name: Integration Soup.

My own thinking has changed a little as well. I used to give code-led engines extra credit simply because anything could be coded. After spending more time inside some of our older Lua interfaces, I am less convinced that writing everything ourselves is an advantage. Modern graphical engines are far more capable than they used to be, and they can remove a lot of repeated logging, connection, security and error-handling code without limiting the business logic.

Integration EngineLicense & CostEase of UseStandards & ConnectivityScalability & Deployment2026 View
Integration Soup
Previously HL7 Soup Integration Host
Commercial subscription with workflow, site and enterprise options. Pricing is by quote. A 30-day trial is available.Very high. Visual workflows, drag-and-drop transformations and readable message views cover most ordinary work. C# remains available when code really is the clearest answer.HL7 v2, FHIR, JSON, XML, CSV and now DICOM. MLLP/TCP, HTTP/S, REST/SOAP, OAuth, files and broad database support. Extension libraries add cloud, SFTP, validation, document and encryption activities.On-premise or cloud deployment, with Windows and .NET Core builds. Azure and AWS extensions, Git-based workflow deployment and product, site and enterprise licensing options.Strengths: The easiest product here to understand quickly. Version 4.0 added useful depth without losing the simple workflow model. HL7 Soup Web is becoming an excellent browser companion, and the migration tooling is a real advantage.
Weaknesses: Smaller vendor and installed base than the enterprise incumbents. I would like to see more of the full Integration Soup experience move into the browser.
Infor CloverleafCommercial enterprise product with quote-based pricing.Medium. GUI tools and wizards are improving, but complex work can still require specialist Cloverleaf and TCL knowledge.HL7 v2, FHIR, CDA, X12 and broad legacy connectivity. Includes API gateway, FHIR and Da Vinci capabilities.Very high scalability and high availability. Available on-premise, in the cloud or as a hybrid deployment, including container options.Strengths: Proven at large healthcare organisations, broad standards support and strong operational reliability.
Weaknesses: Enterprise cost and complexity. It remains a product that benefits from experienced specialists rather than occasional interface developers.
iNTERFACEWARE Iguana / IguanaXCommercial. Published pricing starts at US$10,000 per year for two integrations, with larger packages by quote.Low to medium. IguanaX has a more visual component model, but Lua and code remain central to building and maintaining the interfaces.HL7 v2, FHIR, JSON, XML, REST, databases, files and other formats through components, libraries and custom Lua.Cross-platform deployment with cloud options. IguanaX development is active, with high availability and SSO identified as current areas of focus.Strengths: Fast, flexible and still extremely capable when you have strong developers and want complete control.
Weaknesses: My experience of the older codebase has exposed how much repeated plumbing the customer can end up owning. More importantly, the company now describes itself as being largely run by its founder. Whatever the theory behind that decision, it creates a support and business-continuity concern for a production interface engine.
Rhapsody CorepointCommercial enterprise pricing based on organisation size, deployment model and requirements.Very high. Its graphical, analyst-friendly approach remains one of the strongest in the market, and Rhapsody Axon now adds integrated AI assistance.HL7, FHIR, REST APIs and other healthcare formats, with reusable actions, testing, monitoring and alerting.Enterprise scale with high-availability options. Available as SaaS, on customer infrastructure or as an iPaaS deployment.Strengths: Excellent GUI, support and enterprise record. It was named Best in KLAS again in 2026 and is no longer fairly described as simply Windows-only.
Weaknesses: Premium pricing and a closed platform. It can be more product than a smaller integration team needs.
Mirth Connect by NextGen HealthcareMirth Connect 4.6 and later are commercial and proprietary. Version 4.5.2 remains available as the final open-source release but is no longer maintained by NextGen.Medium. The channel GUI is familiar to a very large community, but JavaScript or Java is still needed for a lot of real mapping and workflow logic.HL7 v2, X12, JSON, XML, REST, SOAP, DICOM and commercial FHIR capabilities.Cross-platform and cloud-agnostic, with commercial clustering, security extensions and central monitoring through Mirth Command Center.Strengths: Huge installed base, a great deal of existing knowledge and very flexible scripting. The commercial product continues to be developed and supported.
Weaknesses: The maintained free edition is gone. The dated development experience and amount of scripting are harder to excuse once commercial licensing is part of the decision.
Qvera Interface Engine (QIE)Commercial with flexible subscription licensing and pricing based on requirements.High. A browser-based visual channel editor handles the main workflow, with JavaScript available for more complex requirements. Qvera now also promotes an AI Companion for help, mapping and troubleshooting.HL7 v2, FHIR, CDA, X12, DICOM, ASTM, databases, JSON, XML and web services.Cloud-optimised and container-friendly, with AWS, Azure and Google Cloud deployment and orchestration options.Strengths: Modern web interface, strong standards coverage, credible cloud deployment and a good reputation for support. It remains one of the strongest alternatives in this list.
Weaknesses: Smaller market share than the major enterprise platforms, quote-based pricing and some scripting for complex work.

So... what do I choose in 2026?

The answer is still Integration Soup, although I think I have better reasons for choosing it this year.

In the past I tended to see a code-first engine as the more powerful option. If everything is code, then surely nothing is out of reach. The problem is that you also take responsibility for everything you code. Looking through our existing Iguana libraries, a surprising amount of the Lua is there to manage connections, logging, errors, security and cleanup. It is important work, but it is also repeated work, and every copy becomes another place for a mistake or an old security decision to survive.

Modern graphical engines do not have the same limitations that put people off them years ago. A good workflow designer can handle the normal integration work while still allowing code where it is genuinely useful. That leaves the developer concentrating on mappings, transformations and the rules that are actually different for that interface.

Integration Soup 4.0 has moved a long way in that direction. It now has broader database support, DICOM, Azure and AWS extensions, stronger source-control deployment and tools for converting existing channels. The rename from HL7 Soup Integration Host also makes sense: this is now much more than an HL7 utility with an engine attached.

I particularly like what is happening in the browser. HL7 Soup Web is already a very good way to inspect, understand and share a message, and Integration Soup is beginning to take over from there when that message needs to become a real workflow. I would definitely like to see more of the Integration Soup experience move into the browser, but the direction looks right.

Corepoint and Qvera remain very credible alternatives, and Cloverleaf is still difficult to argue with at true enterprise scale. For the sort of work I actually want to build and maintain, though, Integration Soup gives me the best balance: a proper interface engine, a modern GUI, code when I need it, and far less code that I have to own simply to keep an interface safe and running.

Tuesday, 4 August 2026

I’ve just found a very handy feature in HL7 Soup Online for sharing an HL7 message with someone else.

Right-click on any message in the list and select Copy message as link. This puts a hyperlink onto your clipboard which you can then paste into an email, support ticket or chat message.

Right-click on your message and select Copy message as Link

When the other person clicks the link, the exact message opens for them in HL7 Soup Online. They can see the readable description of the message, click through the fields, and find out what the values mean without having to install anything.

Take a look at this link to see it in action.

This is particularly useful when the person you are sending it to doesn’t work with HL7 every day. Pasting the raw message into an email normally gives them a block of text full of pipes and carets. Sending the link lets them see that it is a patient registration, which details are for the patient, what sort of visit it is, and where each value sits in the message.

I can see this being useful when asking a software vendor about a particular field, adding an example to a support ticket, or explaining a message to someone who understands the workflow but not necessarily HL7.

There is one important thing to remember. The message is included in the link, so you should treat that link in exactly the same way as you would treat the original message. Don’t copy a live message containing patient information and send it as it is.

HL7 Soup Online has an Anonymize menu at the top of the screen. If you are starting with a real message, anonymize it before creating the link. I would still have a quick look through the result afterwards to make sure that any local identifiers or unusual fields have also been dealt with. If possible, a synthetic test message is always the safest one to share.

That’s really all there is to it. Right-click the message, copy the link and send it. The recipient gets the actual message in a tool that helps them understand it, rather than having to work it out from the raw HL7 themselves.

Monday, 3 August 2026

Moving an Iguana Database Interface

Take a fairly normal Iguana interface that receives a message and writes some of it to a database.

The useful part is quite small. Read a few values from the message, convert them into the format the database expects, and insert or update the record.

But that isn’t all the Lua we ended up with.

We also need to open the database connection, make sure it is still available, handle the error if it isn’t, log enough information to work out what happened, and make sure everything is closed properly afterwards. If the interface needs to retry, that needs to be dealt with as well.

None of this is unusual code. In fact, that is really the point. It is code for exactly the same problems that every database interface has.

I have been looking at this while starting to move our Iguana channels to Integration Soup. When I create the database step there, the connection and the normal failure handling belong to the engine. I configure what I want to do and concentrate on the values I want to write.

The result is that most of the old Lua doesn’t need to be converted at all. It wasn’t business logic. It was just everything we had written around the business logic to make it safe to run.

I must admit, the large Lua libraries had always made the interfaces feel quite powerful. If we needed something, we could code it. That is still useful, but it also meant we took responsibility for a lot of things that would probably have been better handled by the integration engine.

It also makes later changes harder than they need to be. We have some old TCP interfaces where TLS now needs to be added. With our own implementations, each one has to be checked and updated. In Integration Soup it is a connection setting, so the same tested implementation is used throughout.

There will still be places where I use code. Some mappings and unusual rules are simply easier that way. But I would much rather use code for the bit that makes an interface different, and let the engine look after the bits that are the same every time.

That is probably the biggest improvement I have seen from the conversion so far. I’m not losing the useful code. I’m finding out how much of the other code I no longer need.