Laboratory Solutions

From requisition to reimbursement, one lab-first system.

EKLIS is a multi-tenant cloud LIS for US clinical laboratories: a LOINC-coded test compendium, barcode ordering and scanner-first accessioning, a server-enforced specimen and result state machine, an interface engine that speaks ASTM and HL7 to the analyzers, auto-verification gated on quality control, a documented critical-value loop, versioned report PDFs, provider and patient portals, and charges and claims generated the moment an order completes.

Overview

A cloud laboratory information system: order, accession, result, verify, release — and bill.

EKLIS is a laboratory information system built for the bench rather than adapted from a clinic chart. A laboratory signs up, gets its own MySQL database and a LOINC-coded starter compendium, and can run a real day's work without waiting on an implementation project: register a patient, build an order from the compendium, print barcode labels, collect, accession by scanner, enter or receive results, verify them, and hand back a report PDF. Every one of those steps is a server-enforced transition rather than a status field someone types over, and every access to patient data writes an append-only audit row attributed to the user who made it.

Two state machines carry the patient-safety weight. A specimen moves ordered → collected → accessioned → complete, with rejected as a terminal branch, and an out-of-order move is refused outright. A result moves preliminary → final, and a final result is never mutated: a correction inserts a new version linked to the one it supersedes, carrying the reason, and both stay visible — the report PDF prints a CORRECTED banner and names the version. Accessioning refuses to assign a number without an explicit confirmation that the operator matched two patient identifiers against the label, and critical values open a notification that closes only when someone records who was told and confirms the read-back.

The connectivity and money layers are the two places a lab-first system has to be different from a clinical one. The interface engine runs as its own process, so analyzer and HL7 traffic keeps flowing while the application deploys; it writes every inbound message to a durable per-tenant log before it processes anything, validates ASTM frame checksums, and treats all interface traffic as untrusted input that can only file into that tenant's own accessioned specimens and open order tests. On the other side, medical-necessity rules and the ABN prompt run at order time, and completing an order generates its charges and a draft claim in integer cents — export, denial, payment posting and denial analytics all sit on the same data model, so the laboratory never re-keys into a billing system what it already knows.

Laboratory Solutions — main screen
Laboratory Solutions — main screen (demo environment, synthetic data).
Architecture

The bench, the engine and the ledger

Bench surfaces
Worklist dashboard
STAT, to collect, to accession, to result, to verify, critical
Accession
one focused scan field, two-identifier confirmation
Results
split queues for entry and verification
Quality control
control lots, Levey-Jennings, auto-verify rules
Critical values
open loops awaiting read-back
Send-outs
worklist, in transit, courier manifest
Field collection
draw list, custody events, idempotent replay
Outside the bench
Provider portal
own orders only; anything else 404
Patient portal
read-only, final results and latest report
Report PDFs
versioned archive, CORRECTED labeling
Billing console
claims, denials, payments, analytics
Direct ordering
per-laboratory catalog, payment seam, portal code
Order and result core
Compendium
LOINC codes, sex-specific intervals, critical limits
Specimen state machine
ordered → collected → accessioned → complete; rejected terminal
Result state machine
preliminary → final; corrections add linked versions
Auto-verification rule sets
versioned data, gate reasons recorded
Billing engine
necessity, charges, claims, payments in integer cents
Interface engine (separate process)
ASTM listener
E1381 framing with checksum, E1394 records
HL7 MLLP listener
v2.5.1 result messages, ACK on every message
Durable message log
written before parsing, outcome written back
Per-interface code map
analyzer codes to compendium tests, LOINC fallback
Platform
FastAPI application
MySQL, one database per laboratory
grant scoped to the tenant prefix
Redis
rate limiting on sign-in and signup
Same-origin gateway
web and API on one origin, first-party session cookie
Append-only audit log
no payload column, by design
Operator console
tenant and interface registry only; key-gated, off by default
The interface engine is deliberately outside the application process, so analyzer and result traffic keeps being accepted and logged while the application is deployed; everything else reads and writes one laboratory's own database.
Who uses it

Built around the people doing the work

Accessioner

Needs · To get a tray of tubes onto the bench quickly without ever putting a number on the wrong patient's specimen.

