Skip to content

CapabilityStatements

A profile tells you what a resource looks like. It does not tell you whether you can ask the server for one. A CapabilityStatement is the artifact that answers the second question: which resource types this endpoint serves, which operations it honours on each, which search parameters a query may rely on, and which profile the instances it returns are served against.

That is the first thing an integrator needs and the last thing a profile can tell them. Reading every StructureDefinition in this specification will not reveal which types an application can reach, because that is not what a StructureDefinition is for.

The one this guide publishes

Statement The question it answers
Server What may an application do against a Nexus EMR FHIR endpoint? Resource types, the interactions offered on each, and the profiles they are served against.

It is kind = requirements. That word matters: it states what a conformant endpoint must offer. It is not a description of any particular deployment, and it is not what a running server returns from /metadata -- an instance publishes its own statement, and may legitimately offer more than this document requires or less of an optional interaction than it declares.

A second statement was published from 1.17.0 to 1.25.1 and has been withdrawn. It declared the vocabulary a Subscription.criteria could draw on, one entry per subscribable type. The content was sound; the carrier was not. A CapabilityStatement expresses a criteria vocabulary only by writing it into rest.resource.searchParam, and that element means "this endpoint serves a REST search on this type with these parameters" -- a different and stronger claim than "a subscription criteria may name these parameters", and one that was not true. The vocabulary, and the constraints that go with it, now live in Subscriptions, which also states plainly that this API does not offer the Subscription type to applications at all.

A canonical URL is an identifier, not an address

Each statement has a canonical URL: https://fhir.apps.health/CapabilityStatement/nexus-emr-server. That string is the artifact's name. It is how a Subscription statement says which server statement it instantiates, how a validator resolves the artifact out of a package, and how two systems agree they mean the same document.

It is not a link. Nothing is served at it, in development or in production. The website is somewhere else entirely, and the page you read the artifact on is the one linked from the table above. A canonical pasted into a browser resolves nowhere -- which is the correct behaviour, not a gap waiting to be filled: an identifier that is also an address is an identifier that breaks when the hosting moves. Canonical URLs covers the base and the rule in full.

So: cite the canonical, link the page. A document that needs to name the artifact writes the canonical in backticks. A document that wants the reader to go and read it links the reference page with a relative .md target.

Reading the resource table

Each statement's page carries one row per resource type. A linked type name has further notes below the table; the rest are fully described by their row.

Interactions

An interaction is one thing an application may do against that type. In R4:

Interaction What it means
read Fetch one resource by its id: GET [base]/Patient/123
search-type Query the type and get a Bundle back: GET [base]/Patient?...
create Post a new resource of that type
update Replace an existing resource of that type
delete Remove one

Exposure is not all-or-nothing, and the interaction list is the only place the answer is stated. Three shapes recur on the server statement: read-only, everything-but-delete, and full. The middle one is the one to notice -- for several types, withdrawal is a status change (entered-in-error, cancelled, revoked) rather than a delete, because destroying the record would be data loss rather than a workflow step. Where an entry is narrower than you would guess, its notes say why.

The server statement's type list and its interactions are derived from the exposure each profile declares for itself, rather than maintained by hand alongside them. A narrowed exposure therefore cannot leave a stale entry behind here.

Search parameters

A searchParam entry declares that a query naming that parameter is part of the contract: the server is expected to honour it and filter on it. A declared _include says the server can return referenced resources in the same Bundle, so a client need not make a second round trip.

What a declared parameter does not promise is anything about the parameters that are absent. A CapabilityStatement declares; it does not exhaustively deny. A type listed with no searchParam block is not a claim that the type supports no searches -- it is a claim that this guide is not yet standing behind any.

That distinction is doing real work here, because the general search surface varies by backing store and this guide will not publish a list it has not measured against each one. Search parameters are therefore declared on a handful of types and not on the rest, and beyond those this guide stands behind no search surface at all.

Two failure modes make this worth caring about rather than filing away. A search naming an unsupported parameter does not error: it returns a bundle computed without the filter, or an empty one, and the caller cannot tell "nothing matched" from "the server ignored what you asked". And a modifier the store silently drops is worse than a missing one -- owner:missing=true against a server that ignores :missing answers with every task, which looks exactly like a match.

Declared is not measured

Read the per-parameter notes on the server statement, because they carry a distinction the FHIR resource has no field for: some declared parameters have been measured against a running store and some have not, and every entry says which it is.

This is deliberate rather than sloppy. Under kind = requirements, a parameter a consuming surface depends on is a requirement whether or not a store has yet been observed to serve it, and telling an implementer "this is required and unverified" is worth more than telling them nothing -- but only for as long as the two are never allowed to blur. Hence the per-parameter labelling.

A measured entry rests on a conformance request that asserts what the filter must exclude, not merely that a request succeeded: a parameter the store dropped would answer with everything, which a request asserting only "some rows came back" would happily accept. An unmeasured entry is a requirement on a conformant server and a risk on a particular one, and a client depending on it should verify the server honours it rather than reading an empty result as an empty set.

The labelling is per parameter and not per type for a concrete reason, and :missing is the case that shows why. It was measured absent on 2026-08-25 -- patient:missing returned the same unfiltered set for true and false -- and measured present on 2026-09-08, directly against the store image, where owner:missing=true returned only the unowned task, owner:missing=false only the owned one, and an unfiltered control returned both. The store's source agrees with the second result.

Two measurements of the same estate disagree, so the honest state is neither "supported" nor "unsupported" but unsettled, and this specification declares nothing on an unsettled question. What has not been measured is the whole chain at once, which is what would settle it. Until then the guidance elsewhere -- filter for unassigned work on the client -- stands, because the cost of trusting a dropped modifier is that every task reads as a match, silently.

Profiled is not exposed

This is the most misread thing about the artifact, so it is worth stating flatly.

Modelling a resource says the estate contains it. Exposing it says an application may reach it. The two are decided separately. This guide profiles more types than the server statement lists, and the ones it models without listing are absent by decision, not by oversight. The absence is the statement: an implementer meeting one of those types in a payload is meeting data this guide describes but does not offer as an API surface, and no SMART scope naming it is granted.

To find them, compare the profile list on the artifacts index against the resource table on the server statement. The reason each one is held back -- and what would decide it differently -- is recorded in that statement's FSH source, linked from its own page.

The reasons are not uniform, which is why there is no single rule to apply instead. Some types are not ordinary REST surfaces at all. Some are access logs, where exposure is a decision taken per consumer rather than inherited from the profile existing. Some ship with the software rather than travelling over the API. And several are simply closed to applications pending an exposure decision, each of which needs a consumer that names the type and the interactions it needs.

See Also