Publisert - 01.07.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 approval workflow.


Table of Contents


Environment

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

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

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


Data Model

Create Request

Field Type Description
status string Initial status: draft, active, or revoked
comment string Reason or note for the change
subject object Patient the plan belongs to (read-only after create)
clinical_content object Clinical content

Update Content Request

Field Type Description
version int Required, must match current server version
status string Current plan status
comment string Reason or note for the change
clinical_content object Updated clinical content

Status Change Request

Field Type Description
version int Required, must match current server version
comment string Reason for the status change

Approval Request

Field Type Description
version int Required, must match current server version
comment string Reason or note for the action

Mutation Response

All mutation endpoints (POST) return:

Field Type Description
id string UUID of the plan
version int New version number after the change

To retrieve full plan data, use a GET request.

Response

Field Type Description
id string UUID, assigned by server on create (read-only)
version int Current version number
status string Current status
updated_at string ISO 8601 timestamp, set by server (read-only)
updated_by object Health personnel who last updated the plan
subject object Patient the plan belongs to
clinical_content object Clinical content
approval_status string Approval state: approval_requested, approval_given, approval_rejected, or empty
rejection_reason string Reason provided when approval was rejected
revoke_reason string Reason provided when plan was revoked

Clinical Content

Field Type Description
version int Content version, incremented by server on updates
title string Plan title
description string Plan description
zones array List of clinical zones

Zone

Field Type Description
condition string Clinical condition for this zone
action string Recommended action
level string One of: green, yellow, red

History Response

Lightweight version of Response used by the History endpoint. Omits id, subject, clinical_content, approval_status, rejection_reason, and revoke_reason. Tracks only audit trail metadata.

Field Type Description
version int Version number of this history entry
status string Status at this version
updated_at string ISO 8601 timestamp, when this version was created
updated_by object Health personnel who created this version
comment string Comment for this version

Health Personnel

Field Type Description
hpr_number string HPR identifier
display_name string Full name

Patient

Field Type Description
nin string National identity number

Status Lifecycle

A plan can have one of the following statuses:

  • draft — needs follow up
  • active — can be shown to the patient, does not say whether the plan is approved or not
  • revoked — the plan has been withdrawn

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


Approval Lifecycle

Separate from status, each plan tracks an approval state:

  • (none) — no approval process has been initiated
  • approval_requested — approval has been requested
  • approval_given — approval has been granted
  • approval_rejected — approval has been rejected

The rejection_reason field is populated on the response when approval is rejected.


How Versioning Works

Each plan has a single version counter:

  • Starts at 1 when the plan is created.
  • Incremented by the server on every mutation.
  • GET endpoints always return the latest version.
  • Old versions are immutable — once created, a version never changes. Retrieve any past version via GET /v2/plan/{id}/version/{version}.
  • Every mutation (except create) requires the current version in the request body. If it doesn't match the server's version, you'll get a 409 Conflict. This prevents lost updates when multiple users edit the same plan simultaneously.

Endpoints

Create Plan

Creates a new plan.

POST /v2/plan

Request body:

{
  "status": "draft",
  "comment": "Initial draft",
  "subject": {
    "nin": "12345678901"
  },
  "clinical_content": {
    "title": "Behandlingsplan",
    "description": "Plan for patient with chronic obstructive pulmonary disease",
    "zones": [
      {
        "condition": "Peak flow > 80%",
        "action": "Continue current treatment",
        "level": "green"
      },
      {
        "condition": "Peak flow 50-80%",
        "action": "Increase medication dosage and contact GP within 24 hours",
        "level": "yellow"
      },
      {
        "condition": "Peak flow < 50%",
        "action": "Call emergency services immediately",
        "level": "red"
      }
    ]
  }
}

Responses:

Code Description
201 Created Plan created, returns {id, version}
422 Unprocessable Entity Invalid JSON

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 1
}

curl

curl -X POST https://planer.dev.nhn.no/v2/plan \
  -H "Content-Type: application/json" \
  -d '{
    "status": "draft",
    "comment": "Initial draft",
    "subject": {
      "nin": "12345678901"
    },
    "clinical_content": {
      "title": "Behandlingsplan",
      "description": "Plan for patient with chronic obstructive pulmonary disease",
      "zones": [
        {
          "condition": "Peak flow > 80%",
          "action": "Continue current treatment",
          "level": "green"
        },
        {
          "condition": "Peak flow 50-80%",
          "action": "Increase medication dosage and contact GP within 24 hours",
          "level": "yellow"
        },
        {
          "condition": "Peak flow < 50%",
          "action": "Call emergency services immediately",
          "level": "red"
        }
      ]
    }
  }'

Get Latest Plan