Gets · A single focused barcode field that keeps the cursor, a confirm step that requires the two-identifier match before any number is assigned, sequential accession numbering with the receiving user recorded, and rejection with a reason as a proper terminal state.

Medical technologist

Needs · To see what is waiting, enter or review results, know why the system held something, and be able to correct a released result without erasing what was reported.

Gets · Split worklists for what needs entering and what needs verifying, automatic high/low/critical flagging against sex-specific intervals, the hold reason on every held result, and corrections that create a linked new version with its reason.

Laboratory administrator

Needs · To bring a new analyzer online, tune what may release itself, keep quality control honest, and answer an inspector about who did what.

Gets · The interface registry with per-interface code maps and a readable message log, the auto-verification rule editor with a rule-set version badge, control lots with Westgard evaluation and Levey-Jennings charts, staff and role management, and an append-only audit row on every patient-data access.

Ordering provider

Needs · To place an order, attach the diagnoses, and get the report back — without seeing anyone else's patients or being handed the bench.

Gets · Order entry through the same validated endpoint the laboratory uses, a portal scoped to their own orders, report PDFs for those orders, and a flat 404 on anything that is not theirs.

Patient

Needs · To read their own finished results without a phone call, and to be sure nobody else can read them by guessing a record number.

Gets · Sign-in with the laboratory identifier, record number, date of birth and a one-time code issued by the laboratory; a short-lived, patient-only session; current final results with flags and reference intervals; and the latest report PDF.

Billing specialist

Needs · To bill from what the laboratory actually did, to know why claims are being denied, and to stop preventable denials before the specimen is drawn.

Gets · Payers and a fee schedule in integer cents, medical-necessity rules that flag an ABN at order time, charges and a draft claim on order completion, export through the clearinghouse seam, a denial workflow with reasons, payment posting against the balance, and a dashboard of status, denial reasons, clean-claim rate and outstanding balance.

Today vs. with eKlotho

What actually changes

AreaTodayWith Laboratory Solutions
Getting startedA server in the closet, a vendor install, and a compendium built from scratch before the first order.Self-serve provisioning creates the laboratory, its own database, its schema and a LOINC-coded starter compendium — reviewed and adopted by the lab before go-live.
Analyzer connectivityA separate middleware box between the instruments and the LIS, with its own license, its own failure modes and its own vendor.The interface engine is part of the system: ASTM and HL7 listeners, a per-interface code map, and a message log the laboratory can read when an instrument goes quiet.
Deploying the softwareInstrument traffic is refused while the system restarts, and someone reruns the batch afterwards.The interface engine is its own process with a durable message log in front of every parser, so inbound messages are stored before they are parsed.
Releasing resultsAutoverification is a setting nobody can explain, or everything is released by hand.Five named gates in a fixed order, rules stored as data, a rule-set version stamped on every auto-released result, and a written hold reason on everything that did not pass.
Correcting a resultSomeone edits the value and the old number is gone.The correction is a new linked version with its reason; the report prints CORRECTED and names the version, and the superseded row stays on the record.
Critical valuesA phone call and a note in a logbook, if anyone remembers to write it.A notification that will not close without the name of the person notified and an explicit read-back confirmation, attributed and audited.
Getting paidResults are exported to a billing service that re-keys them, and denials arrive weeks later with no pattern anyone can see.Necessity checked at order time, charges and a draft claim generated on completion in integer cents, and a dashboard of status, denial reasons, clean-claim rate and balance from the same rows.
Capabilities

What's included

12 modules, each describing what is built today.

Multi-tenant foundation, roles and audit

Every laboratory gets its own database, its own staff, and an append-only record of who touched what — the base that everything else is built on.

Test compendium and requisition entry

The catalog the whole system reads from: LOINC-coded tests with specimen, container, units, sex-specific reference intervals and critical limits.

Collection, labels and accessioning

The scanner-first path from a printed label to an accession number, with the two-identifier check enforced by the server.

Mobile collection and chain of custody

The draw list a phlebotomist works from, and a custody trail that survives a phone with no signal.

Worklists and the bench dashboard

The lab's primary surface: how much work is waiting, where it is stuck, and what is urgent — computed, never typed.

Results, verification and corrections

Result entry with automatic flagging, a verification step that releases to the report, and corrections that add a version instead of overwriting one.

Interface engine — analyzers and HL7

Its own process, so instrument traffic keeps arriving while the application deploys, with a durable message log in front of every parser.

Auto-verification rules and quality control

Instrument results release themselves only when every gate passes, and quality control is the first gate — not a report someone files afterwards.

Critical values and reference-lab send-outs

The two paths a result takes when it cannot simply be printed: an urgent phone call that has to be documented, and a specimen that has to leave the building.

Reports, provider portal and patient portal

Three ways a finished result leaves the laboratory, each seeing exactly what it is allowed to see.

Billing and the revenue cycle

Charges and claims produced from the order the laboratory already ran, in integer cents, with the payer decisions made before the draw rather than after the denial.

Direct ordering and the operator console

Two surfaces outside the laboratory's own staff: a patient ordering for themselves, and the platform owner minding the tenant registry.

In depth

How it actually works

Tenancy · isolation at the data layer

One database per laboratory

Most multi-tenant software separates customers with a column and a `WHERE` clause, which means a single forgotten filter is a data breach. EKLIS separates laboratories with a database. Each tenant is a registered row in a small core database and a MySQL database of its own; the only way to get a connection is to ask the registry for one by slug, and the registry answers only for a laboratory that is registered and active. A slug that fails a strict pattern never reaches SQL at all.

Order → label → collect → accession

The bench loop, scanner in hand

An order is not a form the laboratory retypes into tubes. Choosing tests produces the specimens: the system groups the ordered tests by specimen type and container and creates one specimen per distinct pair, each with its own sequential identifier. That identifier is what gets printed, scanned and tracked, so the physical tube and the database row are the same object from the first moment.

Auto-verification and quality control

Five gates before a result releases itself

Auto-verification is where a LIS either earns its keep or quietly hurts someone, so the gates are explicit, ordered, and stored as data rather than buried in per-test code. A result filed by an analyzer is considered for release only if auto-verification is enabled for that test; then only if it is not critically flagged; then only if quality control for that test was in control within the last day; then only if the value sits inside the configured auto-verify range; and finally only if the delta against the patient's own prior final result is within the configured absolute and percentage limits.

The interface engine as its own process

No message is ever dropped

The one component that is not allowed to be part of the application is the interface engine. An analyzer does not know that a deploy is in progress; it opens a socket and sends. So the engine runs as its own process, reads the interface registry from the core database, and runs one TCP listener per enabled interface, starting and stopping listeners as the registry changes rather than requiring a restart to pick up a new instrument.

The revenue cycle on the same data model

From a completed order to a clean claim

The reason laboratory billing goes wrong is usually that it starts too late. By the time a claim is built in a separate system, the decisions that would have made it clean — was the patient covered, does the diagnosis support the test, did anyone get an ABN signed — are weeks in the past. EKLIS moves them to the order. Medical-necessity rules are ICD-10 prefixes attached to a test; when an order's diagnoses match no rule for a test that has them, the order is marked as requiring an ABN at the moment it is created, before anyone draws anything.

How it works

From first step to outcome

  1. Order placedTests chosen from the compendium, diagnoses validated, payer optional — specimens derived one per specimen type and container.
  2. Necessity and ABN check

    Each test's ICD-10 prefix rules are checked against the order's diagnoses; a test with rules and no match flags the order as needing an ABN.

  3. Labels and collection

    ZPL or PDF labels carry name, date of birth, record number, container and the specimen barcode; collection stamps the time.

  4. Accessioning

    The scan finds the specimen; what happens next depends on what the bench confirms.

    • Two identifiers confirmedleads to the next sequential accession number, receiver and time
    • Specimen unusableleads to rejected with a required reason — a terminal state
    • Never collectedleads to refused; the transition is not allowed
  5. Testing and result arrival

    An analyzer files through the interface engine, or a technologist enters by hand; either way the value is flagged against the sex-specific interval and the critical limits.

  6. Auto-verification gates

    Rule enabled, not critical, QC in control within the day, inside the auto-verify range, delta check against the patient's own prior result.

    • All gates passleads to final, with the rule-set version stored on the result
    • A gate holdsleads to preliminary with the reason, onto the human verify worklist
    • Critically flaggedleads to never auto-released; a notification opens
  7. Verification and report

    Verification makes the result final and immutable; corrections add a linked version with a reason. The report PDF is generated, versioned and archived.

  8. Order completion and billing

    When the last test is final the order and its specimens close, and charges plus a draft claim are generated once from the fee schedule.

  9. Delivered and billedreport PDF, provider portal and patient portal serve the current version; the claim exports through the clearinghouse seam unless a required ABN is unsigned
