SOAP Report
For product owners and partners: Use this page to understand how SOAP Reports are exposed in the MediKIT API and how this supports referral and care-continuity workflows.
For architects and developers: Use this page to implement patient-scoped SOAP Report retrieval with the correct
Compositionquery shape, scope, and filtering rules.
SOAP Reports (SOEP consultation reports in Dutch) are exposed as FHIR R4 Composition resources in a patient context.
This guide uses SOAP Report as the canonical term to distinguish Composition-based reporting from SOEP-style Observation entries.
This is intended for structured consultation reporting use cases where integrators need narrative + coded context from GP encounters without bespoke HIS integrations.
Where feasible, these Composition resources are modeled to align as closely as possible with relevant Dutch ZIB definitions (MEDMIJ).
What this endpoint is for
Use Composition SOAP Report search when your product needs consultation reporting such as:
- referral context for downstream care providers
- timeline views in patient-facing applications
- care-continuity handovers between systems
Endpoint map
| Use case | Endpoint | Notes |
|---|---|---|
| Search SOAP Reports | GET /v2/{organizationId}/fhir/R4/Patient/{patientId}/Composition | Requires type=http://loinc.org|67781-5, or the SNOMED equivalent under the zib SOAP Report profile |
Required access and parameters
Required scope
composition.read
Required query parameter
| Parameter | Required | Allowed value |
|---|---|---|
type | Yes | http://loinc.org|67781-5, or http://snomed.info/sct|11591000146107 under the zib SOAP Report profile |
If type is missing or uses a different value, the API returns a validation OperationOutcome (422). The two values are not interchangeable: type has to name the code the Composition in the response actually carries, so the SNOMED code goes with _profile and the LOINC code without it.
Supported optional filters
| Parameter | Purpose | Allowed values |
|---|---|---|
_include | Include related resources in the same Bundle | Composition:encounter |
_include:iterate | Follow a reference chain one hop further than _include | Encounter:episode-of-care |
encounter:Encounter.episode-of-care | Restrict SOAP entries to one episode of care | EpisodeOfCare logical ID |
_profile | Shape the response to a profile | http://nictiz.nl/fhir/StructureDefinition/zib-SOAPReport |
_include:iterate=Encounter:episode-of-care returns the EpisodeOfCare behind each included Encounter, so combine it with _include=Composition:encounter. On its own it adds nothing to the Bundle: without an included Encounter there is no reference chain to follow, since a Composition does not reference an EpisodeOfCare itself. An EpisodeOfCare that cannot be resolved is left out of the Bundle rather than failing the request.
Episode name
Composition.title names the episode of care by reference rather than by its human-readable name, and R4 EpisodeOfCare has no element for a name. Ask for the zib SOAP Report profile to get the name:
_profile=http://nictiz.nl/fhir/StructureDefinition/zib-SOAPReport
Asking for it also profiles the resources returned alongside the SOAP Reports against the same zib2020 set, so each included EpisodeOfCare comes back as a zib-EpisodeOfCare carrying its name in an extension:
{
"resourceType": "EpisodeOfCare",
"id": "e07597d4-e9d9-4860-9ef8-a6ab304cf8de",
"meta": {
"profile": ["http://nictiz.nl/fhir/StructureDefinition/zib-EpisodeOfCare"]
},
"extension": [
{
"url": "http://nictiz.nl/fhir/StructureDefinition/ext-EpisodeOfCare.EpisodeOfCareName",
"valueString": "Diabetes mellitus type 2"
}
]
}
The extension rides on the included EpisodeOfCare, so combine _profile with _include=Composition:encounter&_include:iterate=Encounter:episode-of-care — without those there is no EpisodeOfCare in the Bundle to carry it. An episode the source system gives no name gets no extension.
Asking for the profile also makes the response conform to it, which changes the SOAP Report itself in three ways:
-
Composition.meta.profileclaimshttp://nictiz.nl/fhir/StructureDefinition/zib-SOAPReport. -
Composition.typebecomeshttp://snomed.info/sct|11591000146107, the code the profile pins, and no longer carrieshttp://loinc.org|67781-5. This is whytypemust ask for the SNOMED code under the profile: a client matching on the LOINC code has to keep asking for the LOINC one and skip_profile. -
Each
section.codebecomes the SNOMED code the profile binds the SOAP line header to, in place of thehttp://fhir.nl/fhir/NamingSystem/journaalregeltypencoding:Journal line Plain response Under the profile Subjectief ...journaalregeltypen|Shttp://snomed.info/sct|255362007Objectief ...journaalregeltypen|Ohttp://snomed.info/sct|260224007Evaluatie ...journaalregeltypen|Ehttp://snomed.info/sct|129265001Plan ...journaalregeltypen|Phttp://snomed.info/sct|129271007
What the profile costs you
The http://nictiz.nl/fhir/StructureDefinition/code-icpc-1-nl extension on a section, which carries that journal line's ICPC code, is not returned under the profile. The zib places that value on the SOAP line Observation as ext-SOAPReport.SOAPLineCode, and this endpoint references those Observations rather than returning them, so a profiled section has nowhere to put it. If you need the ICPC code, use the plain response.
Omit _profile and the response is exactly what it was before: no meta.profile on the Composition, the LOINC type, the journaalregeltypen section codes with their ICPC extension, and a core EpisodeOfCare with no extension.
Request examples
curl -s \
-H "Authorization: ******" \
"https://dev-api.medikit.nl/v2/{organizationId}/fhir/R4/Patient/{patientId}/Composition?type=http://loinc.org|67781-5"
With encounter include:
curl -s \
-H "Authorization: ******" \
"https://dev-api.medikit.nl/v2/{organizationId}/fhir/R4/Patient/{patientId}/Composition?type=http://loinc.org|67781-5&_include=Composition:encounter"
With encounter include and its episode of care:
curl -s \
-H "Authorization: ******" \
"https://dev-api.medikit.nl/v2/{organizationId}/fhir/R4/Patient/{patientId}/Composition?type=http://loinc.org|67781-5&_include=Composition:encounter&_include:iterate=Encounter:episode-of-care"
With the zib SOAP Report profile, so the included episode of care carries its name:
curl -s \
-H "Authorization: ******" \
"https://dev-api.medikit.nl/v2/{organizationId}/fhir/R4/Patient/{patientId}/Composition?type=http://snomed.info/sct|11591000146107&_profile=http://nictiz.nl/fhir/StructureDefinition/zib-SOAPReport&_include=Composition:encounter&_include:iterate=Encounter:episode-of-care"
With episode-of-care filter:
curl -s \
-H "Authorization: ******" \
"https://dev-api.medikit.nl/v2/{organizationId}/fhir/R4/Patient/{patientId}/Composition?type=http://loinc.org|67781-5&encounter:Encounter.episode-of-care={episodeOfCareId}"
Response shape
Successful responses return a FHIR R4 Bundle (type: searchset) containing SOAP Composition resources for the requested patient context.
Error behavior
| Status | Scenario |
|---|---|
403 | Client lacks composition.read scope or access to the requested patient context |
422 | Missing or unsupported query parameters (for example invalid type or unsupported _include) |
What is supported and what is not
| Supported today | Not supported |
|---|---|
Patient-scoped SOAP Composition search with strict type filter | Generic Composition search without type |
| Optional include of encounter context, and of its episode of care one hop further | Arbitrary _include / _include:iterate values |
| Optional filter by episode of care | Generic create/update/delete for Composition |
_profile=...zib-SOAPReport, which adds the episode name to an included episode of care | Any other _profile value |