Subscription — Real-time FHIR subscriptions
R5 rewrote Subscription around the topic concept. No more search-string criteria — instead reusable SubscriptionTopics, for reliable, declarative, auditable notifications.
Purpose
Subscription describes a subscription to a FHIR event stream: creation, update or deletion of resources matching a topic. R5 replaced the old R4 criteria (search string) with SubscriptionTopics referenced via canonical: topics are defined once on the server or in an IG and reused by every Subscription.
When an event matches an active Subscription, the server sends a notification on the
requested channel (channelType): REST hook (webhook), email, SMS,
WebSocket, FHIR message.
Key fields
| Field | Type | Cardinality | Role |
|---|---|---|---|
status | code | 1..1 | Mandatory. requested | active | error | off | entered-in-error. |
topic | canonical(SubscriptionTopic) | 1..1 | Mandatory. Topic to subscribe to. |
reason | string | 0..1 | Human-readable reason. |
end | instant | 0..1 | Expiration date. |
managingEntity | Reference(CareTeam | HealthcareService | Organization | RelatedPerson | Patient | Practitioner | PractitionerRole) | 0..1 | Entity responsible for the Subscription. |
contact | ContactPoint[] | 0..* | Contacts on error. |
filterBy | BackboneElement[] | 0..* | Additional filters on the topic. |
channelType | Coding | 1..1 | Mandatory. Delivery channel. |
endpoint | url | 0..1 | Target URL or address. |
parameter | BackboneElement[] | 0..* | Channel parameters (HTTP headers, etc.). |
heartbeatPeriod | unsignedInt | 0..1 | Heartbeat period (s). |
timeout | unsignedInt | 0..1 | Delivery timeout (s). |
contentType | code | 0..1 | Payload MIME type. |
content | code | 0..1 | empty, id-only, full-resource. |
maxCount | positiveInt | 0..1 | Max events per notification. |
Supported channels
rest-hook— HTTPS POST toendpoint. The most common.websocket— persistent WebSocket connection.email— email toendpoint.sms— SMS toendpointnumber.message— FHIR Bundletype=messagetoendpoint.
JSON example
Subscription to Cardiology service admissions, delivery via REST hook with Bearer token:
{
"resourceType": "Subscription",
"id": "admission-monitor",
"status": "active",
"topic": "http://example.org/SubscriptionTopic/admission",
"reason": "Real-time monitoring of Cardiology service admissions",
"end": "2026-12-31T23:59:59Z",
"managingEntity": { "reference": "Organization/hospital-1" },
"contact": [{
"system": "email",
"value": "ops@hospital-1.example.org"
}],
"filterBy": [{
"resourceType": "Encounter",
"filterParameter": "class",
"comparator": "eq",
"value": "IMP"
}, {
"resourceType": "Encounter",
"filterParameter": "service-provider",
"comparator": "eq",
"value": "Organization/cardiology-dept"
}],
"channelType": {
"system": "http://terminology.hl7.org/CodeSystem/subscription-channel-type",
"code": "rest-hook"
},
"endpoint": "https://app.example.org/fhir/subscriptions/notify",
"parameter": [{
"name": "Authorization",
"value": "Bearer eyJhbGciOiJSUzI1NiIs..."
}],
"heartbeatPeriod": 60,
"timeout": 30,
"contentType": "application/fhir+json",
"content": "id-only",
"maxCount": 20
} Common pitfalls
- No
topic— R5 requires a canonical SubscriptionTopic. The old R4criteriaare not supported without backport. - Non-HTTPS endpoint — strongly discouraged: notifications carry patient data.
- No
contact— if the endpoint stops answering, the server flips Subscription tostatus=errorand tries to notifycontact[]. - Unbounded volume — without strict
maxCountandfilterBy, a Subscription can generate thousands of notifications/hour. content=full-resourceon sensitive data — preferid-onlyand let the client GET the resource via OAuth for traceability.
Related resources
- SubscriptionTopic — definition of the subscribed topic.
- SubscriptionStatus — state of a delivery (handshake, heartbeat, event-notification).
- Bundle — notification format (
type=subscription-notification). - CapabilityStatement — declares supported channels.