The two decision points are the ones that hurt when they are implicit: whether the specimen may be accessioned at all, and whether a result may release itself without a person.
  1. Order

    A provider or the front desk builds the order from the compendium; the system derives one specimen per specimen type and container, validates the diagnoses, and flags the order for an ABN when a test fails its medical-necessity rule.

  2. Label and collect

    Labels print as ZPL or PDF with the patient's name, date of birth, record number and a scannable specimen barcode; collection moves the specimen out of the ordered state and stamps the time.

  3. Accession

    The bench scans the barcode into a single focused field and confirms two patient identifiers against the label; only then is the next sequential accession number assigned, with the receiving user recorded. An unsuitable specimen is rejected with a reason instead.

  4. Result

    The analyzer files the result through the interface engine, or a technologist enters it by hand. Either way the value is flagged against the patient's sex-specific reference interval and the test's critical limits.

  5. Verify or auto-verify

    Instrument results pass the auto-verification gates — rule enabled, not critical, QC in control, within range, delta check — and record the rule-set version that released them; anything held lands on the human verify worklist.

  6. Release and report

    Verification makes the result final and immutable; a correction adds a linked version rather than overwriting. The report PDF is generated and archived, and the provider portal and patient portal serve the current version.

  7. Bill

    Completing the last test closes the order and generates its charges and a draft claim; export produces the clean-claim payload, denials carry a reason for re-work, and payments post against the balance.

A closer look

Screens and flows

Quality control and auto-verification
Quality control and auto-verification — control lots evaluated against Westgard multirules, beside the versioned auto-verify rule set (demo environment, synthetic data).
Critical values
Critical values — open loops, each waiting on the name of the person notified and a read-back confirmation (demo environment, synthetic data).
Claims and denial analytics
Claims and denial analytics — claims by status with clean-claim rate, open denials and outstanding balance (demo environment, synthetic data).
Reference

The specifics, in tables

Vocabularies, tiers and matrices drawn from the product documentation — the same terms the software uses.

Lab roles and what they unlock

RoleWhat it unlocks
AdminEverything, plus staff and role management, the interface registry and code maps, reference-lab setup and send-out flags
TechnologistResult entry, verification and corrections, quality control and auto-verification rules, critical-value acknowledgement, send-outs
AccessionerPatient registration, order entry, collection and accessioning, rejection, send-outs, patient portal access codes
PhlebotomistCollection and the bench worklists — never result entry or verification
ProviderOrder entry and a portal of their own orders, results and report PDFs; the bench surfaces are refused
BillingPayers, fee schedule, necessity rules, claims, export, denials, payments and billing analytics

Roles are checked deny-by-default on every endpoint, from the session token's claims.

What each state machine refuses

ObjectStatesWhat is refused
Specimenordered → collected → accessioned → complete, with rejected terminalAny out-of-order transition, and accessioning without the two-identifier confirmation
Resultpreliminary → final, corrections add a linked versionVerifying a result that is already final, a second entry against the same order test, and entry against a specimen that is not accessioned
Critical notificationopen → acknowledgedAcknowledgement without a read-back confirmation, and acknowledging a loop that is already closed
Claimdraft → exported → denied or paidExporting anything but a draft or denied claim, exporting with a required ABN unsigned, charges with no CPT code, and a payment larger than the balance
Custody eventcollected → picked up → received, append-onlyPicking up a specimen that was never collected, and applying the same field action twice — a replayed action returns the original outcome

Both are enforced server-side under a row lock, so a stale screen cannot talk the system into an illegal move.

The auto-verification gates, in order

GateWhat it checksHold reason recorded
Rule enabledAuto-verification is switched on for this testAuto-verification disabled
Not criticalThe value is not flagged critically high or lowCritical
QC in controlThe most recent control run for the test within the last day was in controlQuality control not in control
Auto-verify rangeThe value sits inside the configured range for the testAbove or below the auto-verify range
Delta checkThe change from the patient's own prior final result is within the absolute and percentage limitsDelta exceeded

