Leitfaden
Dieser Leitfaden beschreibt den praktischen Integrationsablauf für Drittanbieter gegen die T2med FHIR-API.
Version des zugrunde liegenden Integrationsleitfadens: 1.2 · Stand: 2026-10-29
| Version | Stand | Änderung |
|---|---|---|
| 1.0 | 2026-06-15 | Aktueller Stand des Integrationsleitfadens |
| 1.1 | 2026-10-28 | Ergänzt: Kontext per API anlegen (POST /Encounter, ab Version 26.10) und lesender Zugriff auf die eAkte ($eakte, ab Version 26.11). Interne Verweise korrigiert. |
| 1.2 | 2026-10-29 | Abgleich mit APS 26.11: einheitliche Schreibweise der Pfade, Profil-, Extension- und Identifier-URLs; Diagnose-Relevanz korrekt als Extension dokumentiert. |
Zielbild und Grundprinzip
Die Integration ist kontextbasiert:
- Die Drittanbieter-Software wird durch Nutzerinteraktion aus dem APS-Client heraus per Deep Link aufgerufen. Dafür wird im APS ein temporärer Kontext erstellt.
- Der Drittanbieter ruft die FHIR-API mit
X-API-Keyauf. - Der Drittanbieter übergibt die
kontextIdals FHIR-Identifier oder alsEncounter-Referenz in kontextgebundenen Ressourcen. - APS ordnet die Daten dem Kontext zu und schreibt sie in die Fachdomäne.
| Thema | Vorgabe |
|---|---|
| Kontext-Identifier | system=https://fhir.t2med.de/identifier/kontext, value=<kontextId> |
| Encounter-Referenz | Encounter/<kontextId> |
| Kontextdauer | Kontexte werden bis zu 4 Stunden vorgehalten und stündlich bereinigt. |
| Kontextpflicht | Kontextgebundene create-Operationen und GET /Patient?identifier=... benötigen einen gültigen Kontext. |
Neben diesem klassischen Deep-Link-Pfad gibt es einen zweiten Einstieg über den OAuth Device Flow, wenn der Drittanbieter-Client ohne vorherigen Deep-Link-Aufruf ein Access-Token benötigt.
Voraussetzungen
Serverseitig (APS)
| Voraussetzung | Wert |
|---|---|
| FHIR-Servlet | unter /aps/fhir/api/r4 erreichbar |
| Drittanbieter | in APS aktiviert |
Drittanbieter-seitig
| Voraussetzung | Erwartung |
|---|---|
| FHIR-Client | HTTPS-Client für FHIR R4 |
| Lokale HTTPS-Endpunkte | lokale APS-Server-URLs werden unterstützt |
| Lokale Zertifikate | installationsspezifische APS-Server-Zertifikate werden unterstützt |
| Pflichtheader serverseitig | X-API-Key |
| Optionale Serverheader | X-TreatWarningAsError, X-FHIR-Profile |
| Optionale Client-Header | Authorization, Prefer, X-TreatWarningAsError, Content-Type |
| Deep-Link-Parameter | kontextId, FHIRBasisUrl, oAuthToken |
| OAuth Client ID | aus der APS-Drittanbieter-Definition (ClientId) |
| OAuth Scope | aktuell in APS festgelegt: t2med/aps/FHIR |
| Fehlerformat | OperationOutcome auswerten |
Authentifizierung und Header
Serverseitig zwingend:
| Header | Pflicht | Bedeutung |
|---|---|---|
X-API-Key: <API_KEY> | ja | API-Key des aktivierten Drittanbieters. |
Optionale, üblicherweise zusätzlich gesendete Header:
| Header | Pflicht aus Serversicht | Bedeutung |
|---|---|---|
Authorization: Bearer <oAuthToken> | nein | Wird aus dem Deep-Link-Parameter oAuthToken (bzw. dem per Device Flow erhaltenen Access-Token) gebildet. |
Prefer: return=OperationOutcome | nein | Signalisiert, dass ein OperationOutcome als Create-Ergebnis erwartet wird. |
X-TreatWarningAsError: true | nein | Warnungen werden als Fehler behandelt. |
Content-Type: application/fhir+xml; charset=UTF-8 | nein | Setzt das Anfrageformat. Für JSON application/fhir+json verwenden. |
Optionale FHIR-API-Header:
| Header | Verhalten |
|---|---|
X-TreatWarningAsError: true|false | fehlt oder true ⇒ Warnungen werden als Fehler behandelt; false ⇒ Warnungen bleiben Warnungen. |
X-FHIR-Profile: <profil-url>|1.0.0 | wird nur für Patient-Read und Patient-Search ausgewertet; ohne Header wird FhirApiPatient verwendet. |
Accept: application/fhir+json | sinnvoll für JSON-Antworten. |
Wichtig
loginToken: wird von/aps/rest/FHIR/api/kontext/anlegengeliefert, wenn das aktivierte Produkt eineclientIdhat.oAuthToken: Parametername im Deep Link; enthält dasloginTokenaus der Kontext-Boundary.- Leerer Token: Wenn kein
loginTokenerzeugt wird, ersetzt der APS-Client${oAuthToken}durch einen leeren Wert. FHIRBasisUrl: Muss unverändert als Basis-URL des FHIR-Clients verwendet werden.
Typische Fehler bei der Authentifizierung:
| HTTP | Bedeutung |
|---|---|
403 Forbidden | API-Key fehlt oder ist ungültig. |
503 Service Unavailable | FHIR-API ist per Feature-Flag nicht freigeschaltet. |
Hinweise aus der Kontext-Anlage:
| Fall | Verhalten |
|---|---|
| Unbekanntes Produkt | Kontext-Anlage liefert Validierungsfehler. |
| Nicht aktiviertes Produkt | Kontext-Anlage liefert Validierungsfehler. |
| Aktiviertes Produkt ohne Auth-Registrierung | Kontext wird angelegt, loginToken bleibt leer, es wird ein Info-Hinweis zurückgegeben. |
OAuth Device Flow (RFC 8628)
Neben dem klassischen Deep-Link-Start mit fertigem Bearer-Token kann sich ein Drittanbieter auch eigenständig per OAuth 2.0 Device Flow am APS-Auth-Server authentifizieren. Dieser Pfad ist relevant, wenn der Drittanbieter-Client ohne vorherigen Deep-Link-Aufruf aus dem APS-Client heraus ein Access-Token benötigt.
Ablauf
Drittanbieter-Client Auth-Server Browser (Nutzer)
| | |
|-- POST /device_authorization ----->| |
| Authorization: Basic | |
|<-- device_code, user_code, -------| |
| verification_uri_complete, | |
| expires_in, interval | |
| | |
| zeigt user_code + URI -------------------------------------------------->| Nutzer öffnet URI
| |<-- Nutzer gibt user_code ein ---------|
| | |
|-- POST /token (polling) --------->| |
| Authorization: Basic, | |
| grant_type=device_code | |
|<-- authorization_pending ---------| |
| (warten, erneut pollen) | |
|-- POST /token (polling) --------->| |
|<-- access_token, token_type ------| |
| | |
| FHIR-Client initialisiert | |
Konfigurationsparameter
| Parameter | Beschreibung |
|---|---|
deviceAuthUrl | URL des Device Authorization Endpoint des APS-Auth-Servers. Standard: gleicher Host wie FHIRBasisUrl, Port 16596, Pfad /oauth2/device_authorization. |
tokenUrl | URL des Token Endpoint. Standard: gleicher Host wie FHIRBasisUrl, Port 16596, Pfad /oauth2/token. |
clientId | OAuth Client ID aus der APS-Drittanbieter-Definition (ClientId). |
clientSecret | Client-Secret aus der APS-Drittanbieter-Einrichtung. |
scope | OAuth Scope — aktuell in APS festgelegt: t2med/aps/FHIR. |
Das Client-Secret wird im APS-Einrichtungsprozess für den Drittanbieter-Zugriff bereitgestellt. Der Drittanbieter-Client muss es vertraulich behandeln: nicht protokollieren und nur in einem sicheren Schlüsselspeicher vorhalten (siehe Sicherheit, Betrieb und Go-Live).
Client-Secret gehört in den Header, nicht in den Body
Die Client-Authentifizierung erfolgt bei allen Aufrufen (device_authorization, Token-Polling und Refresh) über den Header Authorization: Basic base64(client_id:client_secret). Das Client-Secret gehört nicht in den Request-Body — dieser enthält nur client_id und scope (bzw. beim Token-Aufruf grant_type und device_code). Wird das Secret im Body mitgesendet, lehnt der Auth-Server den Aufruf mit {"error":"invalid_client"} ab.
Polling-Verhalten
| Server-Antwort | Bedeutung | Empfohlenes Verhalten des Clients |
|---|---|---|
200 OK mit access_token | Autorisierung erfolgreich | Access-Token übernehmen und FHIR-Client initialisieren |
authorization_pending | Nutzer hat noch nicht autorisiert | Warten, erneut pollen |
slow_down | Polling zu häufig | Polling-Intervall um mindestens 5 Sekunden erhöhen |
expired_token | Device Code abgelaufen | Fehler anzeigen, Device Flow neu starten |
access_denied | Nutzer hat abgelehnt | Fehler anzeigen |
Ergebnis nach erfolgreichem Device Flow
Nach erfolgreichem Token-Erhalt kann der Client die FHIR-API mit dem erhaltenen Access-Token (Authorization: Bearer <access_token>) identisch zum klassischen Deep-Link-Pfad nutzen. Alle FHIR-Operationen stehen unverändert zur Verfügung.
Optional: Automatische Wiederverbindung per Refresh-Token
Liefert der Token-Endpoint einen refresh_token, kann ein Drittanbieter-Client diesen nutzen, um nach einem Neustart ohne erneute Browser-Autorisierung ein neues Access-Token zu beziehen (grant_type=refresh_token, Authorization: Basic aus Client ID und Client-Secret). Das Access-Token selbst ist kurzlebig und sollte nicht dauerhaft gespeichert werden. Ist der Refresh-Token abgelaufen oder ungültig, muss der Device Flow erneut durchlaufen werden.
Sicherheitshinweis
Wenn der Client Refresh-Token und Client-Secret für eine spätere Wiederverbindung vorhält, gehören diese Geheimnisse in einen sicheren Schlüsselspeicher (z. B. OS-Keychain), nicht in eine Klartext-Datei.
Minimalfluss (Variante B)
POST <deviceAuthUrl>mit HeaderAuthorization: Basic base64(client_id:client_secret); im Body (Form-Encoded) nurclient_idundscope.device_code,user_code,verification_uri_complete(Fallback:verification_uri),expires_inundintervalaus der Response lesen.user_codeundverification_uri_completedem Nutzer anzeigen.- Polling:
POST <tokenUrl>mit demselbenAuthorization: Basic-Header; im Bodygrant_type=urn:ietf:params:oauth:grant-type:device_code,device_codeundclient_id— alleintervalSekunden. - Bei
authorization_pending: warten und erneut pollen. Beislow_down: Intervall um 5 Sekunden erhöhen. - Bei
200 OKmitaccess_token: Token übernehmen, FHIR-Client wie im Deep-Link-Pfad initialisieren. - Ab hier identisch zum Deep-Link-Pfad: FHIR-Operationen mit
Authorization: Bearer <access_token>ausführen.
Eine lauffähige Referenzimplementierung dieses Flows (inklusive Persistenz und automatischer Wiederverbindung) zeigt die Demo-Anwendung.
Endpunkte und Integrationsablauf
Endpunktübersicht (Drittanbietersicht)
Externe FHIR-API:
| Thema | Wert |
|---|---|
| Basis | /aps/fhir/api/r4 |
| Format in Beispielen | FHIR JSON |
| Unterstützte Content-Types | application/fhir+json, application/fhir+xml |
Ressourcen:
| HTTP | Pfad | Unterstützte Operation |
|---|---|---|
POST | /Patient | Patient anlegen |
GET | /Patient?identifier=<system>|<value> | Patient per Kontext-Identifier suchen |
GET | /Patient?family=...&given=...&birthdate=... | Patient per Name/Geburtsdatum suchen |
GET | /Patient/{id} | Patient lesen |
PUT | /Patient/{id} | Patient aktualisieren |
GET | /Patient/{id}/$eakte | eAkte des Patienten lesen, optional eingegrenzt auf einen Zeitraum (ab 26.11), siehe eAkte lesen |
POST | /Patient/{id}/$eakte | wie GET, Parameter im Body als Parameters-Ressource (ab 26.11) |
GET | /Encounter/{id} | Encounter aus Kontext lesen |
POST | /Encounter | Kontext anlegen (Device Flow, ab 26.10), siehe Kontext per API anlegen |
GET | /Organization/{id} | Organisation lesen |
GET | /Organization?name=...&identifier=... | Organisation nach Name/BSNR suchen |
GET | /Organization?practitioner=... | Organisationen zu Practitioner suchen |
GET | /Practitioner/{id} | Practitioner lesen |
GET | /Practitioner?name=...&identifier=... | Practitioner nach Name/LANR suchen |
GET | /Organization/{id}/Practitioner | Implementierungsnaher Compartment-Sonderfall — siehe Hinweis unten |
POST | /Observation | Observation anlegen |
POST | /Condition | Diagnose anlegen |
POST | /Procedure | Therapie oder Prozedere anlegen |
POST | /DocumentReference | Freitext oder Anhang anlegen |
GET | /DocumentReference/{id} | Referenz auf ein Dokument oder Bild aus der eAkte lesen (ab 26.11) |
POST | / | FHIR-Transaction-Bundle |
Sonderfall GET /Organization/{id}/Practitioner
Der Endpoint ist registriert, der aktuelle Handler interpretiert {id} aber als Practitioner-/Arztrollen-ID und gibt Organization-Ressourcen zurück. Für Drittanbieter ist GET /Organization?practitioner=<id> die fachlich klarere Variante.
Kontext-Management und Drittanbieter-Freischaltung erfolgen APS-intern unter /aps/rest/FHIR/api/... und sind nicht Teil der externen Drittanbieter-API.
Empfohlener Integrationsablauf (End-to-End)
Schritt 1: Kontext bereitstellen lassen
| Schritt | Beschreibung |
|---|---|
| Kontextanlage | APS ruft intern /aps/rest/FHIR/api/kontext/anlegen auf. |
| Pflichtfelder | hersteller, produkt, patientId, arztrolleId, behandlungsortId |
| Optionales Feld | behandlungsfallId |
| Response | kontext, aufrufUrlTemplate, FHIRApiBase, abhängig vom Produkt loginToken |
| Deep Link | APS-Client ersetzt ${kontextId}, ${FHIRBasisUrl}, ${oAuthToken} im aufrufUrlTemplate. |
oAuthToken | Der APS-Client befüllt den Parameter aus dem loginToken. |
FHIRBasisUrl | Zusammengesetzt aus APS-Basis-URL und FHIRApiBase; unverändert im Drittanbieter-Client verwenden. |
Beispiel für ein Template:
t2demo://?kontextId=${kontextId}&FHIRBasisUrl=${FHIRBasisUrl}&oAuthToken=${oAuthToken}
Schritt 2: Optional Patient laden oder validieren
| Zweck | Request |
|---|---|
| Kontextvalidierung | GET /aps/fhir/api/r4/Patient?identifier=https://fhir.t2med.de/identifier/kontext|<KONTEXT_ID> |
| Header-Profil | X-FHIR-Profile: https://fhir.t2med.de/StructureDefinition/FhirApiPatient|1.0.0 |
Schritt 3: Fachdaten schreiben
Je nach Anwendungsfall:
| Ressource | Anwendungsfall |
|---|---|
Observation | Anamnese, Befund oder Freitext |
Condition | Diagnosen |
Procedure | Therapie oder Prozedere |
DocumentReference | Freitext oder eingebetteter Anhang/Datei-Upload |
Patient | Patient anlegen oder aktualisieren |
Für kontextgebundene Ressourcen gilt:
| Variante | FHIR-Element |
|---|---|
| Kontext-Identifier | identifier.system = https://fhir.t2med.de/identifier/kontext, identifier.value = <KONTEXT_ID> |
| Encounter-Referenz | encounter.reference = Encounter/<KONTEXT_ID> |
| Profil | meta.profile[0] muss ein unterstütztes Profil enthalten |
Für eine enthaltene Encounter-Ressource gelten diese Referenz-Prefixe:
| Kontextbestandteil | Referenz |
|---|---|
| Patient | Patient/<patientObjectId> |
| Behandlungsfall | EpisodeOfCare/<behandlungsfallObjectId> |
| Arztrolle | Practitioner/<arztrolleObjectId> |
| Behandlungsort | aktueller Implementierungsstand: Organisation/<behandlungsortObjectId> |
Für DocumentReference mit Profil FhirApiDocumentReferenceAnhang|1.0.0 gilt zusätzlich:
| Element | Vorgabe |
|---|---|
description | Pflicht |
content[0].attachment.data | Pflicht, Base64-kodierter Anhang |
content[0].attachment.contentType | Pflicht |
content[0].attachment.title | optional |
| Zeitpunkt | bevorzugt content[0].attachment.creation, ersatzweise DocumentReference.date |
| Kürzel | optional über https://fhir.t2med.de/StructureDefinition/FhirApiAnhangKuerzel |
Schritt 4: Optional als Transaction bündeln
| Thema | Vorgabe |
|---|---|
| Endpoint | POST /aps/fhir/api/r4 |
| Bundle | Bundle.type = transaction |
| Entry-Methode | nur request.method = POST implementiert |
| Entry-URL | relative Resource-Namen wie Observation oder Condition |
| Rollback | Bei error oder fatal in einem Entry-OperationOutcome wird die Gesamttransaktion auf Rollback markiert. |
Schritt 5: Kontextabschluss
| Schritt | Beschreibung |
|---|---|
| Entfernen | Kontext kann über /aps/rest/FHIR/api/kontext/entfernen entfernt werden. |
| Wiederverwendung | Kontext-IDs nicht wiederverwenden. |
Schnellstart (Minimalfluss, Deep-Link-Pfad)
- Deep Link auswerten und
kontextId,FHIRBasisUrl,oAuthTokenübernehmen. - HTTPS-Client für
FHIRBasisUrlmit passender SSL-Konfiguration initialisieren. X-API-Keybei jedem FHIR-Aufruf mitsenden.- Optional
Authorization: Bearer <oAuthToken>,Prefer: return=OperationOutcomeundX-TreatWarningAsError: truemitsenden. GET /Patient?identifier=https://fhir.t2med.de/identifier/kontext|<KONTEXT_ID>ausführen.- Gewünschte Ressource mit gültigem
meta.profileund Kontext-Identifier oder Encounter-Referenz anlegen. OperationOutcomeund HTTP-Status auswerten.- Kontext bei Bedarf entfernen und nicht wiederverwenden.
Für den Device-Flow-Minimalfluss siehe OAuth Device Flow.
Kontext per API anlegen
Beim klassischen Deep-Link-Start legt der T2med-Client den Kontext an und übergibt ihn an die Drittanbieter-Anwendung. Beim OAuth Device Flow gibt es keinen Deep Link. Hier legt die Drittanbieter-Anwendung den Kontext selbst an, per POST /Encounter (ab Version 26.10). Damit ist innerhalb einer Sitzung auch ein Patientenwechsel möglich: Patient suchen oder anlegen, Kontext anlegen, in die eAkte schreiben.
| Element im Encounter | Referenz | Pflicht |
|---|---|---|
subject | Patient/<patientId> | ja |
participant.individual | Practitioner/<arztrolleId> | ja |
serviceProvider | Organization/<behandlungsortId> | ja |
episodeOfCare | EpisodeOfCare/<behandlungsfallId> | nein |
| Thema | Vorgabe |
|---|---|
| Profil | meta.profile[0] = https://fhir.t2med.de/StructureDefinition/FhirApiEncounter|1.0.0 |
| Patient-ID | aus der Patientensuche oder -anlage |
| Arztrolle-ID | aus der Practitioner-Suche |
| Behandlungsort-ID | aus der Organization-Suche, z. B. GET /Organization?practitioner=<arztrolleId> |
| Antwort | 201 Created; die Kontext-ID steht im Header Location (.../Encounter/<kontextId>/_history/0) |
| Fehler | 400, wenn subject, participant oder serviceProvider fehlt; 422, wenn die Verarbeitung fehlschlägt |
| Weiterverwendung | Die kontextId wird wie im Deep-Link-Pfad als Kontext-Identifier oder Encounter-Referenz verwendet. Kontexte werden bis zu 4 Stunden vorgehalten. |
Ein vollständiges Beispiel steht in der API-Referenz.
eAkte lesen
Ab Version 26.11 kann die eAkte eines Patienten gelesen werden, etwa um die Historie in einer KI-Anwendung zu nutzen. Der Zugriff erfolgt über die Operation $eakte am Patienten.
| Thema | Vorgabe |
|---|---|
| Aufruf | GET /Patient/{id}/$eakte oder POST /Patient/{id}/$eakte mit einer Parameters-Ressource im Body |
{id} | Patienten-ID (Patient.id) |
start | optional, Beginn des Zeitraums (einschließlich): 2026, 2026-01 oder 2026-01-01 |
end | optional, Ende des Zeitraums (einschließlich): 2026, 2026-12 oder 2026-12-31 |
embedEncounter | optional, true oder false (Standard false); bettet den Encounter in jeden Eintrag ein |
| Ergebnis | Bundle vom Typ searchset mit dem Profil https://fhir.t2med.de/StructureDefinition/FhirApiBundleEAkte|1.0.0 |
| Einträge | je eAkten-Eintrag eine Composition mit dem Profil https://fhir.t2med.de/StructureDefinition/FhirApiCompositionEAkte|1.0.0 |
Inhalt einer Composition | Titel, Zeitpunkt, Text, Patient (subject), Arztrolle (author) und Behandlungsort (custodian) |
| Umfang | eine generische eAkte, die der Ansicht der eAkte im T2med-Client entspricht; es werden die Sichtbarkeiten des aktuellen T2med-Benutzers beachtet |
| Dokumente und Bilder | sind als Referenz (DocumentReference) enthalten; die Datei selbst wird in einem zweiten Schritt über eine vom Server mitgelieferte Download-URL abgerufen |
Hinweise
- Bei umfangreichen Akten empfiehlt es sich, den Zeitraum mit
startundendeinzugrenzen. - Weitere Filter (Eintragstyp, Behandlungsfall, Arztrolle, Behandlungsort, Quelle) sind geplant und noch nicht verfügbar.
- Eintragsarten wie Diagnosen oder Befunde werden derzeit als Text in der
Compositiongeliefert. Eigene Profile je Eintragsart sind noch nicht verfügbar.
Ein Beispiel steht in der API-Referenz.
Profile und Code-Systeme
Unterstützte Profile
| Ressource | Profil | Unterstützte Operationen |
|---|---|---|
| Patient | https://fhir.t2med.de/StructureDefinition/FhirApiPatient|1.0.0 | create, read, update, search(identifier), search(family/given/birthdate) |
| Encounter | https://fhir.t2med.de/StructureDefinition/FhirApiEncounter|1.0.0 | create (Kontext anlegen, ab 26.10), read |
| Composition | https://fhir.t2med.de/StructureDefinition/FhirApiCompositionEAkte|1.0.0 | Ergebnis von $eakte (ab 26.11, nur lesend) |
| Bundle | https://fhir.t2med.de/StructureDefinition/FhirApiBundleEAkte|1.0.0 | Ergebnis von $eakte (ab 26.11, nur lesend) |
| Organization | https://fhir.t2med.de/StructureDefinition/FhirApiOrganization|1.0.0 | read, search(name/identifier), search(practitioner) |
| Practitioner | https://fhir.t2med.de/StructureDefinition/FhirApiPractitioner|1.0.0 | read, search(name/identifier), registrierter Organization-Compartment-Sonderfall |
| Observation | https://fhir.t2med.de/StructureDefinition/FhirApiObservationAnamnese|1.0.0 | create |
| Observation | https://fhir.t2med.de/StructureDefinition/FhirApiObservationBefund|1.0.0 | create |
| Observation | https://fhir.t2med.de/StructureDefinition/FhirApiObservationFreitext|1.0.0 | create |
| Condition | https://fhir.t2med.de/StructureDefinition/FhirApiConditionDiagnose|1.0.0 | create |
| Procedure | https://fhir.t2med.de/StructureDefinition/FhirApiProcedureTherapie|1.0.0 | create |
| Procedure | https://fhir.t2med.de/StructureDefinition/FhirApiProcedureProcedere|1.0.0 | create |
| DocumentReference | https://fhir.t2med.de/StructureDefinition/FhirApiDocumentReferenceFreitext|1.0.0 | create |
| DocumentReference | https://fhir.t2med.de/StructureDefinition/FhirApiDocumentReferenceAnhang|1.0.0 | create |
Tips
X-FHIR-Profile ist bei create-Operationen nicht erforderlich; maßgeblich ist dort das im Payload gesetzte meta.profile. Der Header wird nur für Patient-Read und Patient-Search ausgewertet. Profil-URLs werden ohne Beachtung der Groß-/Kleinschreibung verglichen; empfohlen ist die hier dokumentierte Schreibweise.
Verwendete Code-Systeme (insbesondere Condition)
| Anwendungsfall | System-URL | Codes |
|---|---|---|
ICD-Diagnose in Condition.code.coding | http://fhir.de/CodeSystem/bfarm/icd-10-gm | ICD-10-GM-Code in coding.code, Version optional in coding.version |
| Diagnosesicherheit | https://fhir.kbv.de/CodeSystem/KBV_CS_SFHIR_ICD_DIAGNOSESICHERHEIT | V, G, A, Z |
| Seitenlokalisation | https://fhir.kbv.de/CodeSystem/KBV_CS_SFHIR_ICD_SEITENLOKALISATION | L, R, B |
Diagnosesicherheit und Seitenlokalisation werden als Extensions am ICD-Coding übergeben (http://fhir.de/StructureDefinition/icd-10-gm-diagnosesicherheit bzw. http://fhir.de/StructureDefinition/seitenlokalisation). Die Diagnose-Relevanz (akut, dauerhaft, anamnestisch) ist kein Code-System, sondern eine eigene Extension, siehe unten.
Weitere fachliche Extensions
| Ressource / Kontext | Extension-URL | Verwendung |
|---|---|---|
| Observation Freitext | https://fhir.t2med.de/StructureDefinition/FhirApiFreitextKuerzel | Kürzel als valueString |
| Condition Diagnose | https://fhir.t2med.de/StructureDefinition/FhirApiDiagnoseRelevanz | Relevanz als valueCode: akut, dauerhaft, anamnestisch |
| Procedure Therapie | https://fhir.t2med.de/StructureDefinition/FhirApiFeststellungszeitpunkt | Zeitpunkt, ausgewertet vor FhirApiProcedureOccurrence und performedDateTime |
| Procedure Therapie | https://fhir.t2med.de/StructureDefinition/FhirApiProcedureOccurrence | Zeitpunkt, zweite Priorität in der Auswertungsreihenfolge |
| DocumentReference Anhang | https://fhir.t2med.de/StructureDefinition/FhirApiAnhangKuerzel | optionales Kürzel als valueString |
Patient telecom (Telefon) | https://fhir.t2med.de/StructureDefinition/FhirApiTelefonnummerKategorie | Kategorie-Code als valueCode |
Patient telecom (Telefon/E-Mail) | https://fhir.t2med.de/StructureDefinition/FhirApiKontaktinformationKommentar | Freitext-Kommentar als valueString |
Details zur Zeitpunkt-Auswertungsreihenfolge bei Procedure (Therapie und Prozedere): zuerst FhirApiFeststellungszeitpunkt, dann FhirApiProcedureOccurrence, zuletzt performedDateTime.
Fehlerbehandlung und Robustheit
Empfehlungen
| Empfehlung | Begründung |
|---|---|
OperationOutcome immer auswerten | Fachliche Fehler und Warnungen werden darüber transportiert. |
4xx nicht automatisch wiederholen | Meist fachliche oder formale Fehler. |
| Transiente technische Fehler gezielt wiederholen | Dafür X-Request-Id stabil halten, wenn verwendet. |
Statuscodes
| HTTP | Bedeutung |
|---|---|
400 | Request formal ungültig, z. B. Profil fehlt oder Kontext-Identifier ist ungültig |
403 | API-Key fehlt oder ist ungültig; bei Verwendung des Test-/Demo-API-Keys zusätzlich: serverseitiges Limit von 100 Aufrufen pro Serverprozess überschritten |
404 | Resource bei read, search(identifier) oder update nicht gefunden |
409 | Versionskonflikt bei Patient-Update |
422 | fachliche oder technische Verarbeitung fehlgeschlagen |
501 | Profil nicht unterstützt |
503 | FHIR-API per Feature-Flag deaktiviert |
Implementierungsnahe Besonderheiten
| Fall | Verhalten |
|---|---|
GET /Patient?family=...&given=...&birthdate=... ohne Parameter | Suchservice wird mit leeren Spezifikationen aufgerufen; die Antwort ist eine Suchmenge. |
DocumentReference mit Profil FhirApiDocumentReferenceAnhang|1.0.0 | Validierungsfehler, wenn description, attachment.data oder attachment.contentType fehlen. |
GET /Organization/{id}/Practitioner | Endpoint ist registriert, der aktuelle Handler interpretiert {id} aber als Practitioner-/Arztrollen-ID und gibt Organization-Ressourcen zurück. Für Drittanbieter ist GET /Organization?practitioner=<id> die fachlich klarere Variante. |
PUT /Patient/{id} — Optimistic Locking mit If-Match | Der Versionskonflikt-Check (→ 409) wird ausgelöst, wenn der If-Match: W/"<version>"-Header mitgesendet wird. HAPI-FHIR-Clients setzen diesen automatisch, wenn die Versionsnummer im idElement gesetzt ist. Ohne If-Match-Header überspringt der Server den Versionscheck — empfohlen wird, den Header immer mitzusenden, um unbeabsichtigte Überschreibungen zu verhindern. |
meta.versionId im Patient-Response | Der Server liefert meta.versionId als vollen Pfad ({id}/_history/{version}), nicht als kurze Versionsnummer. Die kurze Versionsnummer für den If-Match-Header lässt sich daraus per IdType(meta.versionId).versionIdPart extrahieren (ergibt z. B. "4" aus "abc123/_history/4"). |
| Warnungen | Ohne X-TreatWarningAsError: false werden Warnungen als Fehler behandelt. |
| Content-Type | Die API akzeptiert application/fhir+json und application/fhir+xml; Content-Type und Accept entsprechend dem gewünschten Format setzen. |
Konkrete Beispiel-Payloads für Fehlerfälle finden sich unter API-Referenz → Typische Fehlerbeispiele.
Kontaktdaten und Geschlecht im Patient-Profil
Die Patient-Ressource enthält Kontaktdaten (Telefonnummern und E-Mail-Adressen) als FHIR telecom-Einträge.
Telefonnummer
| Feld | FHIR-Mapping | Mögliche Werte |
|---|---|---|
| Nummer | telecom.value | beliebige Zeichenkette |
| Typ | telecom.system | phone (Telefon), fax (Fax) |
| Verwendung | telecom.use | home, work, mobile (nur bei system=phone) |
| Kategorie | Extension https://fhir.t2med.de/StructureDefinition/FhirApiTelefonnummerKategorie | Code-Wert als valueCode |
| Kommentar | Extension https://fhir.t2med.de/StructureDefinition/FhirApiKontaktinformationKommentar | Freitext als valueString |
Beispiel:
{
"system": "phone",
"value": "089 123456",
"use": "home",
"extension": [
{
"url": "https://fhir.t2med.de/StructureDefinition/FhirApiTelefonnummerKategorie",
"valueCode": "privat"
},
{
"url": "https://fhir.t2med.de/StructureDefinition/FhirApiKontaktinformationKommentar",
"valueString": "nur vormittags erreichbar"
}
]
}
E-Mail-Adresse
| Feld | FHIR-Mapping | Mögliche Werte |
|---|---|---|
| Adresse | telecom.value | E-Mail-Adresse |
| Typ | telecom.system | immer email |
| Verwendung | telecom.use | home, work |
| Kommentar | Extension https://fhir.t2med.de/StructureDefinition/FhirApiKontaktinformationKommentar | Freitext als valueString |
Beispiel:
{
"system": "email",
"value": "max.mustermann@example.de",
"use": "home",
"extension": [
{
"url": "https://fhir.t2med.de/StructureDefinition/FhirApiKontaktinformationKommentar",
"valueString": "bevorzugte Kontaktmethode"
}
]
}
Verhalten bei leeren Kontaktdaten
Sind keine Telefonnummern oder E-Mail-Adressen hinterlegt, enthält die Patient-Ressource kein telecom-Array.
Geschlecht (gender)
Einfache FHIR-Werte (male, female, unknown) werden direkt in Patient.gender übertragen. Die deutschen Werte divers und unbestimmt erfordern zusätzlich die Extension gender-amtlich-de auf dem gender-Element:
| APS-Wert | gender | Extension Code |
|---|---|---|
| männlich | male | — |
| weiblich | female | — |
| divers | other | D |
| unbestimmt | other | X |
| unbekannt | unknown | — |
Die Extension wird als valueCoding auf dem primitiven gender-Element kodiert (nicht auf der Patient-Ressource selbst):
{
"resourceType": "Patient",
"gender": "other",
"_gender": {
"extension": [
{
"url": "http://fhir.de/StructureDefinition/gender-amtlich-de",
"valueCoding": {
"system": "http://fhir.de/CodeSystem/gender-amtlich-de",
"code": "D"
}
}
]
}
}
Warnung
Ohne die Extension wird other serverseitig als unbekannt interpretiert.
Sicherheit, Betrieb und Go-Live
Sicherheits- und Betriebsaspekte
| Thema | Vorgabe |
|---|---|
| API-Key | nie im Klartext loggen |
| Transport | FHIR-Aufrufe über TLS durchführen |
| Lokaler APS-Server | FHIR-API wird lokal über https:// bereitgestellt |
| Zertifikat | APS-Server-Zertifikat wird installationsspezifisch erzeugt |
| Öffentliche CA | Drittanbieter dürfen keine öffentliche CA-signierte Zertifikatskette voraussetzen |
| HTTPS-Client | Bei FHIRBasisUrl mit https:// eigenen SSL-Kontext bzw. HTTP-Client konfigurieren |
| Lokale Hosts | localhost, 127.0.0.1 und lokal konfigurierte Hostnamen unterstützen |
| Zertifikatsprüfung | Installationsspezifische lokale Zertifikate akzeptieren; produktiv den Trust-Store kontrolliert verwalten, statt die Zertifikatsprüfung pauschal zu deaktivieren |
| Geheimnisse | Client-Secret und Refresh-Token nicht im Klartext ablegen, sondern in einem sicheren Schlüsselspeicher; nicht protokollieren |
| Kontext-ID | als kurzlebiges technisches Token behandeln |
| Warnungen | X-TreatWarningAsError bewusst setzen |
| Test-/Demo-API-Key-Limit | Bei Verwendung des Test-/Demo-API-Keys begrenzt der Server auf maximal 100 Aufrufe pro Serverprozess. Nach Erreichen des Limits liefert jeder weitere Aufruf 403 Forbidden. Der Zähler wird nicht zurückgesetzt — für weitere Tests den APS-Server neu starten. |
Go-Live-Checkliste
Klassischer Deep-Link-Pfad
- [ ] Drittanbieter in APS aktiviert
- [ ] API-Key vorhanden und sicher hinterlegt
- [ ]
drittanbieterKeybzw. Hersteller/Produkt korrekt konfiguriert - [ ] Verarbeitung der Deep-Link-Parameter
kontextId,FHIRBasisUrl,oAuthTokenimplementiert - [ ]
FHIRBasisUrlunverändert als FHIR-Client-Basis-URL verwendet - [ ] Eigener SSL-Kontext/HTTP-Client für lokale
https://-APS-Server eingerichtet - [ ] Test mit installationsspezifischem lokalem APS-Zertifikat durchgeführt
- [ ] Test mit
localhost,127.0.0.1oder lokal konfiguriertem Hostnamen durchgeführt - [ ] Test: Aufruf durch T2med-Client über Deep Link
- [ ] Test:
GET /Patient?identifier=https://fhir.t2med.de/identifier/kontext|<KONTEXT_ID> - [ ] Test: gewünschte
POST-Ressourcentypen mit korrektemmeta.profile - [ ] Test:
DocumentReferencemit ProfilFhirApiDocumentReferenceAnhang|1.0.0 - [ ] Test: Fehlerfall ohne oder mit falschem Profil
- [ ] Optional: Transaction-Verhalten mit Rollback geprüft
- [ ] Monitoring für HTTP-Status und
OperationOutcomevorhanden
Zusätzlich bei OAuth Device Flow (Variante B)
- [ ] OAuth Device Authorization Endpoint und Token Endpoint bekannt und erreichbar
- [ ] Client Secret aus APS-Drittanbieter-Einrichtung bereitgestellt
- [ ] Client Secret und Refresh-Token nur im sicheren Schlüsselspeicher abgelegt, nicht im Klartext
- [ ] Client Secret wird nicht geloggt
- [ ] Polling-Verhalten für
authorization_pending,slow_down,expired_tokenundaccess_deniedimplementiert - [ ] Polling-Intervall bei
slow_downkorrekt erhöht (mindestens +5 Sekunden) - [ ] Device Code Expiry korrekt behandelt (Neustart erforderlich)
- [ ] Automatische Wiederverbindung per Refresh-Token (
grant_type=refresh_token) geprüft - [ ] Test: kompletter Device Flow mit Autorisierung im Browser
- [ ] Test: Abbruch und erneuter Start des Device Flow