Handling notifications
Whenever resources are created or updated to match the criteria of an active subscription, the server attempts to POST a notification to the endpoint URL specified in the subscription. Depending on the content field of the subscription, the notification payload may contain different levels of detail about the matching resources. In case of empty content, the notification payload contains no information about the matching resources. In case of id-only co, the notification payload contains the references (i.e., resource type and ID) of the matching resources.
An example notification payload of subscription with empty content looks like this:
{
"resourceType": "Bundle",
"type": "subscription-notification",
"entry": [
{
"resource": {
"resourceType": "SubscriptionStatus",
"status": "active",
"type": "event-notification",
"eventsSinceSubscriptionStart": 113,
"notificationEvent": [
{
"eventNumber": 112
},
{
"eventNumber": 113
}
],
"subscription": {
"reference": "Subscription/42"
}
}
}
]
}
After receiving such a notification, the subscriber needs to send an HTTP request to the /fhir/r5/api/Subscription/${subscription_id}/$events endpoint using the event numbers as specified in the received notification to get the details of the matching resources. Details about this endpoint and the returned response are described in the Fetching notification events page.
For a subscription with id-only content, the notification looks like this:
{
"resourceType": "Bundle",
"type": "subscription-notification",
"entry": [
{
"resource": {
"resourceType": "SubscriptionStatus",
"status": "active",
"type": "event-notification",
"eventsSinceSubscriptionStart": 113,
"notificationEvent": [
{
"eventNumber": 112,
"focus": {
"reference": "Observation/123f1a05-333b-4b62-9c8a-07aa506ccc15"
}
},
{
"eventNumber": 113,
"focus": {
"reference": "Observation/08ab766e-8169-4065-883a-803b1dbd7a97"
}
}
],
"subscription": {
"reference": "Subscription/42"
}
}
}
]
}
The notification endpoint needs to acknowledge the receipt of the handshake by returning an HTTP 200 OK status. After this, the subscriber can fetch the referenced resources by issuing a single request of the following form:
curl -sS -X GET --json @updated-subscription.json "https://${server}/fhir/r5/api/Observation?_id=123f1a05-333b-4b62-9c8a-07aa506ccc15,08ab766e-8169-4065-883a-803b1dbd7a97" \
-H "client_id: ${client_id}" \
-H "client_secret: ${client_secret}" \
-H "org_id: ${org_id}" \
-H "certificate: ${certificate}" | jq
Example response with one successful and one failed result (as indicated by entry.search.mode):
{
"resourceType": "Bundle",
"type": "searchset",
"entry": [
{
"resource": {
"resourceType": "Observation",
"id": "123f1a05-333b-4b62-9c8a-07aa506ccc15",
"meta": {"versionId": "1720619599332", "lastUpdated": "2024-07-10T13:53:19.332+00:00", "profile": ["https://roche.com/fhir/iop/StructureDefinition/rdc-Observation-BG"]},
"status": "final",
"code": {"coding": [{"system": "http://loinc.org", "code": "32016-8", "display": "Glucose [Mass/volume] in Capillary blood"}]},
"subject": {"reference": "Patient/wnvhhuat6vT7s0uQ33Jv0AiOLQheBv1"},
"effectiveTiming": {"event": ["2024-07-10T13:53:17+00:00"]},
"valueQuantity": {"value": 100, "unit": "mg/dL", "system": "http://unitsofmeasure.org", "code": "mg/dL"}
},
"search": {"mode": "match"}
},
{
"resource": {
"resourceType": "OperationOutcome",
"issue": [
{"severity": "error", "code": "forbidden", "diagnostics": "Data sharing is not allowed"},
{"severity": "error", "code": "processing", "details": {"text": "Problem encountered with requested resource Observation/08ab766e-8169-4065-883a-803b1dbd7a97"}}
]
},
"search": {"mode": "outcome"}
}
]
}
A few key points are worth mentioning here:
- The notification endpoint should first save the notification content and acknowledge its receipt and only then should it fetch resources, otherwise it could exceed the maximum timeout. (The default timeout is 10 seconds but can be overridden using the
timeoutfield of the Subscription resource. The maximum allowed value in 20 seconds.) - If the notification endpoint does not return an HTTP 200 OK status in time (i.e., it returns something else or it doesn't return at all), the server will move the subscription to an error state (discussed in a later section).
- Subscribers are encouraged to use the presented way of fetching multiple resources in a single request, instead of fetching them one by one. This significantly reduces the overhead of these operations. Up to 100 ID-s are allowed per request but the 2048 characters total length limit of URL-s also need to be obeyed at the same time.
- Notifications may arrive out of order or multiple times. This is not an error and therefore it should be handled by the subscriber gracefully.
- The same event (with identical content) may get delivered in multiple notification bundles. This is not an error and therefore it should be handled by the subscriber gracefully.
- Multiple events in a single notification bundle may refer to the same resource. In such a case, it is enough to fetch the resource once (but if after fetching the resource, a new event arrives that references it, then it needs be fetched again, because it may have been updated since the last fetch).
Sequence diagram
The notification handling workflow can be represented in a sequence diagram as follows:
