Skip to main content

Ghasi e-Prescribing Gateway Service — API Contracts

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

Conventions

  • Direct base path: /v1/ghasi-e-prescribing-gateway/fhir (Kong route)
  • Interop proxy path: /fhir/R4/interop/ghasi-eprescribing/* (via fhir-gateway — preferred for first-party services)
  • Auth: Authorization: Bearer <JWT> — Keycloak; tenantId from JWT only
  • Persona enforcement: JWT persona claim must be ehr-backend for MR writes; pharmacy-backend for MD writes
  • Idempotency-Key: Required header on all POST operations (create)
  • ETag: Returned on GET; required via If-Match on PUT/PATCH
  • Content-Type: application/fhir+json
  • Error format: FHIR OperationOutcome on validation failures; JSON { code, message } on gateway errors

Resource: MedicationRequest

POST /fhir/MedicationRequest

Create a new prescription (EHR/orders-service only).

FieldValue
Actorehr-backend persona
Required headersIdempotency-Key, Authorization

Request body (FHIR R4 MedicationRequest):

{
"resourceType": "MedicationRequest",
"status": "active",
"intent": "order",
"medicationCodeableConcept": {
"coding": [{ "system": "http://www.whocc.no/atc", "code": "J01CA01", "display": "Ampicillin" }]
},
"subject": { "reference": "Patient/pat_01..." },
"requester": { "reference": "Practitioner/prac_01..." },
"authoredOn": "2026-04-18",
"dispenseRequest": { "quantity": { "value": 30, "unit": "tablet" } }
}

Response 201:

Headers: ETag: W/"a3f9..."
Location: /fhir/MedicationRequest/mr_01...
X-Prescription-Business-Id: prx_01...
X-Correlation-Id: req_01...
Body: { FHIR MedicationRequest with id, meta.versionId, meta.lastUpdated }

Errors: 403 FORBIDDEN_WRITE_PERSONA, 422 (OperationOutcome on validation), 409 (idempotency conflict), 403 MODULE_NOT_LICENSED


GET /fhir/MedicationRequest/:id

Retrieve a single MedicationRequest.

FieldValue
Actorehr-backend or pharmacy-backend (tenant-scoped)
Response headersETag: W/"..."

Response 200: FHIR MedicationRequest + ETag.

Errors: 404 (not found for tenant), 403 (wrong tenant)


GET /fhir/MedicationRequest

Search MedicationRequests.

Query paramDescription
patientPatient/<id> — required
statusFilter by status (active, cancelled, completed)
_countPage size (default 20, max 100)
_offsetOffset for pagination
authoredDate range filter (ge2026-01-01)

Response 200: FHIR Bundle (type=searchset) with matching resources.


PUT /fhir/MedicationRequest/:id

Update an existing MedicationRequest.

FieldValue
Actorehr-backend only
Required headersIf-Match: W/"<current-etag>"

Response 200: Updated FHIR MedicationRequest with new ETag.

Errors: 412 PRECONDITION_FAILED (stale ETag), 403, 422


Resource: MedicationDispense

POST /fhir/MedicationDispense

Record pharmacy fulfillment.

FieldValue
Actorpharmacy-backend persona only
Required headersIdempotency-Key, Authorization

Request body (FHIR R4 MedicationDispense):

{
"resourceType": "MedicationDispense",
"status": "completed",
"medicationCodeableConcept": {
"coding": [{ "system": "http://www.whocc.no/atc", "code": "J01CA01" }]
},
"subject": { "reference": "Patient/pat_01..." },
"authorizingPrescription": [{ "reference": "MedicationRequest/mr_01..." }],
"quantity": { "value": 30, "unit": "tablet" },
"whenHandedOver": "2026-04-20T14:00:00Z",
"performer": [{ "actor": { "reference": "Practitioner/pharm_01..." } }]
}

Response 201: FHIR MedicationDispense with ETag.

Errors: 422 PRESCRIPTION_NOT_FOUND (MR not known to tenant), 403 FORBIDDEN_WRITE_PERSONA, 422 (profile validation)


GET /fhir/MedicationDispense/:id

Retrieve a single MedicationDispense.

Response 200: FHIR MedicationDispense + ETag.


GET /fhir/MedicationDispense

Search by prescription reference.

Query paramDescription
requestMedicationRequest/<id> — filter dispenses for a prescription
patientPatient/<id>
statuscompleted, in-progress

Resource: Subscription

POST /fhir/Subscription

Register an HTTPS notification channel.

FieldValue
Actorehr-backend or pharmacy-backend

Request body:

{
"resourceType": "Subscription",
"status": "requested",
"criteria": "MedicationDispense?authorizingPrescription=MedicationRequest/mr_01...",
"channel": {
"type": "rest-hook",
"endpoint": "https://pharmacy.example.com/webhooks/eprescribing",
"payload": "application/fhir+json",
"header": ["X-Api-Key: <secret>"]
}
}

Response 201: FHIR Subscription with status: active after endpoint verification.


GET /fhir/Subscription/:id

Get Subscription status and cursor position.


DELETE /fhir/Subscription/:id

Unregister a notification channel.


Resource: Task (P1 — Renewals and Clarifications)

POST /fhir/Task

Create a renewal or clarification task.

FieldValue
Actorpharmacy-backend (requester) or ehr-backend (policy)

Response 201: FHIR Task with status requested.


PATCH /fhir/Task/:id

Update Task status (accept, reject, complete).


Resource: Organization / Endpoint (Directory, P1)

GET /fhir/Organization

Search for pharmacy organizations.

Query paramDescription
namePartial name search
typeOrganization type (pharmacy)
_countPage size

FHIR Operations

POST /fhir/MedicationRequest/$validate

Validate a MedicationRequest against the tenant's pinned IG without persisting.

Response 200: OperationOutcome with informational issues (valid) or error issues (invalid).


Common Error Codes

HTTPCodeMeaning
403FORBIDDEN_WRITE_PERSONAWrong actor type for this resource
403MODULE_NOT_LICENSEDTenant lacks gateway entitlement
403TENANT_ISOLATION_VIOLATIONCross-tenant read/write attempt
409IDEMPOTENCY_KEY_CONFLICTSame key, different payload
412PRECONDITION_FAILEDStale ETag on update
422PROFILE_VALIDATION_FAILUREIG profile constraint violated (OperationOutcome body)
422PRESCRIPTION_NOT_FOUNDMD references MR unknown to tenant
429RATE_LIMIT_EXCEEDEDPer-tenant rate limit hit
503VALIDATOR_UNAVAILABLEIG validator service unavailable (degraded mode)