The first gate that fails writes its reason onto the result and sends it to a person.

What the interface engine speaks

ProtocolWhat is acceptedWhat is answered
ASTM E1381 / E1394Framed records over TCP with the ENQ/ACK/EOT session handshake; results read from the order and result recordsACK per valid frame; NAK on a checksum failure, with nothing filed
HL7 v2.5.1 result messagesMLLP-wrapped messages; specimen identifier from the order segment, code and value from the observation segmentsAn accept acknowledgement when filed, an error acknowledgement when processing fails
Any other HL7 message typeLogged and recorded as ignoredA rejection acknowledgement naming it unsupported

Every inbound message is logged before it is parsed, and the outcome is written back onto the stored message.

How we make sure

The mechanics behind the claims

Every promise on this page maps to something the software actually enforces.

Laboratories cannot see each other's data
Isolation is at the data layer — one database per tenant, engines resolved only through the registry of active tenants, and the application's database grant scoped to the tenant prefix. Cross-tenant reads answer 404 and a token for an unregistered tenant is rejected; both are covered by the project's isolation tests.
A number is never assigned to the wrong patient's specimen
The accession endpoint takes an explicit identity-confirmation flag and refuses the request without it, and it will only accept a specimen already in the collected state — the label carries name, date of birth, record number and the barcode so there is something to match against.
A released result cannot be quietly changed
Result state transitions are enforced server-side under a row lock: a final result cannot be verified again, and a correction inserts a new row with an incremented version and its reason while linking the old row's superseded pointer to it. Both versions stay in the order's result history.
Quality control actually gates release
Auto-verification asks whether the most recent control run for that test within the last day was in control before it considers the value; a Westgard violation marks the run out of control, so the gate closes for that test until control is regained.
No inbound interface message is lost
The listener writes the raw message to the tenant's durable message log with a received status before parsing, then updates that row with the outcome. Processing exceptions are recorded on the message and caught, so a bad message never takes the listener down.
Interface traffic cannot file a result anywhere it likes
Ingest resolves the code through that interface's own code map or an exact compendium match, then requires a specimen belonging to the same tenant that is in the accessioned state and an order test that is still open. Anything else is rejected with the reason written to the message log.
A claim is not exported when an ABN is outstanding
Necessity rules mark the order at creation time, and the export endpoint refuses a claim whose order requires an ABN that has not been signed — the refusal names the missing ABN rather than exporting something that will be denied.
Outcomes

What changes for your team

  • A laboratory can be provisioned, staffed and running a real order the same day — its own database, its own compendium, no shared schema
  • Instrument traffic keeps arriving during a deploy, because the interface engine is a separate process with a durable log in front of it
  • Nothing releases itself past a quality-control failure, a critical flag or a delta the patient's own history does not support
  • A corrected result adds a version instead of erasing one, so what the clinician saw last week is still on the record
  • Every critical value carries the name of the person notified and a read-back confirmation, because the loop will not close without them
  • The claim is built from the order the laboratory already ran, so nobody re-keys results into a billing system
FAQ

Common questions

Terms on this page

LIS
Laboratory information system — the software that runs a laboratory's orders, specimens, results, quality control and reporting, as distinct from the clinic's EMR.
Compendium
The laboratory's test catalog: each test with its code, department, specimen type, container, units, reference intervals and critical limits.
LOINC
Logical Observation Identifiers Names and Codes — the standard vocabulary for identifying a laboratory test and its result; the starter compendium is LOINC-coded.
Accession
The laboratory's intake record for a received specimen — a sequential number assigned after the two-identifier check, with the receiving user and time.
ASTM E1381 / E1394
The low-level framing and the record format that bench analyzers use to speak to a LIS over a serial or TCP connection.
HL7 v2.5.1 and MLLP
The healthcare messaging standard and the minimal lower-layer protocol that wraps each message on a TCP socket; an ORU message carries results and is answered with an ACK.
Auto-verification
Releasing an instrument result without a human, but only when every configured gate passes; the rule-set version that released it is stored on the result.
Delta check
A comparison of a new result against the same patient's own prior final result for that test; too large a jump holds the result for a person to look at.
Westgard multirules
The control-run rules — 1-3s, 2-2s, R-4s, 4-1s and 10x — that decide whether a quality-control run is in control; a violation blocks auto-verification for that test.
Levey-Jennings
The chart of a control lot's results in standard deviations from its mean, which makes drift and shift visible before a rule fires.
Critical value
A result far enough outside the reference interval to need an immediate call; the notification closes only with the name of the person notified and a read-back confirmation.
Corrected report
A report reissued because a result was corrected; the new version supersedes the old one, which is retained and still linked rather than overwritten.
Send-out
A test the laboratory does not perform itself, routed to a reference laboratory with a courier manifest; the row closes when the result comes back and goes final.
ABN
Advance beneficiary notice — the form a patient signs when a test may not be covered; the system flags the order at ordering time and blocks claim export until it is signed.
Clean claim
A claim with everything a payer needs on it the first time — payer, subscriber, diagnoses and coded service lines — built here from the completed order rather than re-keyed.
How are laboratories kept apart from each other?

