Changelog
v2.0.0
Released date: TBD
Motivation
The previous status field (draft/active/revoked) tried to capture the plan's
lifecycle in a single enum. It couldn't represent multiple content versions with
independent approval states, and draft and revoked were both just "not in effect".
The new model replaces status with an active_version pointer — the version number
of the content version that can currently be shown to patients (null if no version
can). The old statuses map to the new model like this:
Old status |
Meaning | New representation |
|---|---|---|
draft |
Not yet in effect | No active version: active_version is null, is_active is false |
active |
Can be shown to patients | active_version points at the version that can be shown (is_active is true for that version) |
revoked |
Withdrawn, no longer shown | Same as draft: deactivating clears active_version |
Since draft and revoked collapse into the same state, "a draft" is now simply
"a plan without an active version". This also enables:
- per-version approval tracking (
approvalsarray) - clients always seeing current metadata when querying historical snapshots
Terminology cleanup
versionhas been renamed torevisionfor all endpoints and models to avoid confusion withcontent.versioncontent.versionhas been renamed toversionfor all endpoints and models- the term
revokehas been replaced bydeactivate. Deactivating a plan clears theactive_versionpointer, so the plan has no active version
Changes
New endpoint
- Added
GET /api/v2/plan/{id}/active— returns the currently active version of a plan
PlanResponse changes
statusfield removedis_activefield added — true only when this content version is the active oneactive_versionfield added — the content version that is currently active,nullif the plan has no active versioncontent_versionrenamed toversionversion(event counter) renamed torevisionapproval_statusremoved — replaced withapprovalsarray (one entry per content version)rejection_reasonandrevoke_reasonfields removedpublication_statusentries:content_versionrenamed toversion,published_atrenamed toupdated_at
Approvals
approvalsis now an array ofApprovalEntry— one per content version- Each entry has:
version,status(requested/given/rejected),updated_at - Approval commands (
$approval-requested,$approval-given,$approval-rejected) now require bothrevision(for optimistic locking) andversion(the content version being approved)
Mutation commands
- All commands:
versionfield renamed torevision(optimistic locking) - All commands:
content_versionfield renamed toversion(where applicable) CreatePlanCommandno longer acceptsstatus— new plans start with no active version
Renamed endpoints
POST /api/v2/plan/{id}/$publish→POST /api/v2/plan/{id}/$mark-publishedPOST /api/v2/plan/{id}/$unpublish→POST /api/v2/plan/{id}/$mark-unpublishedPOST /api/v2/plan/{id}/$revoke→POST /api/v2/plan/{id}/$deactivate
Removed endpoint
POST /api/v2/plan/{id}/$draft— plans start with no active version
Search filters
- Removed
?statusand?approval_statusquery parameters - Added
?is_active=true|false— filter by active/inactive plans - Added
?updated_since=<RFC3339>— filter by last updated timestamp - Added
?published=true|false— filter by publication status for the requesting provider (usesorgnr_parentheader). This can be used by each provider to keep up to date with publication status for plans.
HistoryResponse changes
versionrenamed torevision,content_versionrenamed toversionstatusandapproval_statusfields removed- Added
event_typefield — shows which event produced that snapshot approvalsis now the count of approval entries,publicationsis the count of publication entries
Response to versioned queries
GET /api/v2/plan/{id}/version/{version}now returns the historical content with currentapprovals,publication_status, andactive_versionmerged inGET /api/v2/plan/{id}/historyreturns raw historical snapshots (no merge) for audit purposes
v1.2.2
Released date: 2026-08-19
Motivation
The description field in clinical_content was renamed to better reflect its purpose: capturing the patient's personal goals for the care plan.
Changes
clinical_content.descriptionrenamed toclinical_content.personal_goals(breaking change)
v1.2.1
Released date: 2026-08-03
Motivation
Improve data quality and prevent leaking real national identity numbers (NIN) through the test & dev environment
Changes
We only accept synthetic NINs in the dev & test environment, and we will only accept real NINs in production
v1.2.0
Released date: 2026-07-28
Motivation
Providers need to independently control when a plan is visible to patients in their own systems. The publication workflow enables per-provider publication tracking.
Changes
- Added
POST /api/v2/plan/{id}/$publishto mark plan as published for the requesting provider - Added
POST /api/v2/plan/{id}/$unpublishto mark plan as unpublished for the requesting provider - Publish and unpublish commands require
versionandcontent_versionto specify which content snapshot to publish PlanResponsenow includescontent_version(independent content version counter)PlanResponsenow includespublication_status(array ofPublicationEntryper provider)HistoryResponsenow includescontent_version,approval_status, andpublications(count of publication entries)PublicationEntrymodel:provider_id,status(published/unpublished),content_version,published_at
v1.1.1
Released date: 2026-07-20
Motivation
Improve routing internally in NHN
Changes
All endpoints exposed to clients are prefixed /api/. This means that GET /v2/plan/{id} becomes GET /api/v2/plan/{id} and so on
v1.1.0
Released date: 2026-07-01
Motivation
The CQRS pattern (/write/ and /read/ prefixes) is an internal implementation detail that shouldn't be exposed to API consumers. Additionally, automatic API documentation via Swagger improves developer experience.
Changes
- All v2 endpoints unified under
/v2/prefix, hiding the internal/write/and/read/CQRS separation GET /write/plan/{id}renamed toGET /v2/plan/{id}/$latest- Swagger UI available at
/swagger/ 409 Conflictresponses includeLocationheader pointing to the plan's$latestendpoint
v1.0.0
Released date: 2026-06-30
Motivation
The API has been rewritten with CQRS to separate mutations from queries and added an approval workflow for plan governance.
Changes
- All mutations moved under
/write/plan, all queries under/read/plan - Single
PUT /plan/{id}replaced with dedicated endpoints:$update-content,$draft,$activate,$revoke - New approval workflow:
$approval-requested,$approval-given,$approval-rejected - Read response includes
approval_status,rejection_reason,revoke_reasonfields - Search endpoint supports
approval_statusquery parameter (pending,approved,rejected) - Mutation endpoints return minimal response (
{id, version}); use GET to retrieve full plan - Added
GET /write/plan/{id}for reading from the write model - Documentation moved to
Endpoints_v2.md
v0.4.0
Released date: 2026-06-15
Motivation
Clients need to retrieve a specific historical version of a plan, not just the latest one. This complements the History endpoint (which returns metadata only) by returning the full plan object at a given version.
Changes
- Added
GET /plan/{id}/version/{version}endpoint returning fullResponseobject - Returns
400for invalid UUID or version format,404for plan or version not found
v0.3.0
Released date: 2026-06-12
Motivation
The API now supports retrieving the full version history of a plan, enabling audit trail use cases. Additionally, the Search endpoint now requires the patient parameter to prevent unintended broad queries.
Changes
- Added
GET /plan/{id}/historyendpoint returning[]HistoryResponse - Added
HistoryResponsemodel with fields:version,status,updated_at,updated_by,comment patientquery parameter is now mandatory inSearchendpoint (returns400when missing)
v0.2.0
Released date: 2026-06-12
Motivation
The API model has been refactored to separate request and response. This provides a cleaner public API where server-assigned fields (id, version, updated_at) are not exposed in request bodies, and consumers receive dedicated response objects.
Additionally, the API now enforces optimistic locking via version checking on updates.
Changes
- Split single
Requestmodel intoCreateRequest,UpdateRequest, andResponse - Renamed
planfield toclinical_contentin all requests and responses - Renamed
Planmodel toContent/Clinical Content CreateRequestno longer acceptsversion— assigned by serverUpdateRequestrequiresversion— must match current server version for optimistic lockingUpdateendpoint returns409 Conflicton version mismatch,422 Unprocessable Entityon missing version- Updated
activestatus description to clarify it does NOT imply the plan is approved
v0.1.0
Released date: 2026-06-12
Motivation
Based of the feedback from work meeting 2026-06-11, we have revised which FHIR statuses to include as of now.
Furthermore, we have updated the documentation for the active status
to not imply the plan is approved. This does not currently cause any behavioural changes in the API.
Changes
- Added
Request.statusoptionrevoked - Removed
Request.statusoptionscompletedandon-hold