Returns the latest version of a plan by ID (from the mutation side).

GET /v2/plan/{id}/$latest

Path parameters:

Parameter Description
id Plan UUID

Responses:

Code Description
200 OK Returns plan object
400 Bad Request Invalid UUID
404 Not Found Plan not found

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 3,
  "status": "active",
  "updated_at": "2024-03-15T12:00:00Z",
  "updated_by": {
    "hpr_number": "123456789",
    "display_name": "Dr. Hansen"
  },
  "subject": {
    "nin": "12345678901"
  },
  "approval": {
    "status": ""
  },
  "clinical_content": {
    "version": 0,
    "title": "Behandlingsplan",
    "description": "Plan for patient with chronic obstructive pulmonary disease",
    "zones": [
      {
        "condition": "Peak flow > 80%",
        "action": "Continue current treatment",
        "level": "green"
      },
      {
        "condition": "Peak flow 50-80%",
        "action": "Increase medication dosage and contact GP within 24 hours",
        "level": "yellow"
      },
      {
        "condition": "Peak flow < 50%",
        "action": "Call emergency services immediately",
        "level": "red"
      }
    ]
  }
}

curl

curl https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/$latest

Update Content

Updates the clinical content of a plan, creating a new version. The version field must match the current server version; otherwise a 409 Conflict is returned.

POST /v2/plan/{id}/$update-content

Path parameters:

Parameter Description
id Plan UUID

Request body:

{
  "version": 1,
  "status": "draft",
  "comment": "Updated treatment zones",
  "clinical_content": {
    "title": "Updated Behandlingsplan",
    "description": "Revised plan for patient with chronic obstructive pulmonary disease",
    "zones": [
      {
        "condition": "Peak flow > 80%",
        "action": "Continue current treatment",
        "level": "green"
      },
      {
        "condition": "Peak flow 50-80%",
        "action": "Increase medication dosage and contact GP within 24 hours",
        "level": "yellow"
      },
      {
        "condition": "Peak flow < 50%",
        "action": "Call emergency services immediately",
        "level": "red"
      }
    ]
  }
}

Responses:

Code Description
200 OK Content updated, returns {id, version}
400 Bad Request Invalid UUID
404 Not Found Plan not found
409 Conflict Version mismatch — plan was modified by another user; includes Location header pointing to $latest
422 Unprocessable Entity Invalid JSON or missing version field

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 2
}

curl

curl -X POST https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/$update-content \
  -H "Content-Type: application/json" \
  -d '{
    "version": 1,
    "status": "draft",
    "comment": "Updated treatment zones",
    "clinical_content": {
      "title": "Updated Behandlingsplan",
      "description": "Revised plan for patient with chronic obstructive pulmonary disease",
      "zones": [
        {
          "condition": "Peak flow > 80%",
          "action": "Continue current treatment",
          "level": "green"
        },
        {
          "condition": "Peak flow 50-80%",
          "action": "Increase medication dosage and contact GP within 24 hours",
          "level": "yellow"
        },
        {
          "condition": "Peak flow < 50%",
          "action": "Call emergency services immediately",
          "level": "red"
        }
      ]
    }
  }'

Set Draft

Transitions the plan status to draft.

POST /v2/plan/{id}/$draft

Path parameters:

Parameter Description
id Plan UUID

Request body:

{
  "version": 3,
  "comment": "Returned to draft for revision"
}

Responses:

Code Description
200 OK Status changed, returns {id, version}
400 Bad Request Invalid UUID
404 Not Found Plan not found
409 Conflict Version mismatch — plan was modified by another user; includes Location header pointing to $latest
422 Unprocessable Entity Invalid JSON or missing version field

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 4
}

curl

curl -X POST https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/$draft \
  -H "Content-Type: application/json" \
  -d '{
    "version": 3,
    "comment": "Returned to draft for revision"
  }'

Activate Plan

Transitions the plan status to active.

POST /v2/plan/{id}/$activate

Path parameters:

Parameter Description
id Plan UUID

Request body:

{
  "version": 1,
  "comment": "Plan approved and activated"
}

Responses:

Code Description
200 OK Status changed, returns {id, version}
400 Bad Request Invalid UUID
404 Not Found Plan not found
409 Conflict Version mismatch — plan was modified by another user; includes Location header pointing to $latest
422 Unprocessable Entity Invalid JSON or missing version field

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 2
}

curl

curl -X POST https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/$activate \
  -H "Content-Type: application/json" \
  -d '{
    "version": 1,
    "comment": "Plan approved and activated"
  }'

Revoke Plan

Transitions the plan status to revoked. The comment is stored as the revoke reason.

POST /v2/plan/{id}/$revoke

