Skip to main content

Medication Service — API Contracts

Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · API paths · FHIR-first

1. Conventions

  • Base path (internal REST): /api/v1/medications, /api/v1/dispenses, /api/v1/stock-items, /api/v1/mar, /api/v1/reconciliation.
  • Base path (FHIR R4): via fhir-gateway — this service owns MedicationRequest (chart side), MedicationAdministration, MedicationStatement, Medication, MedicationKnowledge. National interop copies of MR/MD live in ghasi-eprescribing-gateway-service.
  • AuthN: Bearer JWT (identity-service).
  • AuthZ: scopes (see SECURITY_MODEL).
  • Idempotency: Idempotency-Key header required for POST /dispenses and POST /medications/{id}/sign.
  • Concurrency: If-Match ETag on PUT/PATCH.
  • Pagination: ?page=1&pageSize=50, max 200; cursor style for FHIR.
  • Response envelope: { success, data, error, meta }.

2. Prescriptions (Medication list & prescribing)

MethodPathScopePurpose
POST/api/v1/medicationsmedication:prescribeDraft a prescription
GET/api/v1/medicationsmedication:readList for a patient (patientId, status, source)
GET/api/v1/medications/{id}medication:readRetrieve single
PATCH/api/v1/medications/{id}medication:prescribeUpdate draft (pre-sign)
POST/api/v1/medications/{id}/signmedication:prescribeSign — runs safety checks; includes overrides[] if required
POST/api/v1/medications/{id}/overridemedication:prescribeRecord override standalone
PUT/api/v1/medications/{id}/discontinuemedication:prescribeDiscontinue with reason
PUT/api/v1/medications/{id}/holdmedication:prescribePlace on hold
PUT/api/v1/medications/{id}/resumemedication:prescribeResume from hold
POST/api/v1/medications/{id}/refillmedication:prescribeAuthorize refill

Sign request schema

{
"acknowledgeAlerts": [
{ "alertId": "...", "overrideReason": "patient has tolerated amox historically, allergy re-assessed" }
],
"destination": "pharmacy:PHX-001",
"preferredPharmacyId": "phm_...",
"transmitExternally": false
}

Error codes

CodeMeaning
MED_ALERT_BLOCKING (422)Blocking alert without override
MED_CROSS_TENANT (403)Cross-tenant reference
MED_PRECONDITION_FAILED (412)Stale ETag
MED_INVALID_STATUS (409)Status transition not allowed
MED_DRUG_KB_UNAVAILABLE (503)KB check failed

3. Dispensing

MethodPathScopePurpose
POST/api/v1/dispensesdispense:createRecord a dispense; atomic inventory decrement
GET/api/v1/dispensesdispense:readQueue with filters
GET/api/v1/dispenses/{id}dispense:readSingle dispense
POST/api/v1/dispenses/{id}/returndispense:createReturn/undispense
POST/api/v1/dispenses/{id}/countersigndispense:countersignSchedule II counter-sign

Dispense request

{
"prescriptionId": "rx_...",
"stockItemId": "stk_...",
"dispensedQuantity": 30,
"quantityUnit": "tablet",
"lotNumber": "LOT-2026-04",
"expiryDate": "2027-12-31",
"partial": false,
"notes": "labeled"
}

Idempotency: server computes fingerprint on (prescriptionId, dispensedQuantity, lotNumber, idempotencyKey).

4. Stock / Inventory

MethodPathScopePurpose
POST/api/v1/stock-itemsinventory:writeReceive stock (GRN)
GET/api/v1/stock-itemsinventory:readList stock with filters
PATCH/api/v1/stock-items/{id}inventory:writeAdjust (threshold-gated)
POST/api/v1/stock-items/{id}/transferinventory:transferTransfer between nodes
POST/api/v1/stock-items/{id}/recallinventory:recallMark lot recalled
GET/api/v1/stock-items/reorder-alertsinventory:readBelow reorder point
GET/api/v1/stock-items/expiry-alertsinventory:readWithin expiry horizon

5. Medication Administration (MAR)

MethodPathScopePurpose
POST/api/v1/marmar:recordRecord administration
GET/api/v1/marmar:readPer patient or per prescription
PATCH/api/v1/mar/{id}/correctmar:recordCorrection (new entry linked)

6. Reconciliation

MethodPathScopePurpose
POST/api/v1/reconciliationreconciliation:startStart session
GET/api/v1/reconciliation/{id}reconciliation:readSession + diff
PATCH/api/v1/reconciliation/{id}/items/{lineId}reconciliation:actionContinue / Discontinue / Modify
POST/api/v1/reconciliation/{id}/completereconciliation:completeFinalize

7. FHIR REST (via fhir-gateway)

ResourceInteractionsSearch params
MedicationRequestread, search, create (chart), updatesubject, status, category, _lastUpdated
MedicationAdministrationread, search, createsubject, medication, effective-time
MedicationStatementread, search, createsubject, status
Medicationread, searchcode
MedicationKnowledgeread, searchcode, ingredient
DetectedIssueread, searchpatient, category (alert-override records)

8. Rate Limits

EndpointLimit
POST /medications/{id}/sign30 rpm per actor
POST /dispenses120 rpm per actor
GET /dispenses (queue)300 rpm per actor

9. Errors (common envelope)

{
"success": false,
"error": {
"code": "MED_ALERT_BLOCKING",
"message": "Signing blocked by 1 critical alert",
"details": { "alerts": [ { "id": "...", "severity": "high", "type": "drug-allergy" } ] }
}
}