IKJ-API Overview
Behavior
In short, FHIR resources submitted to IKJ is stored as they are received, and key information is indexed to enable searching.
Incoming resources are validated to ensure that they are valid FHIR R4 resources - more strict profile validation might be added at a later stage. For now, we have made recommendation on how to use IKJ in this page.
Available environments
| Environment | FQDN |
|---|---|
| Test | api.ikj.test.nhn.no |
Authentication & Authorization
Accessing the IKJ API requires clients to be authenticated using HelseID and DPoP.
| Property | Value | Description |
|---|---|---|
| Audience | nhn:ikj |
Identifies the API |
| Scope | nhn:ikj/api.read |
Access to read endpoints |
| Scope | nhn:ikj/api.write |
Access to write endpoints |
| Claim | helseid://claims/client/claims/orgnr_parent |
Organization you are acting on behalf of |
Supported resource types
| Operation | Patient | EpisodeOfCare | CarePlan |
|---|---|---|---|
Submit: POST /v1/{type} |
✓ | ✓ | ✓ |
Update: PUT /v1/{type}/{resourceId} |
✓ | ✓ | ✓ |
Update: PUT /v1/{type}?identifier=... |
✓ | ||
Read: GET /v1/{type}/{resourceId} |
✓ | ✓ | ✓ |
Search: GET /v1/{type}?... |
✓ | ✓ | ✓ |
Submitting and updating resources
All write requests are processed asynchronously. A request that passes initial validation returns
202 Accepted, and the resource is queued for processing. The Location header contains the URL of a Task
resource that reports the outcome. Poll the Task to find out whether processing succeeded or failed.
Errors are reported in one of two ways:
- A request that cannot be accepted — such as an unparsable body or a malformed parameter — is rejected
immediately with
400 Bad Request. - A request that is accepted but cannot be carried out — such as one referencing a resource that does not exist, or
violating an identifier rule — returns
202, and the failure is reported on the Task.
Resource IDs are assigned by the server and cannot be chosen by the client. A submitted resource's ID is not part
of the 202 response; once processing has succeeded, the Task contains a reference to the resource, such as
Patient/3f9a1c58-2d4b-4e17-8c60-7a5b9e0d1234.
The request body size limit is 900 KB (921,600 bytes); querystring size limit is 2048 bytes.
Resource-specific rules
- A
Patientmust carry at least one identifier with both asystemand avalue; processing of a Patient without one fails. - An
EpisodeOfCare'spatientelement is required and must reference an existing patient. Thepatientreference cannot be changed when updating the resource. - A
CarePlan'ssubjectelement is required and must reference an existing patient. Thesubjectreference cannot be changed when updating the resource.
Updating by resource ID
PUT /v1/{type}/{resourceId} replaces an existing resource.
{resourceId}is the resource ID reported in the Task when resource was created, as described above. A value that is not a well-formed resource ID is rejected with400 Bad Request.- The request body must contain an
ididentical to{resourceId}. A missing or differentidis rejected with400 Bad Request. - A
PUTto a resource that does not exist fails during processing.
A PUT replaces the stored resource in full — it is not a merge. For identifiers, this means the stored set
becomes exactly the set in the request body: an identifier that is omitted is removed, and stops working as a
lookup key. An identifier in the body that is already registered to a different resource of the same type fails
processing — resources are never merged.
Updating by identifier
PUT /v1/{type}?identifier={system}|{value} replaces an existing resource found by identifier instead of resource ID.
It otherwise behaves like updating by resource ID.
- The
identifierparameter must use the full{system}|{value}form, and must match one of the identifiers in the request body; otherwise the request is rejected with400 Bad Request. Since that identifier must be in the body, it is the one identifier this endpoint cannot change — use another identifier or the resource ID to change it. - The
idin the request body is optional. When omitted, the server fills in the ID of the resource found. When present, a mismatch with the resource found fails processing.
Reading single resource
GET /v1/{type}/{resourceId} returns the resource, or 404 Not Found with an OperationOutcome if there is no
match.
Searching for resources
GET /v1/{type}?... returns a FHIR Bundle of type searchset with the matching resources, possibly none. Matching
entries have search.mode = match. The supported search parameters for each resource type are listed in the OpenAPI
document, and may be combined freely; a resource must match all of them.
Pagination
Search results are paged using keyset pagination:
_countcontrols the page size (1–50, default 20)._sortcontrols the sort order:_lastUpdatedfor ascending (default) or-_lastUpdatedfor descending.- When there are more results, the Bundle includes a
nextlink with an opaquecursorparameter. Follow the link viaGETto fetch the next page.
Treat the cursor as opaque — do not decode or modify it. It carries the filters, page size and sort order of the
request that produced it, so combining a cursor with filter parameters, _count or _sort is rejected with
400 Bad Request.
GET /v1/Patient?_count=10&_sort=-_lastUpdated
{
"resourceType": "Bundle",
"type": "searchset",
"link": [
{
"relation": "self",
"url": "https://api.ikj.test.nhn.no/v1/Patient?_count=10&_sort=-_lastUpdated"
},
{
"relation": "next",
"url": "https://api.ikj.test.nhn.no/v1/Patient?cursor=ZXlKTVlYTjB..."
}
]
}
Identifiers and coded elements
IKJ treats three kinds of elements differently, which decides both what you must submit and what you can search for:
- Identifiers (
Patient.identifier,EpisodeOfCare.identifier,CarePlan.identifier) name one specific resource. They are lookup keys, so they must be unambiguous. - Referenced identifiers (
EpisodeOfCare.managingOrganization.identifier) identify a different resource that this one points at. They are written and searched like identifiers, but say nothing about the identity of the resource carrying them. - Coded elements (
EpisodeOfCare.type, and otherCodeableConceptelements as they are introduced) classify a resource. Many resources legitimately share the same code.
Rules for identifiers and referenced identifiers
- Only identifiers with both a
systemand avalueare indexed. An identifier missing either part is stored in the resource as submitted, but cannot be searched for, cannot be used to update by identifier, and takes no part in the uniqueness rule below. - The
systemmay be at most 256 and thevalueat most 64 characters long. A resource carrying a longer one fails processing. - Identifiers are unique: if an identifier is already registered to a different resource of the same type in your organization, processing fails. Referenced identifiers are not unique — many EpisodeOfCare resources may name the same managing organization.
- Searching by identifier is a token search, and may return more than one resource. Only the full
{system}|{value}form of an identifier is guaranteed to match at most one. Updating by identifier requires the full form.
Rules for coded elements
systemandcodeare both optional, but a coding carrying neither is ignored, as nothing could ever match it. ACodeableConceptwith onlytextand nocodingis therefore not searchable.- Coded elements are not unique. A search by code returns every resource carrying it.
Empty values
FHIR does not allow an empty string as an element value — omit the element instead. "system": "" is invalid and
is rejected when the resource is parsed, before any of the rules above are applied.
Token search forms
Search parameters that match an identifier or a coded element are FHIR tokens. For identifiers, read {code} as
{value}:
| Form | Matches |
|---|---|
{code} |
The code in any system |
{system}\|{code} |
The code in that system |
\|{code} |
The code, only where the coding was submitted without a system |
{system}\| |
Any code in that system |
The |{code} form is only supported for coded elements: identifiers without a system are not indexed, so the form
could never match one. It is rejected with 400 Bad Request for identifier search parameters.
A token that is just |, that contains more than one |, or whose system exceeds 256 or code exceeds 64
characters, is rejected with 400 Bad Request. A parameter given with an empty value, such as type=, is treated
as if it were absent.
Search with _include
_include=EpisodeOfCare:patient adds the referenced Patient to the response, with search.mode = include. It is
supported:
- When searching: Each patient is included once per page.
- When reading by resource ID: The response becomes a
searchsetBundle instead of a single EpisodeOfCare.