Skip to main content

HL7 Configuration

The HL7 configuration is a standard configuration object managed via the Configuration API. Within this framework, it is identified by its configuration type and consumed by the HL7 worker.

This document describes the structure and behavior of HL7 configurations and how they are used to transform incoming HL7 messages into FHIR resources at runtime.

Configuration Model Overview

An HL7 configuration is identified by a combination of tenant, and metadata. The transformation logic is defined declaratively in the content field.

FieldDescription
TypeIdentifies the configuration domain. HL7 configurations use: hl7.
ScopeIdentifies the configuration scope. Can be one of: global, organization, ward, role, or user.
NameIdentifies the configuration name. This name is not required when resolving configurations.
TenantIdIdentifies the tenant (e.g., hospital or system) that this configuration belongs to. This field is mandatory and ensures proper routing and isolation. The fallback tenantId in the HL7 worker is mona-default.
MetaA flexible JSON object used for message-level matching. The HL7 worker reads the event type from the incoming message and selects the appropriate configuration based on these metadata filters.
contentContains the ordered list of operations executed by the HL7 worker. Operations define how HL7 data is transformed into FHIR resources.
{
"meta": {
"hl7_event": "ORU^R01"
},
"type": "hl7"
"scope": "global",
"name": "ORU^R01^DEV"
"tenantId": "mona-default",
"content": {...}
}

content

FieldRequiredDescription
operationstrueOrdered list of transformation operations executed by the HL7 worker. Determines how HL7 data becomes FHIR resources.
hl7FieldTypeMapfalseOverrides / extends the default HL7 field-path → HL7-type lookup. Keys use normalized segment paths (e.g. PID-7, OBX-5). Useful when a device reports non-standard HL7 types.
hl7TypeMappingfalseMaps HL7 types (e.g. NM, TS, ST) to internal target type keys such as valueInteger, valueDateTime, or valueString. Controls which FHIR value[x] wrapper is used.
obxTypeMappingfalseMaps OBX-2 value types to the FHIR value[x] path (may include sub-fields). Merges with and overrides built-in defaults. Used for redirecting the final leaf value into the correct FHIR structure.
For more information about the mapping options and how they work read: Dynamic Type Detection

Example:

 "hl7FieldTypeMap": {
"PID-7": "TS"
},
"hl7TypeMapping": {
"TS": "valueDateTime"
},
"obxTypeMapping": {
"NM": "valueQuantity.value",
"TX": "valueString"
},
"operations": [
{
"type": "upsertResource",
"options": {
"search": "identifier={{PID-3-1}}",
"fhirType": "Patient",
"createMapping": {
"gender": "{{PID-8|hl7Gender}}",
"name[0]": "{{PID-5}}",
"birthDate": "{{PID-7}}"
},
"updateMapping": {
"gender": "{{PID-8|hl7Gender}}",
"name[0].family": "{{PID-5-1}}",
"name[0].given[0]": "{{PID-5-2}}",
"address[0].city": "{{PID-11-3}}",
"address[0].country": "{{PID-11-5}}",
"address[0].line[0]": "{{PID-11-1}}",
"address[0].postalCode": "{{PID-11-4}}",
"birthDate": "{{PID-7|hl7DateTime}}"
}
},
"storeAs": "patient"
....
},
{
"type": "createResource",
"options": {
"mapping": {
"status": "final",
"effectiveDateTime": "{{OBX-14}}",
"subject.reference": "Patient/%patient.id%",
"valueQuantity.code": "{{OBX-6-1}}",
"valueQuantity.unit": "{{OBX-6-2}}",
"code.coding[0].code": "%observationTranslations.code%",
"encounter.reference": "Encounter/%encounter.id%",
"valueQuantity.value": "{{OBX-5}}",
"valueQuantity.system": "http://unitsofmeasure.org",
"code.coding[0].system": "%observationTranslations.system%",
"code.coding[0].display": "%observationTranslations.display%"
},
"fhirType": "Observation"
},
"hl7Segment": {
"hl7Type": "OBX",
"iterate": true
},
"isCritical": false
}
]

Operation Model

HL7 transformations are defined as a sequence of operations. Operations are executed sequentially from top to bottom.

Each operation performs a specific task such as:

  • creating a resource
  • updating a resource
  • loading an existing resource
  • performing an upsert operation
export interface Operation {
type: OperationType;
options: OperationOptions;
storeAs?: string;
isCritical?: boolean;
hl7Segment?: {
hl7Type?: string;
iterate?: boolean;
};
}

Type

Defines the action executed by the HL7 worker. Current supported values:

createResource
updateResource
loadResource
upsertResource
translate

Each operation type has specific option requirements. See operation-handlers for more information for each handler and examples.

Options

Operations define their configuration using the options object.

