asyncapi: 3.1.0 info: title: labcomplete AIS-Schnittstelle version: 1.0.0 contact: name: medcom GmbH url: https://www.medcom.at email: support@medcom.at description: | Der Transport der labcomplete AIS-Schnittstelle: Verbindung, Anmeldung, Schutz der Frames, Zustellung und Grenzen. Inhalt, Bedeutung und Ablauf der Nachrichten legt der FHIR-Leitfaden fest: https://fhir.labcomplete.at/ais/v1 ## Frames Ein Frame trägt eine Nachricht: eine FHIR-Nachricht (`Bundle` vom Typ `message`) oder die Quittung `{"ack": ""}`. Die `messageId` ist der `Bundle.identifier` der Nachricht. ## Zustellung - Das AIS baut die Verbindung auf; labcomplete ruft das AIS nie auf. - `ack` heißt angekommen, nicht noch einmal senden; nicht angenommen, eine Fehlerantwort kann folgen. Eine Nachricht, die gegen die Profile verstößt, beantwortet labcomplete mit `invalid-message` und quittiert sie dann, ohne sie zu speichern. Einen `print-job` quittiert das AIS, wenn der Druck in der Warteschlange des Druckers liegt; kann es nicht drucken, antwortet es statt mit `ack` mit einem Fehler. - Ohne `ack` wiederholt der Absender die Nachricht mit derselben `messageId`, höchstens 1 Stunde lang, `request-updated` ohne Zeitgrenze. labcomplete wiederholt, wenn 30 s nach dem Senden kein `ack` da ist; den Abstand des AIS legt das AIS fest. Wiederholungen erkennt der Empfänger an der `messageId` (7 Tage). Die Reihenfolge ist nicht garantiert. - Unbekannte Nachrichtenarten werden quittiert und ignoriert. ## Schutz - Jeder Frame ist ein JWE an den Empfänger (`ECDH-ES+A256KW` mit X25519, `A256GCM`), darin ein JWS des Absenders (`Ed25519`, `typ` = `lab-order+json`), darin die Nachricht. Geschützte Header: `kid`, im JWS zusätzlich `iss` und `aud`. Nicht Prüfbares wird nicht quittiert. - Schlüssel tauschen beide Seiten bei der Einrichtung; ein neuer wird angekündigt und gilt eine Zeit lang neben dem alten. ## Verbindungen und Grenzen - Das AIS hält mindestens zwei Verbindungen offen; je Instanz höchstens 10. Ping alle 30 s. - Höchstens 10 MiB je Frame. - Schließcodes: 1001 Instanz fährt herunter, 1009 Frame zu groß, 1013 zu viele Verbindungen, 4500 Ping unbeantwortet oder Empfänger zu langsam; HTTP 401 beim Handshake. - Inkompatible Änderungen kommen nur mit einem neuen Subprotokoll (`ais.v2`). servers: labcomplete: host: '{host}' protocol: wss pathname: /ais/v1/socket title: WebSocket-Server von labcomplete variables: host: default: api.test.labcomplete.at description: Host von labcomplete, api.test.labcomplete.at (Test) bzw. api.labcomplete.at (Produktion) security: - $ref: '#/components/securitySchemes/connectionToken' channels: connection: address: / title: Verbindung AIS – labcomplete messages: requestCreate: $ref: '#/components/messages/requestCreate' sessionCreate: $ref: '#/components/messages/sessionCreate' sessionLink: $ref: '#/components/messages/sessionLink' printJob: $ref: '#/components/messages/printJob' requestUpdated: $ref: '#/components/messages/requestUpdated' error: $ref: '#/components/messages/error' ack: $ref: '#/components/messages/ack' bindings: ws: method: GET headers: type: object required: - Authorization - Sec-WebSocket-Protocol properties: Authorization: type: string pattern: '^Bearer [A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$' Sec-WebSocket-Protocol: type: string description: Muss `ais.v1` enthalten pattern: '(^|,)\s*ais\.v1\s*(,|$)' bindingVersion: 0.1.0 operations: receiveRequestCreate: action: receive description: Das AIS übergibt eine Anforderung mit Patient, Zuweiser und Vorauswahl. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/requestCreate' receiveSessionCreate: action: receive description: Das AIS bittet um einen Einmal-Link, mit dem ein Benutzer die Anforderung in labcomplete öffnet. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/sessionCreate' sendSessionLink: action: send description: labcomplete antwortet auf `session-create` mit dem Einmal-Link. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/sessionLink' sendPrintJob: action: send description: labcomplete schickt einen Ausdruck an die Sitzung des zuletzt eingelösten Links. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/printJob' sendRequestUpdated: action: send description: labcomplete meldet den Stand der Anforderung mit ihren Aufträgen, nach jeder Datenänderung. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/requestUpdated' sendError: action: send description: labcomplete lehnt eine Nachricht des AIS ab. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/error' receiveError: action: receive description: Das AIS lehnt einen Druck ab, den es nicht ausführen kann. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/error' sendAck: action: send description: labcomplete bestätigt, dass eine Nachricht des AIS angekommen ist, gespeichert oder abgewiesen. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/ack' receiveAck: action: receive description: Das AIS bestätigt, dass es eine Nachricht von labcomplete übernommen hat. channel: $ref: '#/channels/connection' messages: - $ref: '#/channels/connection/messages/ack' components: securitySchemes: connectionToken: type: http scheme: bearer bearerFormat: JWS description: JWS vom AIS (`Ed25519`, `kid` im Header), Claims `iss`, `aud` = Issuer von labcomplete, `iat`, `exp` (höchstens 60 s nach `iat`), `jti` (nur einmal). messages: requestCreate: name: request-create title: Anforderung summary: Bundle-Profil `ais-request-create-message`. payload: $ref: '#/components/schemas/FhirMessage' externalDocs: description: Vollständiges Beispiel im Leitfaden url: https://fhir.labcomplete.at/ais/v1/Bundle-request-create.html examples: - name: request-create summary: 'Gekürzt auf den MessageHeader; das vollständige Beispiel: https://fhir.labcomplete.at/ais/v1/Bundle-request-create.html' payload: resourceType: Bundle meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-request-create-message type: message timestamp: '2026-10-16T08:12:03Z' identifier: system: urn:ietf:rfc:3986 value: urn:uuid:01a143c4-a438-7b42-8fa3-0a4f06a1a3da entry: - fullUrl: urn:uuid:01a143c4-a438-7b42-8fa3-0a4f06a1a3da resource: resourceType: MessageHeader id: 01a143c4-a438-7b42-8fa3-0a4f06a1a3da meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-message-header eventCoding: system: https://fhir.labcomplete.at/ais/v1/CodeSystem/ais-event code: request-create source: name: Beispiel-AIS endpointUrl: https://ais.beispiel.example focus: - reference: urn:uuid:01a143c4-a438-755d-8002-34c8b2893e4a sessionCreate: name: session-create title: Neue Sitzung summary: Bundle-Profil `ais-session-create-message`. payload: $ref: '#/components/schemas/FhirMessage' externalDocs: description: Vollständiges Beispiel im Leitfaden url: https://fhir.labcomplete.at/ais/v1/Bundle-session-create.html examples: - name: session-create summary: 'Gekürzt auf den MessageHeader; das vollständige Beispiel: https://fhir.labcomplete.at/ais/v1/Bundle-session-create.html' payload: resourceType: Bundle meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-session-create-message type: message timestamp: '2026-10-16T08:12:03Z' identifier: system: urn:ietf:rfc:3986 value: urn:uuid:01a143c4-a438-7f68-9c73-6bc4a4b38de8 entry: - fullUrl: urn:uuid:01a143c4-a438-7f68-9c73-6bc4a4b38de8 resource: resourceType: MessageHeader id: 01a143c4-a438-7f68-9c73-6bc4a4b38de8 meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-message-header eventCoding: system: https://fhir.labcomplete.at/ais/v1/CodeSystem/ais-event code: session-create source: name: Beispiel-AIS endpointUrl: https://ais.beispiel.example focus: - reference: urn:uuid:5c1d0000-0000-4000-8000-000000000201 sessionLink: name: session-create (Antwort) title: Einmal-Link summary: Bundle-Profil `ais-session-link-message`. payload: $ref: '#/components/schemas/FhirMessage' externalDocs: description: Vollständiges Beispiel im Leitfaden url: https://fhir.labcomplete.at/ais/v1/Bundle-session-create-response.html examples: - name: session-create-response summary: 'Gekürzt auf den MessageHeader; das vollständige Beispiel: https://fhir.labcomplete.at/ais/v1/Bundle-session-create-response.html' payload: resourceType: Bundle meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-session-link-message type: message timestamp: '2026-10-17T09:01:02Z' identifier: system: urn:ietf:rfc:3986 value: urn:uuid:d063098f-c26a-5608-8e71-272b2c413135 entry: - fullUrl: urn:uuid:d063098f-c26a-5608-8e71-272b2c413135 resource: resourceType: MessageHeader id: d063098f-c26a-5608-8e71-272b2c413135 meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-message-header eventCoding: system: https://fhir.labcomplete.at/ais/v1/CodeSystem/ais-event code: session-create source: endpointUrl: https://api.labcomplete.at/ais/v1/socket name: labcomplete response: identifier: system: urn:ietf:rfc:3986 value: urn:uuid:01a143c4-a438-7f68-9c73-6bc4a4b38de8 code: ok focus: - reference: urn:uuid:77758e16-d61b-5fa7-a67d-871eebeaa657 printJob: name: print-job title: Druckauftrag summary: Bundle-Profil `ais-print-job-message`. payload: $ref: '#/components/schemas/FhirMessage' externalDocs: description: Vollständiges Beispiel im Leitfaden url: https://fhir.labcomplete.at/ais/v1/Bundle-print-job.html examples: - name: print-job summary: 'Gekürzt auf den MessageHeader; das vollständige Beispiel: https://fhir.labcomplete.at/ais/v1/Bundle-print-job.html' payload: resourceType: Bundle meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-print-job-message type: message timestamp: '2026-10-17T09:01:02Z' identifier: system: urn:ietf:rfc:3986 value: urn:uuid:e9f12fcb-cf13-5f6c-8beb-d47e60ece32c entry: - fullUrl: urn:uuid:e9f12fcb-cf13-5f6c-8beb-d47e60ece32c resource: resourceType: MessageHeader id: e9f12fcb-cf13-5f6c-8beb-d47e60ece32c meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-message-header eventCoding: system: https://fhir.labcomplete.at/ais/v1/CodeSystem/ais-event code: print-job source: endpointUrl: https://api.labcomplete.at/ais/v1/socket name: labcomplete focus: - reference: urn:uuid:37611a3c-0f5c-554a-89e1-b914bb4e6e73 requestUpdated: name: request-updated title: Rückschrieb summary: Bundle-Profil `ais-request-updated-message`. payload: $ref: '#/components/schemas/FhirMessage' externalDocs: description: Vollständiges Beispiel im Leitfaden url: https://fhir.labcomplete.at/ais/v1/Bundle-request-updated.html examples: - name: request-updated summary: 'Gekürzt auf den MessageHeader; das vollständige Beispiel: https://fhir.labcomplete.at/ais/v1/Bundle-request-updated.html' payload: resourceType: Bundle meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-request-updated-message type: message timestamp: '2026-10-17T09:01:02Z' identifier: system: urn:ietf:rfc:3986 value: urn:uuid:cc243c81-fb3a-5de3-949f-fb2af70c560a entry: - fullUrl: urn:uuid:cc243c81-fb3a-5de3-949f-fb2af70c560a resource: resourceType: MessageHeader id: cc243c81-fb3a-5de3-949f-fb2af70c560a meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-message-header eventCoding: system: https://fhir.labcomplete.at/ais/v1/CodeSystem/ais-event code: request-updated source: endpointUrl: https://api.labcomplete.at/ais/v1/socket name: labcomplete focus: - reference: urn:uuid:0198a3c1-7e40-7b2e-a1f0-3c5d7e9f1a2c - reference: urn:uuid:0198a3c1-7e52-7a3f-9b0d-4c6e1f2a8b30 - reference: urn:uuid:d6481ec9-0595-597d-9002-c8793a66afa7 - reference: urn:uuid:17267849-5f12-58b0-802a-8065d590258a - reference: urn:uuid:0198a3c1-7e53-7b4e-8c1d-5d7f2a3b9c41 - reference: urn:uuid:723f6b43-46b0-549e-a977-6ffbb54cf8c1 error: name: Fehler title: Fehlerantwort summary: Bundle-Profil `ais-error-message`. payload: $ref: '#/components/schemas/FhirMessage' externalDocs: description: Vollständiges Beispiel im Leitfaden url: https://fhir.labcomplete.at/ais/v1/Bundle-request-create-error.html examples: - name: request-create-error summary: 'Gekürzt auf den MessageHeader; das vollständige Beispiel: https://fhir.labcomplete.at/ais/v1/Bundle-request-create-error.html' payload: resourceType: Bundle meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-error-message type: message timestamp: '2026-10-17T09:01:02Z' identifier: system: urn:ietf:rfc:3986 value: urn:uuid:8ef13a73-5d41-509f-9310-15e71dd59407 entry: - fullUrl: urn:uuid:8ef13a73-5d41-509f-9310-15e71dd59407 resource: resourceType: MessageHeader id: 8ef13a73-5d41-509f-9310-15e71dd59407 meta: profile: - https://fhir.labcomplete.at/ais/v1/StructureDefinition/ais-message-header eventCoding: system: https://fhir.labcomplete.at/ais/v1/CodeSystem/ais-event code: request-create source: endpointUrl: https://api.labcomplete.at/ais/v1/socket name: labcomplete response: identifier: system: urn:ietf:rfc:3986 value: urn:uuid:01a143c4-a438-7b42-8fa3-0a4f06a1a3da code: fatal-error details: reference: urn:uuid:b532bc80-fb66-5aa4-90b3-b0695b310acd ack: name: ack title: Quittung summary: Die Nachricht ist angekommen und wird nicht noch einmal gesendet. payload: $ref: '#/components/schemas/Ack' examples: - name: ack payload: ack: 01a143c4-a438-7b42-8fa3-0a4f06a1a3da schemas: FhirMessage: type: object description: >- FHIR R5 Bundle vom Typ `message`, gültig gegen R5 und die Profile unter `https://fhir.labcomplete.at/ais/v1`. Der erste Eintrag ist der `MessageHeader`. required: - resourceType - type - identifier - timestamp - entry properties: resourceType: const: Bundle meta: type: object properties: profile: type: array items: type: string format: uri type: const: message identifier: type: object description: Die `messageId`. required: - system - value properties: system: const: urn:ietf:rfc:3986 value: type: string pattern: '^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' timestamp: type: string format: date-time description: In UTC. entry: type: array minItems: 1 items: type: object required: - fullUrl - resource properties: fullUrl: type: string resource: type: object required: - resourceType properties: resourceType: type: string Ack: type: object required: - ack properties: ack: type: string format: uuid description: Die `messageId` der quittierten Nachricht. additionalProperties: false