Health IT · XCodeFix Global
Clinics do not switch EMR because the charting is bad. They switch because patients cannot book online, reminders go out at the wrong time or not at all, referrals disappear into a fax machine, and nobody can say why.
So we did not build another EMR. We built the layer around one — and made it work with whatever system the clinic already has.
How it works
The separation is not architectural taste. It is what lets one product serve clinics on different systems, and what keeps our code on the right side of a licence boundary.
Unmodified. No patches, no dropped-in modules, no direct database writes. Pinned to a named release with a verified checksum, and replaced wholesale rather than edited.
Speaks to the EMR over its own APIs and translates to one canonical model. One adaptor per system; OpenEMR today, anything else tomorrow. Nothing above it knows the difference.
Reminders, referrals, messaging, booking. One database and one encryption key per clinic, so "delete everything you hold about us" is one operation rather than a careful sweep.
The part nobody else shows you
Every EMR exposes a different amount through its API. Most integrations discover the gaps by hitting them in production. We read them off the route tables and put them in the interface.
| Record | Read | Create | Update | What that means |
|---|---|---|---|---|
| Patients | yes | yes | yes | Full sync, both directions |
| Appointments | yes | yes | no | Bookable and cancellable. A reschedule is a cancel plus a new booking — the appointment gets a new reference |
| Practitioners | yes | yes | yes | Full sync |
| Encounters | yes | yes | yes | Visits link back to the record |
| Immunisations | yes | no | no | Read only — record them in the EMR |
| Lab results | yes | no | no | No write path exists in OpenEMR's API |
| Billing | no | no | no | No API at all, in either direction |
Derived from OpenEMR 8.2.0's own route tables: 71 FHIR routes of which 65 are reads, plus 96 routes on its proprietary API. Identical in 8.3.0. Re-derived automatically before any version change, so the table cannot quietly go out of date.
Each gap is also a contribution we intend to send upstream. When one lands, a flag flips in the adaptor and the product gains a feature without any product code changing.
Status
Cancel the visit and the reminder dies with it — within the minute, whether the cancellation came from the EMR, an HL7 feed or the front desk. Quiet hours are honoured in the clinic's own timezone, and a message that will not be sent is recorded with the reason rather than dropped.
A patient who texts STOP is opted out of every channel, not just the one they replied on, and the check runs again at the moment of sending — so a reminder scheduled two days ago never reaches someone who opted out yesterday.
Every entry carries the hash of the one before it, and database triggers refuse updates and deletes outright — against the application, against a migration, against a privileged session. Each clinic reads its own complete history, including every time our staff entered their workspace.
One database and one encryption key per clinic. Query helpers refuse to run at all without knowing whose data they are reading. The test suite provisions two real workspaces and tries to break across the boundary every way we could think of.
Remaining: the referral module, partner white-label, and a final hardening pass.
Try it
Separate on purpose. There is no column anywhere that turns a clinic's receptionist into an administrator of the platform.
The product. Reminders, the EMR connection, the audit log, emergency access.
Connections to EMRs, what each one will allow, and what has synced.
Stock OpenEMR 8.2.0, exactly as it ships. Book an appointment here and watch it appear in Essentials.