export interface OperationOptions {
fhirType: string;
mapping: MappingConfig;
createMapping: MappingConfig;
updateMapping: MappingConfig;
search: string;


// translate options
conceptMap?: string;
system?: string;
code?: string;
display?: string;
onNoMatch?: 'passthrough' | 'drop';
}

Not every option is required for every operation. See details in the operation-handlers section.


FhirType

Specifies the FHIR resource type. Examples: Patient, Encounter, Observation.


Mapping/CreateMapping/UpdateMapping

Defines the transformation from HL7 fields to FHIR fields.

"createMapping": {
"gender": "{{PID-8|hl7Gender}}",
"name[0]": "{{PID-5}}",
"birthDate": "{{PID-7}}",
"address[0]": "{{PID-11}}",
"identifier[0].value": "{{PID-3-1}}",
"identifier[0].system": "HOSPITAL"
},

FHIR search query used to locate existing resources. Example:

 { "search": "identifier={{PID-3-1}}" }

StoreAs (optional)

Stores the resulting resource in the execution context so it can be reused by later operations.

storeAs: "patient"

Later usage:

Patient/%patient.id%

This behaves like a runtime variable shared between operations.

IsCritical (optional)

Controls error handling behavior.

ValueBehavior
trueProcessing stops if the operation fails
falseProcessing continues

This allows distinguishing between mandatory and optional operations. If not set, processing will continue after errors.

hl7Segment (optional)

Defines the HL7 segment or group that should trigger the operation.

{
"hl7Segment": {
"hl7Type": "OBX",
"iterate": true
}
}
FieldDescription
hl7TypeHL7 segment type (e.g. PID, PV1, OBX)
iterateExecute the operation for every occurrence

If iterate is true, the worker processes all matching segments.

Operation Handler

loadResource

Loads an existing resource using a FHIR search query. Required options:

  • fhirType
  • search
{
"type": "loadResource",
"storeAs": "patient",
"options": {
"fhirType": "Patient",
"search": "identifier={{PID-3-1}}"
}
}

createResource

Creates a new FHIR resource. Required options:

  • fhirType
  • mapping

Example:

{
"type": "createResource",
"storeAs": "patient",
"options": {
"fhirType": "Patient",
"mapping": {
"identifier[0].value": "{{PID-3-1}}",
"gender": "{{PID-8|hl7Gender}}",
"birthDate": "{{PID-7|hl7Date}}"
}
}
}

updateResource

Updates an existing FHIR resource. Typically used after a loadResource operation because it uses a context id. If you want to search and update for a resource in one step use the upsert resource handler.

  • fhirType
  • mapping

Example:

{
"type": "updateResource",
"storeAs": "patient"
"options": {
"fhirType": "Patient",
"mapping": {
"address[0].city": "{{PID-11-3}}"
}
}
}

UpsertResource

Performs a conditional create or update.

Execution logic:

  1. Execute search
  2. If resource exists → update using updateMapping
  3. If no resource exists → create using createMapping

Required options:

  • fhirType
  • search
  • createMapping
  • updateMapping

Example:

{
"type": "upsertResource",
"storeAs": "patient",
"options": {
"fhirType": "Patient",
"search": "identifier={{PID-3-1}}",
"createMapping": {
"identifier[0].value": "{{PID-3-1}}",
"gender": "{{PID-8|hl7Gender}}"
},
"updateMapping": {
"gender": "{{PID-8|hl7Gender}}"
}
}
}

Translate

Translates a local code to a target code system using a FHIR ConceptMap ($translate operation).

Execution logic

  • Extract the source code from the HL7 message
  • (Optional) Perform batch translation for all segments (performance optimization)
  • Call FHIR $translate
  • Evaluate response: If result = true → use translated code. If result = false → apply fallback strategy
  • Store the result in the context under the configured alias (storeAs)

Subsequent mapping steps can access the translated values

Result structure:

context[storeAs] = [
{ code: "...", system: "...", display: "..." },
{ code: "...", system: "...", display: "..." }
]

Required Options

  • conceptMap – URL or ID of the ConceptMap
  • system – source code system
  • code – HL7 field path (e.g. OBX-3-1)

Optional Options

  • display – HL7 field used as fallback display (e.g. OBX-3-2)
  • onNoMatch – behavior if no translation is found: "passthrough" (default) → use original code "drop" → skip this value

Batch processing (Performance Optimization)

If hl7Segment.iterate = true, the engine automatically:

  • collects all codes across segments (e.g. all OBX)
  • executes translations in batch internally
  • caches results in context.translateCache

This avoids repeated FHIR calls for identical codes.

Iteration behavior

When iterate is enabled: The operation runs once per segment (e.g. per OBX). Each result is stored at the corresponding index and can be accessed afterwards in the mapper.

