Skip to main content

Care Plan Service — API Contracts

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

Conventions

  • Base path: /api/v1/care-plans (Kong route prefix)
  • Auth: Authorization: Bearer <JWT> — Keycloak-issued, tenantId from JWT claims
  • Tenant isolation: enforced server-side; clients cannot override tenantId
  • Pagination: ?page=1&limit=20; response envelope: { data, meta: { total, page, limit } }
  • Concurrency: every mutating response includes version; PATCH/POST state changes require version in body
  • IDs: ULIDs with prefix (e.g., cp_01..., cpg_01...)
  • Content-Type: application/json

Resource: Care Plans

POST /api/v1/care-plans

Create a new care plan.

FieldValue
Auth scopecare_plan:write
Idempotency-KeyOptional header; recommended for retry safety

Request body:

{
"patientId": "pat_01...",
"encounterId": "enc_01...",
"title": "Diabetes Management Plan",
"category": { "coding": [{ "system": "http://snomed.info/sct", "code": "734163000", "display": "Care plan" }] },
"description": "Quarterly HbA1c monitoring and lifestyle coaching"
}

Response 201:

{
"data": {
"id": "cp_01...",
"patientId": "pat_01...",
"status": "draft",
"version": 1,
"title": "Diabetes Management Plan",
"createdAt": "2026-04-18T10:00:00Z"
}
}

Errors: 400 VALIDATION_ERROR, 403 MODULE_NOT_LICENSED, 409 (duplicate Idempotency-Key)


GET /api/v1/care-plans

List care plans for a patient.

FieldValue
Auth scopecare_plan:read
Query paramspatientId (required), status (optional), page, limit

Response 200:

{
"data": [
{ "id": "cp_01...", "patientId": "pat_01...", "title": "...", "status": "active", "version": 3 }
],
"meta": { "total": 1, "page": 1, "limit": 20 }
}

GET /api/v1/care-plans/:id

Get a single care plan with goals, activities, and care team.

FieldValue
Auth scopecare_plan:read

Response 200:

{
"data": {
"id": "cp_01...",
"patientId": "pat_01...",
"status": "active",
"version": 2,
"title": "Diabetes Management Plan",
"goals": [{ "id": "cpg_01...", "description": "Reduce HbA1c below 7%", "status": "in_progress", "dueAt": "2026-09-01" }],
"activities": [{ "id": "cpa_01...", "description": "Monthly dietitian visit", "status": "not_started", "assigneeId": "prac_01..." }],
"careTeam": [{ "id": "ctm_01...", "practitionerId": "prac_01...", "role": { "coding": [{ "code": "112247003", "display": "Medical doctor" }] } }]
}
}

Errors: 404 CARE_PLAN_NOT_FOUND


PATCH /api/v1/care-plans/:id

Update care plan fields. Requires current version.

FieldValue
Auth scopecare_plan:write

Request body:

{
"version": 2,
"title": "Updated Plan Title",
"description": "Updated description"
}

Response 200: Updated care plan object with incremented version.

Errors: 404, 409 VERSION_CONFLICT, 409 CARE_PLAN_CLOSED


POST /api/v1/care-plans/:id/activate

Transition plan from draft to active.

FieldValue
Auth scopecare_plan:write
Body{ "version": <current> }

Response 200: Updated plan with status: active.


POST /api/v1/care-plans/:id/review

Record a formal care plan review.

FieldValue
Auth scopecare_plan:write

Request body:

{ "version": 2, "reviewNote": "Goals on track; no changes needed", "nextReviewDue": "2026-07-01" }

Response 200: { "carePlanId": "cp_01...", "lastReviewedAt": "2026-04-18T10:00:00Z", "version": 3 }


POST /api/v1/care-plans/:id/close

Close (complete or revoke) a care plan.

FieldValue
Auth scopecare_plan:admin
Body{ "version": 3, "closeReason": "completed" }closeReason: completed or revoked

Response 200: Plan with terminal status.


Resource: Goals

POST /api/v1/care-plans/:id/goals

Add a goal to an active care plan.

FieldValue
Auth scopecare_plan:write

Request body:

{
"description": "Achieve HbA1c < 7%",
"targetDetail": { "measure": { "coding": [{ "system": "http://loinc.org", "code": "4548-4", "display": "HbA1c" }] }, "detailQuantity": { "value": 7, "unit": "%" } },
"dueAt": "2026-09-01",
"status": "proposed"
}

Response 201: { "data": { "id": "cpg_01...", "carePlanId": "cp_01...", "status": "proposed", ... } }


PATCH /api/v1/care-plans/:id/goals/:goalId

Update goal status or target.

FieldValue
Auth scopecare_plan:write
Body{ "status": "in_progress", "dueAt": "2026-10-01" }

Response 200: Updated goal.


Resource: Activities

POST /api/v1/care-plans/:id/activities

Add an activity to a care plan.

FieldValue
Auth scopecare_plan:write

Request body:

{
"description": "Monthly dietitian consultation",
"assigneeId": "prac_01...",
"scheduleDetail": { "repeat": { "frequency": 1, "period": 1, "periodUnit": "mo" } },
"status": "not_started"
}

Response 201: { "data": { "id": "cpa_01...", ... } }


POST /api/v1/care-plans/:id/activities/:activityId/complete

Mark an activity as complete.

FieldValue
Auth scopecare_plan:write
Body{ "completionNote": "Patient attended; goals discussed" }

Response 200: Updated activity with status: completed, completedAt.


Resource: CareTeam

PUT /api/v1/care-plans/:id/care-team

Replace the care team for a plan.

FieldValue
Auth scopecare_plan:admin

Request body:

{
"version": 2,
"members": [
{ "practitionerId": "prac_01...", "role": { "coding": [{ "code": "446050000", "display": "Primary care physician" }] }, "effectiveFrom": "2026-04-01" }
]
}

Response 200: Updated plan with new team.


FHIR R4 Read Surface

Served via fhir-gateway routing to care-plan-service FHIR adapter. Read/search only — no FHIR write interactions supported.

EndpointFHIR resourceParameters
GET /fhir/R4/CarePlan/:idCarePlan
GET /fhir/R4/CarePlan?patient=Patient/:patientIdBundle<CarePlan>status, _count, _offset
GET /fhir/R4/Goal/:idGoal
GET /fhir/R4/Goal?patient=Patient/:patientIdBundle<Goal>lifecycle-status
GET /fhir/R4/CareTeam?patient=Patient/:patientIdBundle<CareTeam>

Common Error Codes

HTTPCodeMeaning
400VALIDATION_ERRORMissing or invalid field
403MODULE_NOT_LICENSEDTenant lacks ehr.care_plans entitlement
403INSUFFICIENT_SCOPEMissing required RBAC scope
403TENANT_ISOLATION_VIOLATIONCross-tenant access attempt detected
404CARE_PLAN_NOT_FOUNDPlan ID not found for tenant
409VERSION_CONFLICTStale version in request
409CARE_PLAN_CLOSEDAttempt to mutate completed/revoked plan
422INVALID_STATUS_TRANSITIONTransition violates state machine
422INVALID_CODINGCoding system/code invalid per terminology-service