FHIR-Gateway

FHIR-Gateway

Version

Page Info

Last update

Page Info

Classification

public

Responsible

Product Management

Summary

The samedi FHIR-Gateway is an on-premises client application that synchronizes appointments, patients, forms, and availability data between the samedi platform and hospital FHIR servers, supporting bidirectional synchronization according to ISiK standards.

The samedi FHIR-Gateway supports:

  • Availability Management (Slots), synchronizing free appointment slots from the FHIR server to the samedi platform for appointment booking

  • Terminplanung (Appointment Scheduling) according to ISiK Stufe 2/3 from the perspective of a FHIR Requestor, including bidirectional synchronization of appointments between the samedi platform and FHIR server

  • Patient Management, including finding or creating patients in the FHIR server, synchronizing patient data between platform and FHIR, and maintaining patient identifier mappings

  • Form Types Synchronization, converting and sending samedi form types to the FHIR server as Questionnaires

  • Forms Synchronization, converting and sending completed forms from the samedi platform to the FHIR server as QuestionnaireResponses

  • Change Detection, supporting webhook and websocket subscriptions to detect and synchronize appointment changes from the FHIR server back to samedi platform

Implementation modes: The FHIR-Gateway supports three integration modes, each tailored to different hospital information systems: iMedOne, CGM Medico, and ISHMed. The implementation and configuration vary depending on the selected mode.

Availability Management

FHIR-Gateway synchronizes appointment availability from the FHIR server to the samedi platform. For each appointment type with a configured FHIR service type code reference, the gateway queries the FHIR server for Slot resources using the service type code and date. It extracts slots with status "free" and sends the available times to the samedi platform. The synchronization runs periodically, processing slots for each day from the current date up to 6 months in the future. This keeps the platform's availability data current, so patients see accurate available appointment times when booking online.

Referencing service type code in platform appointment type settings

Appointment type reference can be set in the appointment type settings:

Screenshot from 2025-12-09 16-43-49.png

Requesting time slots from FHIR server

For all referenced appointment types FHIR-Gateway will request available slots from the FHIR server.

Example request for CGM Medio mode:

GET {BASE_URL}/Slot?service-type=allgemeine-sprechstunde&start=2024-01-15

Example request for iMedOne mode:

GET {BASE_URL}/Slot?service-type=allgemeine-sprechstunde&start=ge2024-01-15T00:00:00Z&_count=100

Example request for ISHMed mode:

GET {BASE_URL}/Slot?schedule=schedule-123&service-type=allgemeine-sprechstunde&start=2024-01-15

Displaying available times for online appointment booking

As a result of synchronization a patient sees available time slots for the corresponding appointment type on their booking form on patient portal:

Screenshot from 2025-12-09 16-48-32.png

Appointment Booking

General Process:

When an appointment is created, updated or cancelled online or on the samedi platform, the fhirgateway synchronizes the change to the FHIR server:

  1. Patient Handling: The gateway decrypts the patient data, finds or creates the patient in the FHIR server, and updates the patient identifiers on the platform with the FHIR patient ID. FHIR patient id is visible on the patient dashboard:

    Screenshot from 2025-12-09 17-20-35.png
  2. Slot Finding: The gateway searches for an available Slot resource matching the appointment type (service type code) and requested time.

  3. Appointment Creation: The gateway creates a FHIR Appointment resource referencing the found slot and calls the Appointment/$book operation to book the appointment on the FHIR server.

  4. Reference Update: After successful booking, the gateway updates the platform with the FHIR appointment ID (xref) to link the platform appointment with the FHIR appointment.

  5. Error Handling: If booking fails (e.g., slot no longer available, FHIR server error), the gateway cancels the appointment on the samedi platform to keep the systems in sync.

Mode-Specific Differences

Medico

  • Searches for slots using service type code and date (start=YYYY-MM-DD)

  • Retrieves the Schedule resource to obtain the HealthcareService reference

  • Includes the HealthcareService as a participant in the appointment

  • Includes ServiceType in the appointment resource

  • For rescheduling: If an existing appointment has a different start time, includes the old appointment ID in the cancelled-appt-id parameter of the booking operation