Example:

            {
"type": "translate",
"options": {
"conceptMap": "http://franzi.test/fhir/ConceptMap/local-lab-to-loinc",
"system": "http://franzi.test/codes/local-lab",
"code": "OBX-3-1",
"display": "OBX-3-2"
},
"storeAs": "observationTranslations",
"hl7Segment": {
"hl7Type": "OBX",
"iterate": true
}
},

Execution Semantics

Operations are processed sequentially.

Important rules:

  • Later operations may reference previously stored resources
  • Template expressions are resolved at runtime
  • Failures respect the isCritical setting

Mapping Expressions

Mappings define how HL7 data is transformed into FHIR fields.

{
"gender": "{{PID-8|hl7Gender}}",
"status": "in-progress",
"subject.reference": "Patient/%patient.id%"
}
Expression TypeExampleResult
HL7 field{{PID-3-1}}'45678'
transformer{{ PID-8|hl7Gender }}'male'
static valuefinal'final'
stored variable"Patient/%patient.id%"'fd081de3-c151-49c5-98aa-09856ce379d1'

Custom HL7 Transformers

Transformers convert HL7 values into valid FHIR values.

Usage

{{PID-8|hl7Gender}}

The full list with some examples and explanations can be found here: HL7 Value Transformer

Examples

Example with multiple operations

    {
"content": {
"operations": [
{
"type": "createResource",
"options": {
"mapping": {
"gender": "{{PID-8|hl7Gender}}",
"name[0].family": "{{PID-5-1}}",
"name[0].given[0]": "{{PID-5-2}}",
"identifier[0].value": "{{PID-3-1}}",
"identifier[0].system": "{{PID-3-5}}"
},
"fhirType": "Patient"
},
"storeAs": "%patient%",
"isCritical": true
},
{
"type": "createResource",
"options": {
"mapping": {
"status": "in-progress",
"class.code": "{{PV1-2|hl7PatientClass}}",
"class.system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
"period.start": "{{PV1-44|hl7DateTime}}",
"subject.reference": "Patient/%patient.id%",
"identifier[0].value": "{{PV1-19-1}}",
"identifier[0].system": "{{PV1-19-4}}"
},
"fhirType": "Encounter"
},
"storeAs": "%encounter%",
"isCritical": false
}
]
},
"meta": {
"hl7_event": "ADT^A01"
},
"id": "85e50210-c27c-4eb0-94fc-267ecc557350",
"name": "ADT^A01^Default",
"scope": "global",
"scopeId": null,
"tenantId": "mona-default",
"type": "hl7",
"createdAt": "2026-03-10T10:53:12.458Z",
"createdBy": null,
"updatedAt": "2026-03-10T10:53:12.458Z",
"updatedBy": null,
"deletedAt": null,
"deletedBy": null,
"version": 1
},

In this example:

  • First a Patient resource is created
  • HL7 fields are mapped declaratively to FHIR elements
  • The resulting resource is stored as %patient%
  • Processing stops if this operation fails
  • Second an Encounter resource is created with the reference to the new created patient in the first step

Example with iterate

    {
"content": {
"operations": [
{
"type": "loadResource",
"options": {
"search": "identifier={{PID-3-1}}",
"fhirType": "Patient"
},
"storeAs": "patient"
"isCritical": true
},
{
"type": "loadResource",
"options": {
"search": "identifier={{PV1-19}}",
"fhirType": "Encounter"
},
"storeAs": "encounter"
"isCritical": true
},
{
"type": "createResource",
"options": {
"hl7Type": "OBX",
"mapping": {
"status": "final",
"effectiveDateTime": "{{now}}",
"subject.reference": "Patient/%patient%.id",
"valueQuantity.code": "{{OBX-6-1}}",
"valueQuantity.unit": "{{OBX-6-2}}",
"code.coding[0].code": "{{OBX-3-1}}",
"encounter.reference": "Encounter/%encounter%.id",
"valueQuantity.value": "{{OBX-5|toNumber}}",
"valueQuantity.system": "http://unitsofmeasure.org",
"code.coding[0].system": "http://loinc.org",
"code.coding[0].display": "{{OBX-3-2}}"
},
"fhirType": "Observation",
"createEach": true
},
"segment": {
"hl7Type": "OBX",
"iterate": true
},
"isCritical": false
}
]
},
"meta": {
"hl7_event": "ORU^R01"
},
"id": "fd081de3-c151-49c5-98aa-09856ce379d1",
"name": "ORU^R01^Default",
"scope": "global",
"scopeId": null,
"tenantId": "mona-default",
"type": "hl7",
"createdAt": "2026-03-10T10:54:35.176Z",
"createdBy": null,
"updatedAt": "2026-03-10T10:56:54.144Z",
"updatedBy": null,
"deletedAt": null,
"deletedBy": null,
"version": 2
}

In this example:

  • The patient must be loaded
  • The encounter must be loaded
  • For every OBX Segment an observation will stored. With the loaded patientId and the encounterId