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 prefix | Purpose | Auth |
|---|---|---|
/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 2575 | HL7 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.
| Attribute | Value |
|---|---|
| Auth scope | SMART user/{ResourceType}.read or patient/{ResourceType}.read |
| ABAC | Patient-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:
| Resource | Required params | Optional params |
|---|---|---|
Patient | identifier, family, birthdate | gender, address |
Observation | patient, category, code | date, _sort, _count |
DiagnosticReport | patient, category | date, status, _sort |
ServiceRequest | patient, status, category | authored, requester |
ImagingStudy | patient | started, modality, status |
Specimen | patient, accession | type, status |
Response 200: FHIR Bundle (type=searchset).
POST /fhir/R4/{ResourceType}
Create resource. Routes to owning service.
| Attribute | Value |
|---|---|
| Auth scope | SMART user/{ResourceType}.write |
| Profile validation | Validated 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.
| Attribute | Value |
|---|---|
| Auth scope | svc: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).
| Attribute | Value |
|---|---|
| Auth scope | svc: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)
| Operation | Path | Notes |
|---|---|---|
| Lookup | GET /fhir/R4/CodeSystem/$lookup?system=&code= | Proxied to terminology-service |
| Validate code | GET /fhir/R4/CodeSystem/$validate-code?system=&code= | Proxied |
| Expand ValueSet | GET /fhir/R4/ValueSet/$expand?url= | Proxied |
| Translate | POST /fhir/R4/ConceptMap/$translate | Proxied |
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
| Code | HTTP | Description |
|---|---|---|
INTEROP_CONNECTOR_NOT_FOUND | 404 | Connector does not exist |
INTEROP_CONNECTOR_ALREADY_ACTIVE | 409 | Activate called on active connector |
INTEROP_FHIR_ROUTE_NOT_FOUND | 404 | No routing rule for resource type |
INTEROP_OWNING_SERVICE_UNAVAILABLE | 503 | Target service unreachable |
INTEROP_PROFILE_VIOLATION | 422 | Resource fails profile validation |
INTEROP_BULK_JOB_NOT_FOUND | 404 | Export job ID not found |
INTEROP_TENANT_MISMATCH | 403 | Resource/connector belongs to different tenant |