iMedOne

  • Searches for slots using service type code with exact timestamp match (start=eq2024-01-15T10:00:00Z)

  • Includes ServiceType in the appointment resource

  • Only includes the Patient as a participant

  • For rescheduling: Cancels the old appointment first, then creates a new one

ISHMed

  • Searches for slots across multiple configured Schedule IDs for the appointment type

  • Uses service type code and schedule ID in the slot search with exact timestamp match (schedule=schedule-123&service-type=INJEKT&start=eq2024-01-15T10:00:00Z)

  • Only includes the Patient as a participant

  • For rescheduling: Cancels the old appointment first, then creates a new one

All modes use the ISiK $book operation endpoint: POST /Appointment/$book with a Parameters resource containing the appointment to be booked.

Patient Management

Patient data is handled for now only as part of appointment booking. When an appointment is created or updated, the gateway finds or creates the patient in the FHIR server before booking the appointment. The patient can be searched by id or an identifier:

GET {BASE_URL}/Patient/{id}
GET {BASE_URL}/Patient?identifier={system}|{value}

Patient Fields Sent to FHIR Server:

When creating a new patient, the gateway sends the following fields from the samedi platform patient to the FHIR Patient resource:

  • Name: given name (first name), family name (last name), prefix (title)

  • Identifier: samedi patient ID (system: http://samedi.de/fhir/CodeSystem/patient-id, value: samedi patient ID)

  • Gender: administrative gender (male, female, other, unknown)

  • Birth Date

  • Address: street, city, postal code, country

Note: Contact information (phone, mobile, email, fax) is not sent to the FHIR server during appointment handling.

Appointment Synchronization from FHIR Server to Platform

The fhirgateway synchronizes appointment changes from the FHIR server to the samedi platform. The implementation differs by mode.

General Process (for all modes)

When an appointment is created, updated, or cancelled in the FHIR server, the FHIR-Gateway:

  1. Detects the change via polling the GET /Appointment?_lastUpdated=ge{timestamp} endpoint or webhook, or websocket request (mode-dependent)

  2. Checks the service type code of the appointment. If it is one of those that are set as a reference for samedi appointment types, it proceeds with handling the appointment. If it’s not one of those, the change is ignored.

  3. Extracts the patient ID from the appointment participants, retrieves the full Patient resource from the FHIR server and encrypts the patient data with customer’s public key, to send it to platform.

  4. Sends the appointment data to the platform: appointment start time, appointment type reference, and encrypted patient information.

Mode-Specific Differences

Medico

  • Change Detection: Polling using GET {{BASE_URL}}/Appointment?_lastUpdated=ge{timestamp} query, with optional WebSocket subscription for real-time updates

  • Polling Frequency: Configurable sync interval (default: 30 seconds)

  • State Management: Tracks the last processed timestamp and appointment IDs to avoid duplicate processing

iMedOne

  • Change Detection: Webhook only

  • Webhook Endpoint: Receives HTTP POST requests with FHIR Bundle containing appointment changes

  • Real-time: Processes changes immediately when webhook is received

ISHMed

  • Change Detection: Webhook only

  • Webhook Endpoint: Receives HTTP POST requests with FHIR Bundle containing appointment changes

  • Real-time: Processes changes immediately when webhook is received

Resource Interactions

Appointment Updates Polling

GET {base-url}/Appointment/_history?_since={timestamp}

Example:

GET <https://fhir-server.example/fhir/Appointment/_history?_since=2024-08-04T07:19:23.209+00:00>

Questionnaire & QuestionnaireResponse

Questionnaire

Questionnaire Search

GET {base-url}/Questionnaire?identifier={system}|{value}

Example:

GET <https://fhir-server.example/fhir/Questionnaire?identifier=https%3A%2F%2Fsamedi.de%2Ffhir%2Fforms|unique-form-id>

Questionnaire Creation

POST {base-url}/Questionnaire Content-Type: application/fhir+json

Example:

POST <https://fhir-server.example/fhir/Questionnaire> Content-Type: application/fhir+json { "resourceType": "Questionnaire", "identifier": [{ "system": "<https://samedi.de/fhir/forms>", "value": "unique-form-id" }], "name": "ANAMNESIS", "title": "Anamnesis", "status": "active", "date": "2024-08-29T08:21:57+02:00", "description": "", "item": [ { "linkId": "1", "text": "Do you have any allergies?", "type": "boolean" } ], }

QuestionnaireResponse

When handling form submissions, our gateway performs the following steps:

  1. Finds or creates the Patient resource based on the form data

  2. Creates or finds the corresponding Questionnaire resource

  3. Creates or updates the QuestionnaireResponse

Finds or creates the Patient resource based on the form data

Patient Search

GET {base-url}/Patient/{id}

Example:

GET <https://fhir-server.example/fhir/Patient/123>

Patient Creation

Example:

POST <https://fhir-server.example/fhir/Patient> Content-Type: application/fhir+json { "resourceType": "Patient", "meta": { "profile": [ "<https://gematik.de/fhir/isik/v3/Basismodul/StructureDefinition/ISiKPatient>" ] }, "identifier": [{ "type": { "coding": [{ "system": "<https://terminology.hl7.org/CodeSystem/v2-0203>", "code": "MR" }] }, "system": "<https://fhir.krankenhaus.example/NamingSystem/PID>", "value": "TestPID" }], "name": [{ "use": "official", "family": "Fürstin von Musterfrau", "given": ["Erika"] }], "active": true, "gender": "female", "birthDate": "1964-08-12" }

Creates or finds the corresponding Questionnaire resource

Questionnaire Search

See above

Questionnaire Creation

See above

Creates or updates the QuestionnaireResponse

The gateway implements an intelligent update mechanism for QuestionnaireResponses:

  1. It first searches for an existing QuestionnaireResponse using the identifier

  2. If no existing response is found, it creates a new one

  3. If an existing response is found:

    • The gateway compares the content (items/answers) of both responses

    • Only updates the response if the content has changed

    • Uses PUT request with the existing resource ID for updates

QuestionnaireResponse Search

GET {base-url}/QuestionnaireResponse?identifier={system}|{value}

Example:

GET <https://fhir-server.example/fhir/QuestionnaireResponse?identifier=https%3A%2F%2Fsamedi.de%2Ffhir%2Fforms|unique-form-id>

QuestionnaireResponse Creation

Example:

POST <https://fhir-server.example/fhir/QuestionnaireResponse> Content-Type: application/fhir+json { "resourceType": "QuestionnaireResponse", "identifier": { "system": "<https://samedi.de/fhir/forms>", "value": "unique-form-id" }, "questionnaire": "Questionnaire/123", "status": "completed", "subject": { "reference": "Patient/456" }, "authored": "2024-03-14T15:30:00Z", "item": [ { "linkId": "1", "text": "Do you have any allergies?", "answer": [ { "valueBoolean": false } ] } ] }

QuestionnaireResponse Updates

Example:

PUT <https://fhir-server.example/fhir/QuestionnaireResponse/123> Content-Type: application/fhir+json { "resourceType": "QuestionnaireResponse", "identifier": { "system": "<https://samedi.de/fhir/forms>", "value": "unique-form-id" }, "questionnaire": "Questionnaire/123", "status": "completed", "subject": { "reference": "Patient/456" }, "authored": "2024-03-14T15:30:00Z", "item": [ { "linkId": "1", "text": "Do you have any allergies?", "answer": [ { "valueBoolean": false } ] }, { "linkId": "2", "text": "When was your last medical checkup?", "type": "date" }, ] }

Integration Setup

Prerequisites

  • A FHIR server implementing ISiK Terminbuchung Stufe 2

  • Support for Patient, Schedule, Slot, Appointment, and HealthcareService resources

  • Valid endpoint URL for the FHIR server

  • Authentication credentials (if required)

  • A defined way to receive appointment updates from the FHIR system to the samedi platform, such as supported Appointment search by _lastUpdated parameter: Appointment?_lastUpdated=ge{timestamp}, Webhook or WebSocket subscriptions.

Download FHIR-Gateway

Download FHIR-Gateway for your system from here: https://github.com/samedi/fhirgateway/releases

For Windows download MSI installer package

For Linux/macOS download the binary archive (.tgz)

Installation

Windows

Run the MSI installer and follow the installation wizard

Linux/macOS

  • Extract the binary archive to your desired location (e.g., /opt/fhirgateway or ~/fhirgateway)

  • Make the binary executable: chmod +x fhirgateway

  • Create a systemd service file (Linux) or launchd plist (macOS) to run it as a service, or run it manually

Configuration

Configuration should be stored in the format toml. By default the configuration file is expected to be present in the same directory as the executable and be named fhirgateway.toml, but the executable can also take it as a parameter, and then the name or the location of the file can be different.

The installer will provide fhirgateway.example.toml with an example configuration that can be used as a starting point to configure the integration.

The configuration file is divided onto main sections:

  • [samedi] - samedi platform gateway API connection settings

  • [fhir] - FHIR server connection settings and FHIR-resources-related settings

[samedi] section

This section is common and independent of the system mode. It contains settings that apply to samedi platform side of the integration.

token

Authentication token for the samedi gateway API. Used to authenticate all API requests to the samedi platform. Obtain this from the samedi support

  • Required: Yes

  • Example: token = "abc123xyz789"

endpoint

Base URL of the samedi gateway API endpoint. Override only if using a custom endpoint (e.g., staging). For production, the default is correct.

  • Required: No

  • Default: https://app.samedi.de

  • Example: endpoint = "https://staging.samedi.de"

state_file

Path to the file where synchronization state is persisted. Stores last processed timestamps and processed appointment IDs to resume after restarts and avoid repeated processing. Use an absolute path or a path relative to the working directory. Ensure the gateway has write permissions.

  • Required: No

  • Default: fhirgateway-state.json

  • Example: state_file = "state.json"

sync_interval_seconds

Interval in seconds between synchronization cycles for polling operations. Controls how often the gateway polls the samedi platform for changes (appointments, forms, form types). Lower values increase responsiveness but also API load. Higher values reduce load but increase latency.

  • Required: No

  • Default: 30

  • Example: sync_interval_seconds = 60

request_timeout_seconds

HTTP request timeout in seconds for API calls to the samedi platform. Maximum time to wait for a response from the samedi API. Increase for slow networks or large payloads. If exceeded, the request fails and may be retried.

  • Required: No

  • Default: 30

  • Example: request_timeout_seconds = 60

sync_forms

Enable or disable synchronization of forms (QuestionnaireResponses) from the platform to the FHIR server. When enabled, completed forms are converted to FHIR QuestionnaireResponse resources and sent to the FHIR server. Disable if you don't need form synchronization.

  • Required: No

  • Default: true

  • Example: sync_forms = false

sync_form_types

Enable or disable synchronization of form types (Questionnaires) from the platform to the FHIR server. When enabled, form type definitions are converted to FHIR Questionnaire resources and sent to the FHIR server. Disable if you don't need form type synchronization.

  • Required: No

  • Default: true

  • Example: sync_form_types = false

sync_appointments

Enable or disable synchronization of appointments from the platform to the FHIR server. When enabled, appointment changes (create, update, cancel) are synchronized from the samedi platform to the FHIR server. This is the core appointment booking functionality. Disable only if you only need unidirectional sync (FHIR to platform).

  • Required: No

  • Default: true

  • Example: sync_appointments = true

[fhir] section

These settings belong to the FHIR side of the integration. They might depend on the system mode, because different system modes might support their mode-specific settings.

base_url

Base URL of the FHIR server. Must end with. Used as a base URL for all FHIR API requests.

  • Required: Yes

  • Example: base_url = "https://fhir.example.com/fhir/"

system_mode

Integration mode. Determines adapter behavior and required configuration. Supported values: "medico", "imedone", "ishmed".

  • Required: Yes

  • Example: system_mode = "medico"

token

Authentication token for the FHIR server. Used as a Bearer token in the Authorization header. Required if the FHIR server uses token-based authentication. Cannot be used together with OAuth authentication methods.

  • Required: No (required if no OAuth is configured)

  • Default: None

  • Example: token = "your-fhir-server-token"

insecure_ssl_verify_none

Disable SSL certificate verification for the FHIR server. Set to true only for self-signed certificates or testing environment. Not recommended for production.

  • Required: No

  • Default: false

  • Example: insecure_ssl_verify_none = true

request_timeout_seconds

HTTP request timeout in seconds for FHIR server API calls. Maximum time to wait for a response. Increase for slow networks or large payloads.

  • Required: No

  • Default: 30

  • Example: request_timeout_seconds = 60

sync_interval_seconds

Interval in seconds between synchronization cycles for FHIR server polling operations. Used for regulating frequency of change detection polling (medico mode). Lower values increase responsiveness but also server load.

  • Required: No

  • Default: 30

  • Example: sync_interval_seconds = 60

system_namespace

System namespace identifier for the FHIR server. Used as the system identifier when creating patient identifiers and referencing resources. If not specified, defaults to the base_url value.

  • Required: No

  • Default: Value of base_url

  • Example: system_namespace = "https://fhir.example.com"

max_concurrent_requests

Maximum number of concurrent HTTP requests to the FHIR server. Limits parallelism to avoid overloading the server. Set based on server capacity and network conditions.

  • Required: No

  • Default: No limit (0 means unlimited)

  • Example: max_concurrent_requests = 10

sync_slots

Enable or disable synchronization of appointment slots (availabilities) from the FHIR server to the samedi platform. When enabled, the gateway periodically queries Slot resources and updates platform availability data.

  • Required: No

  • Default: true

  • Example: sync_slots = false

[fhir.auth.oauth] section

Generic OAuth 2.0 authentication configuration for FHIR servers. Use this instead of the token setting when the FHIR server requires OAuth authentication. Used by iMedOne mode and can also be used by medico mode if you prefer to specify scopes explicitly. Cannot be used together with other authentication methods.

endpoint

OAuth token endpoint URL for obtaining access tokens.

  • Required: Yes

  • Example: endpoint = "https://fhir.example.com/fhir/auth/token"

client_id

OAuth client ID for authentication.

  • Required: Yes (if using OAuth auth)

  • Example: client_id = "oauth-client-id"

client_secret

OAuth client secret for authentication.

  • Required: Yes (if using OAuth auth)

  • Example: client_secret = "your-secret-key"

scopes

List of OAuth scopes to request. If not specified, defaults to the required scopes for Medico integration.

  • Required: No

  • Default: system/Patient.read, system/Patient.write, system/Appointment.read, system/Appointment.write, system/HealthcareService.read, system/Schedule.read, system/Slot.read, system/Subscription.read, system/Subscription.write

  • Example: scopes = ["system/Patient.read", "system/Appointment.read"]

[fhir.ishmed.mappings] section

Configuration section specific for ISHMed. It contains appointment type mappings. It maps platform appointment type references to FHIR service type codes and schedule IDs.

Example:

[fhir.ishmed.mappings] [fhir.ishmed.mappings.appointment_type.INJEKT-DERM] service_type = "INJEKT" schedules = ["DRIESCHA-000645", "DRIESCHA-000632"] [fhir.ishmed.mappings.appointment_type.INJEKT-PED] service_type = "INJEKT" schedules = ["KRIEVKA-000645", "KRIEVKA-000632"]

[fhir.resources.change_detection] section

Change detection enables synchronization of appointments from the FHIR server to the samedi platform. Currently only Appointment resource can be synchronized. Patients will be also sent to platform, but only together with the appointment changes.

mode

Change detection mode. Determines how the gateway detects appointment changes in the FHIR server. Supported values: "query_polling" (poll Appointment resource using _lastUpdated), "subscription" (real-time via webhook or websocket), "none" (disabled).

  • Required: No

  • Default: "none" (sync disabled)

  • Example: mode = "query_polling"

channel_type

Channel type for subscription mode. Only used when mode = "subscription". Supported values: "webhook" (HTTP POST notifications), "websocket" (WebSocket connection).

  • Required: Yes (if mode = "subscription")

  • Default: None

  • Example: channel_type = "webhook"

endpoint

WebSocket endpoint URL (e.g., wss://fhir.example.com/websocket) to connect to for real-time notifications.

  • Required: Yes (if mode = "subscription")

  • Example: endpoint = "wss://fhir.example.com/websocket"

listen_address

Address and port where the gateway listens for incoming webhook notifications. Required for webhook subscriptions. Format: "host:port" or just "port" (listens on all interfaces). The gateway starts an HTTP server on this address to receive webhook POST requests.

  • Required: Yes (if channel_type = "webhook")

  • Default: None

  • Example: listen_address = "localhost:8080" or listen_address = "8080"