Path parameters:

Parameter Description
id Plan UUID

Request body:

{
  "version": 2,
  "comment": "Plan no longer applicable"
}

Responses:

Code Description
200 OK Status changed, returns {id, version}
400 Bad Request Invalid UUID
404 Not Found Plan not found
409 Conflict Version mismatch — plan was modified by another user; includes Location header pointing to $latest
422 Unprocessable Entity Invalid JSON or missing version field

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 3
}

curl

curl -X POST https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/$revoke \
  -H "Content-Type: application/json" \
  -d '{
    "version": 2,
    "comment": "Plan no longer applicable"
  }'

Request Approval

Initiates the approval process for the plan.

POST /v2/plan/{id}/$approval-requested

Path parameters:

Parameter Description
id Plan UUID

Request body:

{
  "version": 2,
  "comment": "Submitting for approval"
}

Responses:

Code Description
200 OK Approval requested, returns {id, version}
400 Bad Request Invalid UUID
404 Not Found Plan not found
409 Conflict Version mismatch — plan was modified by another user; includes Location header pointing to $latest
422 Unprocessable Entity Invalid JSON or missing version field

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 3
}

curl

curl -X POST https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/$approval-requested \
  -H "Content-Type: application/json" \
  -d '{
    "version": 2,
    "comment": "Submitting for approval"
  }'

Give Approval

Grants approval for the plan.

POST /v2/plan/{id}/$approval-given

Path parameters:

Parameter Description
id Plan UUID

Request body:

{
  "version": 3,
  "comment": "Plan reviewed and approved"
}

Responses:

Code Description
200 OK Approval given, returns {id, version}
400 Bad Request Invalid UUID
404 Not Found Plan not found
409 Conflict Version mismatch — plan was modified by another user; includes Location header pointing to $latest
422 Unprocessable Entity Invalid JSON or missing version field

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 4
}

curl

curl -X POST https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/$approval-given \
  -H "Content-Type: application/json" \
  -d '{
    "version": 3,
    "comment": "Plan reviewed and approved"
  }'

Reject Approval

Rejects the plan's approval request. The comment is stored as the rejection reason.

POST /v2/plan/{id}/$approval-rejected

Path parameters:

Parameter Description
id Plan UUID

Request body:

{
  "version": 3,
  "comment": "Missing required assessment data"
}

Responses:

Code Description
200 OK Approval rejected, returns {id, version}
400 Bad Request Invalid UUID
404 Not Found Plan not found
409 Conflict Version mismatch — plan was modified by another user; includes Location header pointing to $latest
422 Unprocessable Entity Invalid JSON or missing version field

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 4
}

curl

curl -X POST https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/$approval-rejected \
  -H "Content-Type: application/json" \
  -d '{
    "version": 3,
    "comment": "Missing required assessment data"
  }'

Get Plan

Returns the latest version of a plan by ID.

GET /v2/plan/{id}

Path parameters:

Parameter Description
id Plan UUID

Responses:

Code Description
200 OK Returns plan object
400 Bad Request Invalid UUID
404 Not Found Plan not found

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 3,
  "status": "active",
  "updated_at": "2024-03-15T12:00:00Z",
  "updated_by": {
    "hpr_number": "123456789"
  },
  "subject": {
    "nin": "12345678901"
  },
  "clinical_content": {
    "version": 0,
    "title": "Behandlingsplan",
    "description": "Plan for patient with chronic obstructive pulmonary disease",
    "zones": [
      {
        "condition": "Peak flow > 80%",
        "action": "Continue current treatment",
        "level": "green"
      },
      {
        "condition": "Peak flow 50-80%",
        "action": "Increase medication dosage and contact GP within 24 hours",
        "level": "yellow"
      },
      {
        "condition": "Peak flow < 50%",
        "action": "Call emergency services immediately",
        "level": "red"
      }
    ]
  },
  "approval_status": "approval_given",
  "rejection_reason": "",
  "revoke_reason": ""
}

curl

curl https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000

Get Plan Version

Returns a specific historical version of a plan by ID and version number. The returned version is immutable — it reflects the plan exactly as it was at that point in time.

GET /v2/plan/{id}/version/{version}

Path parameters:

Parameter Description
id Plan UUID
version Version number (int)

Responses:

Code Description
200 OK Returns plan object at version
400 Bad Request Invalid UUID or version format
404 Not Found Plan or version not found

