Skip to main content

Interop Service — API Contracts

Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · 03 platform-services · 02 DDD


1. Base Paths and Auth

Path prefixPurposeAuth
/fhir/R4/*FHIR R4 REST API (external + internal consumers)Bearer JWT (Keycloak); SMART scopes
/v1/interop/*Management APIs (connectors, message log, export)Bearer JWT; svc:interop:admin
MLLP port 2575HL7 v2 inbound (TCP + TLS)Per-connector client cert / shared secret

2. FHIR R4 Gateway Endpoints

GET /fhir/R4/metadata

Returns consolidated CapabilityStatement.

Response 200: FHIR CapabilityStatement resource declaring all supported resource types, interactions, search parameters, and profiles.


GET /fhir/R4/{ResourceType}/{id}

Read a specific resource. Routes to owning service.

AttributeValue
Auth scopeSMART user/{ResourceType}.read or patient/{ResourceType}.read
ABACPatient-linked resources checked against access policy

Response 200: FHIR resource JSON. Response 404: OperationOutcome with not-found. Response 403: OperationOutcome with security.


GET /fhir/R4/{ResourceType}

Search resources. Routes to owning service; may fan-out for split-ownership resources.

Common search parameters supported:

ResourceRequired paramsOptional params
Patientidentifier, family, birthdategender, address
Observationpatient, category, codedate, _sort, _count
DiagnosticReportpatient, categorydate, status, _sort
ServiceRequestpatient, status, categoryauthored, requester
ImagingStudypatientstarted, modality, status
Specimenpatient, accessiontype, status

Response 200: FHIR Bundle (type=searchset).


POST /fhir/R4/{ResourceType}

Create resource. Routes to owning service.

AttributeValue
Auth scopeSMART user/{ResourceType}.write
Profile validationValidated against declared profile; 422 on violation

Request body: FHIR resource JSON. Response 201: Created resource with Location header. Response 422: OperationOutcome with validation issues.


PUT /fhir/R4/{ResourceType}/{id}

Update resource. Routes to owning service (mutable facts only).

Response 200: Updated resource. Response 409: Optimistic lock conflict.


POST /fhir/R4/{ResourceType}/$validate

Validate a resource against declared profile without persisting.

Response 200: OperationOutcome with validation results (may be issue[].severity=information if valid).


GET /fhir/R4/Group/{id}/$export — Bulk Export

Initiate FHIR bulk export for a patient group.

AttributeValue
Auth scopesvc:interop:bulk-export
Parameters_type (comma-separated resource types), _since (date filter)

Response 202: Empty body; Content-Location: /fhir/R4/$export/{jobId}.

GET /fhir/R4/$export/{jobId} — Bulk Export Status

Poll export job status.

Response 200 (complete):

{
"transactionTime": "2026-04-18T00:00:00Z",
"request": "...",
"requiresAccessToken": true,
"output": [
{ "type": "Patient", "url": "https://storage.ghasi.af/exports/PAT.ndjson" }
],
"error": []
}

Response 202 (in-progress): Empty body; X-Progress header. Response 500: OperationOutcome.


POST /fhir/R4/$import — Bulk Import

Initiate FHIR bulk import (admin / migration only).

AttributeValue
Auth scopesvc:interop:bulk-import

Request body:

{
"inputFormat": "application/fhir+ndjson",
"inputSource": "https://storage.ghasi.af/imports/batch-001.ndjson",
"input": [{ "type": "Patient", "url": "..." }]
}

Response 202: Content-Location for polling.


3. FHIR Terminology Operations (proxied to terminology-service)

OperationPathNotes
LookupGET /fhir/R4/CodeSystem/$lookup?system=&code=Proxied to terminology-service
Validate codeGET /fhir/R4/CodeSystem/$validate-code?system=&code=Proxied
Expand ValueSetGET /fhir/R4/ValueSet/$expand?url=Proxied
TranslatePOST /fhir/R4/ConceptMap/$translateProxied

4. Connector Management APIs

GET /v1/interop/connectors

List connectors for tenant.

Response 200: Paginated connector list.

POST /v1/interop/connectors

Register a new integration connector.

Request body:

{
"name": "KMC LIS HL7 v2",
"protocol": "mllp",
"direction": "inbound",
"host": "lis.kmc.af",
"port": 2575,
"tlsEnabled": true,
"messageTypes": ["ORU^R01", "ORM^O01"],
"facilityId": "FAC_01J..."
}

Response 201: Connector object with id.

POST /v1/interop/connectors/:id/activate

Activate a connector (start MLLP listener or enable outbound send).

POST /v1/interop/connectors/:id/deactivate

Deactivate connector. Does not delete message history.


5. HL7 Message Log

GET /v1/interop/hl7/messages

Query HL7 message log.

| Query params | connectorId, messageType, status, from, to, page, pageSize |

Response 200: Paginated message list with id, messageType, status, receivedAt, processingStatus.

GET /v1/interop/hl7/messages/:id

Get full message detail including raw payload and resource links.

POST /v1/interop/hl7/messages/:id/reprocess

Manually reprocess a failed message (admin only).


6. FHIR Error Format

All FHIR errors return OperationOutcome:

{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "not-found",
"diagnostics": "Resource Patient/PAT_01J... not found for tenant tenant_01J..."
}]
}

7. Management API Error Format

{
"error": {
"code": "INTEROP_CONNECTOR_NOT_FOUND",
"message": "Connector ID not found for this tenant",
"details": { "connectorId": "CONN_01J..." }
}
}

8. Common Error Codes

CodeHTTPDescription
INTEROP_CONNECTOR_NOT_FOUND404Connector does not exist
INTEROP_CONNECTOR_ALREADY_ACTIVE409Activate called on active connector
INTEROP_FHIR_ROUTE_NOT_FOUND404No routing rule for resource type
INTEROP_OWNING_SERVICE_UNAVAILABLE503Target service unreachable
INTEROP_PROFILE_VIOLATION422Resource fails profile validation
INTEROP_BULK_JOB_NOT_FOUND404Export job ID not found
INTEROP_TENANT_MISMATCH403Resource/connector belongs to different tenant