Skip to content

Subscriptions

This API does not offer FHIR Subscription. An application cannot register one, and no scope grants access to the type. If you are looking for change notification, read this page before building against an expectation the endpoint will not meet.

That is a statement about the published API surface, not about whether records change. They do, constantly. How an estate propagates its own changes internally is an implementation matter that varies by deployment and is not part of this specification.

What to do instead, today

Poll. A client that needs to know what changed searches for it, using the search parameters the server statement declares for the type, and keeps its own high-water mark.

Two cautions carry over from the server statement and matter more here than in ordinary querying:

  • Search parameters are declared on a handful of types and no others. Their absence elsewhere is not a claim that none are supported, but it does mean this specification does not stand behind them. A parameter a store ignores answers with an unfiltered set rather than an error, which a polling loop reads as "everything changed."
  • _lastUpdated is not declared by this guide on any type. A polling strategy that assumes it is honoured should verify that against the deployment it runs on, not against this document.

Why the type is not exposed

Managing a subscription is not an ordinary REST interaction over record content. Every subscription is a standing instruction to send record content somewhere, so the decision to open that path is taken per consumer rather than inherited from the resource type existing.

The Subscription profile is still published, and that is deliberate: an estate may hold Subscription resources whether or not it offers the type over its API, and a partner meeting one in a payload needs to know its shape. A published profile says the estate contains it. It does not say an application may reach it -- see CapabilityStatements for the distinction, which runs through the whole of this guide.

If a subscription surface is offered later

The rest of this page is design, not a promise. It records the shape a subscription surface would take here, so that an implementer planning for one is not guessing, and so that the constraints below are not rediscovered late. Nothing in it is offered by any current deployment.

Authorization: two permissions, deliberately separate

Managing a Subscription -- creating, reading, amending, revoking it -- is distinct from receiving what it delivers.

Receiving is governed by the ordinary read authorization on the resource type named in the criteria: the right to subscribe to a type is the right to read it, expressed with the scopes the server statement already declares. No separate subscription scope vocabulary exists, and none is needed.

Keeping those apart is what makes an id-only notification the safe default. When channel.payload is absent the notification names a resource without carrying it, and the receiver must fetch it under its own credential -- so authorization happens at the read, where it can be enforced against the caller who is actually asking. When payload is present, record content is pushed to the endpoint and the delivery itself becomes the disclosure.

A subscription outlives the session that created it. A delegated or user credential is short-lived; a subscription is not. Set end -- an open-ended subscription is a standing egress path that survives the reason it was created, and reviewing it later means reviewing channel.endpoint, not only the criteria.

Criteria are a closed vocabulary

R4 makes Subscription.criteria a search expression, which means a criteria can only be validated against a declaration of what search parameters exist. Without one, a criteria naming an unsupported parameter does not fail -- it matches nothing, forever, and silent non-delivery is indistinguishable from a period in which nothing happened.

So the vocabulary is closed: a type that is not declared cannot be subscribed to, and a parameter that is not declared cannot appear in a criteria on that type. The set is opened one entry at a time, when a consumer names one, never speculatively.

Two properties of that vocabulary are worth stating because they are easy to get wrong:

  • Every parameter is a base R4 SearchParameter, named by its canonical. A parameter name does not tell you which element it reads -- patient on a DocumentReference reads subject, date on an Appointment reads start, and date on an Observation reads effective[x] in any of its four types. Restating those by hand is how a criteria silently comes to match a narrower set than the same query would on a conformant server.
  • Choice types expand from base FHIR, not from the profile. A profile may narrow effective[x], but a server holds what it holds: a variant this guide excludes is still legal FHIR and still arrives, so narrowing the criteria to the profile would drop it silently. Matching the wider base list can only ever reach more of the same element.

Being subscribable would also require being exposed. A subscription on a type no application may read would route record content around the read authorization this guide places on it, and the preference for id-only notification would be meaningless for a type that cannot be read. Exposure is necessary, not sufficient: it removes that objection, and nothing more.

Limits that would apply, and are properties of a change feed

  • No transition criteria. There is no way to express "changed into cancelled". A criteria is matched against the resource as it now stands, which is what R4 specifies, so status=cancelled fires on every update where the resource is cancelled -- not only on the update that cancelled it. Implementers porting from a server that offers previous-versus-current criteria should expect more notifications, not fewer.
  • No deletes. A change feed of this shape carries creates and updates. A subscriber cannot learn that a resource was withdrawn, and must not read silence as continued existence.
  • No unbounded replay. Notification history is bounded. A subscriber offline longer than the retention window has a gap it cannot detect from the feed; recovering it means searching for what changed, not replaying.
  • Modifiers are outside the vocabulary. :missing, :not, :above/:below, chaining, reverse chaining (_has), _include and composite parameters are all excluded. A criteria using one would be rejected rather than partially honoured.

A criteria vocabulary is not a search capability

The last point is the one that retired this guide's previous attempt to publish the vocabulary as a second CapabilityStatement. A criteria is evaluated by a subscription layer against each changed resource. That is not the same claim as "this endpoint serves a REST search on that type with those parameters", and CapabilityStatement.rest.resource.searchParam cannot say the first without also saying the second.

Where a deployment fulfils subscriptions by registering a real server-side Subscription on its backing store rather than by evaluating criteria itself, that path additionally requires the store to support both subscriptions and the parameters named. Several stores do not, and a store that accepts a Subscription resource has not thereby agreed to deliver on it.

See Also