Example response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "version": 2,
  "status": "draft",
  "updated_at": "2024-03-15T11:00:00Z",
  "updated_by": {
    "hpr_number": "123456789"
  },
  "subject": {
    "nin": "12345678901"
  },
  "clinical_content": {
    "version": 0,
    "title": "Updated Behandlingsplan",
    "description": "Revised plan for patient with chronic obstructive pulmonary disease",
    "zones": [
      {
        "condition": "Peak flow > 80%",
        "action": "Continue current treatment",
        "level": "green"
      },
      {
        "condition": "Peak flow 50-80%",
        "action": "Increase medication dosage and contact GP within 24 hours",
        "level": "yellow"
      },
      {
        "condition": "Peak flow < 50%",
        "action": "Call emergency services immediately",
        "level": "red"
      }
    ]
  },
  "approval_status": "",
  "rejection_reason": "",
  "revoke_reason": ""
}

curl

curl https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/version/2

Get Plan History

Returns all historical versions of a plan by ID. Returns an empty array if the plan is not found.

GET /v2/plan/{id}/history

Path parameters:

Parameter Description
id Plan UUID

Responses:

Code Description
200 OK Returns array of HistoryResponse objects (empty array if no plan found)
400 Bad Request Invalid UUID format

Example response:

[
  {
    "version": 1,
    "status": "draft",
    "updated_at": "2024-03-15T10:30:00Z",
    "updated_by": {
      "hpr_number": "123456789"
    },
    "comment": "Initial draft"
  },
  {
    "version": 2,
    "status": "draft",
    "updated_at": "2024-03-15T11:00:00Z",
    "updated_by": {
      "hpr_number": "123456789"
    },
    "comment": "Updated treatment plan"
  },
  {
    "version": 3,
    "status": "active",
    "updated_at": "2024-03-15T12:00:00Z",
    "updated_by": {
      "hpr_number": "123456789"
    },
    "comment": "Approved after review"
  }
]

curl

curl https://planer.dev.nhn.no/v2/plan/550e8400-e29b-41d4-a716-446655440000/history

Search Plans

Search plans by patient NIN and/or status. An optional approval_status filter is also supported. Returns the latest version of each matching plan.

GET /v2/plan?patient={nin}&status={status}&approval_status={approval_status}

Query parameters:

Parameter Required Description
patient true Patient NIN
status false One of: draft, active, revoked
approval_status false One of: pending, approved, rejected

Responses:

Code Description
200 OK Returns array of matching plans (empty array if no matches)
400 Bad Request Missing patient parameter, invalid status, or invalid approval_status

Example response:

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "version": 3,
    "status": "active",
    "updated_at": "2024-03-15T12:00:00Z",
    "updated_by": {
      "hpr_number": "123456789"
    },
    "subject": {
      "nin": "12345678901"
    },
    "clinical_content": {
      "version": 0,
      "title": "Behandlingsplan",
      "description": "Plan for patient with chronic obstructive pulmonary disease",
      "zones": [
        {
          "condition": "Peak flow > 80%",
          "action": "Continue current treatment",
          "level": "green"
        },
        {
          "condition": "Peak flow 50-80%",
          "action": "Increase medication dosage and contact GP within 24 hours",
          "level": "yellow"
        },
        {
          "condition": "Peak flow < 50%",
          "action": "Call emergency services immediately",
          "level": "red"
        }
      ]
    },
    "approval_status": "approval_given",
    "rejection_reason": "",
    "revoke_reason": ""
  },
  {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "version": 1,
    "status": "draft",
    "updated_at": "2024-03-14T09:00:00Z",
    "updated_by": {
      "hpr_number": "987654321"
    },
    "subject": {
      "nin": "12345678901"
    },
    "clinical_content": {
      "version": 0,
      "title": "Diabetesplan",
      "description": "Plan for patient with type 2 diabetes",
      "zones": [
        {
          "condition": "Blood glucose 4-7 mmol/L",
          "action": "Continue current treatment",
          "level": "green"
        },
        {
          "condition": "Blood glucose 7-11 mmol/L",
          "action": "Adjust diet and monitor closely",
          "level": "yellow"
        },
        {
          "condition": "Blood glucose > 11 mmol/L",
          "action": "Contact GP immediately",
          "level": "red"
        }
      ]
    },
    "approval_status": "",
    "rejection_reason": "",
    "revoke_reason": ""
  }
]

curl

# Get all plans for patient:
curl "https://planer.dev.nhn.no/v2/plan?patient=12345678901"

# Get all plans for patient with status 'draft':
curl "https://planer.dev.nhn.no/v2/plan?patient=12345678901&status=draft"

# Get all plans for patient with approval_status 'pending':
curl "https://planer.dev.nhn.no/v2/plan?patient=12345678901&approval_status=pending"

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 /v2/. This provides scalability and consistency guarantees without exposing the CQRS pattern to API consumers.

Søk i Utviklerportalen

Søket er fullført!