Publisert - 27.08.2026

API Endpoints v2

This API allows healthcare providers to create, update, and manage patient care plans. Each plan tracks clinical zones with recommended actions, maintains a full version history, supports optimistic concurrency control to prevent lost updates, and includes an activation, approval, and publication workflow.


Table of Contents


Environment

Development environment URL (no HelseID): https://planer.dev.nhn.no/

Swagger UI: https://planer.dev.nhn.no/api/swagger/

All requests and responses use Content-Type: application/json.


Activation

A plan has no status enum. Instead, activation is a pointer: active_version is the content version that can currently be shown to patients, or null if the plan has no active version.

  • New plans start with no active version.
  • POST $activate sets active_version to a specific content version.
  • POST $deactivate clears active_version — the plan should no longer be shown to patients.
  • PlanResponse.is_active is true only when the returned content version is the active one.
  • GET /api/v2/plan/{id}/active returns the currently active version (404 if none).

Activation transitions and who made them are recorded in the version history via updated_by, updated_at, and comment.


Approval Lifecycle

Separate from activation, each plan tracks approval state per content version in the approvals array. Each entry has:

  • version — the content version the approval refers to
  • statusrequested, given, or rejected
  • updated_at — when the state was last changed

Approval commands ($approval-requested, $approval-given, $approval-rejected) require both revision (for optimistic locking) and version (the content version being approved). A new content version starts with no approval entry; approving one version does not affect any other version.


Publication Lifecycle

Separate from activation and approval, each plan tracks per-provider publication state in the publication_status array. This allows different providers to independently publish or unpublish a version to their own patient-facing systems.

Each entry has:

  • provider_id — the provider that published or unpublished
  • version — the content version that was published
  • statuspublished or unpublished
  • updated_at — when the state was last changed

When a provider publishes a plan, they specify which content version to publish via $mark-published / $mark-unpublished. The array contains one entry per provider that has published or unpublished the plan.


How Versioning Works

Each plan has two version counters:

Revision (revision):

  • Starts at 1 when the plan is created.
  • Incremented by the server on every mutation.
  • Every mutation (except create) requires the current revision in the request body. If it doesn't match the server's revision, you'll get a 409 Conflict. This prevents lost updates when multiple users edit the same plan simultaneously.

Content version (version):

  • Starts at 1 when the plan is created.
  • Incremented only when clinical content is updated via $update-content.
  • Referenced by $activate, the approval commands, and $mark-published / $mark-unpublished to specify which content snapshot they apply to.

GET endpoints always return the latest content version. Old versions are immutable — once created, a version never changes. Retrieve any past version via GET /api/v2/plan/{id}/version/{version}, which returns the historical content with current approvals, publication_status, and active_version merged in.


Endpoints

For request/response schemas, parameters, and status codes, use the Swagger UI.

Method Path Description
POST /api/v2/plan Create a new plan (starts with no active version)
GET /api/v2/plan/{id}/$latest Latest version from write-side event store
GET /api/v2/plan/{id} Latest version from read-side projection
GET /api/v2/plan/{id}/active Currently active version (404 if none)
GET /api/v2/plan/{id}/version/{version} Specific historical version
GET /api/v2/plan/{id}/history Version history (audit trail)
GET /api/v2/plan?patient={nin} Search plans by patient
POST /api/v2/plan/{id}/$update-content Update clinical content
POST /api/v2/plan/{id}/$activate Set a content version as the active version
POST /api/v2/plan/{id}/$deactivate Clear the active version
POST /api/v2/plan/{id}/$approval-requested Request approval for a content version
POST /api/v2/plan/{id}/$approval-given Grant approval for a content version
POST /api/v2/plan/{id}/$approval-rejected Reject approval for a content version
POST /api/v2/plan/{id}/$mark-published Mark a content version as published for the requesting provider
POST /api/v2/plan/{id}/$mark-unpublished Mark a content version as unpublished for the requesting provider

Search Filters

GET /api/v2/plan requires patient (patient NIN) and supports the following optional filters:

Parameter Values Description
patient NIN Required. Only plans for this patient are returned
is_active true / false Filter by whether the plan has an active version
updated_since RFC3339 timestamp Only plans updated at or after this timestamp
published true / false Filter by publication state for the requesting provider. Requires the orgnr_parent header identifying the provider

Error Response

All error responses use this structure:

{
  "error": "plan not found",
  "code": "NOT_FOUND",
  "details": "extra context"
}
Field Type Description
error string Human-readable error message
code string Machine-readable error code (optional)
details any Optional extra context

Implementation Notes

This API uses CQRS (Command Query Responsibility Segregation) and event sourcing under the hood. The CQRS separation is internal; externally all v2 endpoints are unified under /api/v2/. This provides scalability and consistency guarantees without exposing the CQRS pattern to API consumers.

Søk i Utviklerportalen

Søket er fullført!