At the data layer. Each laboratory gets its own MySQL database, and a database engine is only ever resolved through the registry of registered, active tenants — the application's own database grant is scoped to the tenant prefix, so there is no query that could reach across. A cross-tenant read answers 404 rather than 403, and a token minted for a laboratory that is not registered is rejected before anything is read.

Can a result be edited after it is released?

No. A final result is immutable. A correction inserts a new version carrying its reason, links the superseded row to it, and leaves both visible in the order's history. The report PDF prints a CORRECTED banner and names the version next to the test, and the footer states that prior versions are retained by the laboratory.

What has to be true before an instrument result releases itself?

Five things, in order: auto-verification is enabled for that test, the result is not critically flagged, quality control for that test is in control within the last day, the value sits inside the configured auto-verify range, and the delta check against the patient's own prior final result passes. Any gate that fails holds the result as preliminary with the reason recorded, and it goes to a person.

What happens to a message if the parser fails?

It is already saved. Every inbound message is written to the laboratory's durable message log before anything is processed, so a parse or processing failure is recorded on the stored message rather than losing it, and the listener stays up. A corrupt ASTM frame is answered with a NAK and nothing is filed; an HL7 message that cannot be processed is answered with an error acknowledgement.

How is the right patient tied to the right tube?

The label carries the name, date of birth and record number alongside the specimen barcode, and accessioning will not assign a number unless the operator explicitly confirms the two-identifier match — the request is refused without it. A specimen that was never marked collected cannot be accessioned at all, and the receiving user and time are stored on the specimen.

Does the laboratory have to run its own connectivity middleware?

No — the interface engine is part of the system, but it runs as its own process rather than inside the application, precisely so analyzer and result traffic keeps being accepted while the application is being deployed. Listeners start and stop as the interface registry changes, and each interface belongs to the laboratory that created it.

How much can an ordering provider see?

Only their own orders. The order, its results and its report PDF all answer 404 for a provider who did not place it, and the bench surfaces — worklists, quality control, critical values — are refused for the provider role entirely.

How do patients get their results?

The laboratory issues a one-time access code, stored hashed and shown once, which it can rotate. The patient signs in with the laboratory identifier, record number, date of birth and that code, and receives a short-lived token of a distinct kind that only works on the read-only patient endpoints. They see current final results and the latest report — never preliminary or held ones — and sign-in failures are uniform and rate-limited so a record number cannot be probed.

Where does billing start?

At the order, not the invoice. Medical necessity is checked against per-test diagnosis rules while the order is being placed, and a failing order is flagged as needing an ABN there and then. Completing the order generates its charges and a draft claim once, in integer cents; export refuses to build a claim when a required ABN is unsigned.

Is real payer eligibility included?

The seam is, the connection is not. Eligibility sits behind an adapter, and without configured payer credentials it answers with an explicit, deterministic stub for demonstration and testing — it is never dressed up as a real payer response. The same is true of claim submission: the export builds and stores the structured clean-claim payload through the clearinghouse seam.

See Laboratory Solutions on your own workflows

We walk through it with your data and your team — not a canned demo.

Program and billing eligibility are determined by each practice and its payers. Results and alerts do not constitute a medical diagnosis. Third-party names are trademarks of their respective owners and do not imply endorsement.