FHIR R6 Subscription Workflow
Create a FHIR R6 SubscriptionTopic and Subscription, configure optional REST-hook authorization, complete the handshake, receive event notifications, and retrieve Subscription status.
Workflow overview
DDFS supports REST-hook notification delivery for FHIR R6 Subscriptions. Each notification endpoint must be a publicly routable HTTPS URL that uses port 443.
Use https://<ddfs-instance-id>.ddfs.<region>.oci.oraclecloud.com/api/fhir/r6-ballot4 as the FHIR R6 ballot 4 base URL, replacing the instance and region placeholders with the values for your DDFS instance.
- Create an active
SubscriptionTopicthat defines the resource events and filters. - If the endpoint requires an outbound
Authorizationheader, create an OCI Vault secret and grant the DDFS instance permission to read it. - Create a
Subscriptioninrequestedstatus that references the active topic and identifies the REST-hook endpoint. - DDFS returns the created Subscription and then sends the handshake request. The create response does not confirm handshake success.
- A successful handshake changes the Subscription status to
active. A failed handshake changes it toerror. - After activation, matching resource events cause event-notification requests.
- Use the type-level or instance-level
$statusoperation to retrieve the current status.
| Resource | Purpose in DDFS |
|---|---|
SubscriptionTopic | Defines the event topic, trigger resource, optional trigger criteria, and filters that subscriptions may use. |
Subscription | Requests REST-hook notifications for a topic. |
SubscriptionStatus | Reports status through the type-level and instance-level Subscription/$status operations and appears in REST-hook notification bundles. |
Create a SubscriptionTopic
Use Create SubscriptionTopic to create the topic before creating a Subscription. The topic must be active before a Subscription can reference it.
{
"resourceType": "SubscriptionTopic",
"url": "https://<ddfs-instance-id>.ddfs.<region>.oci.oraclecloud.com/api/fhir/r6-ballot4/SubscriptionTopic/device-create",
"status": "active",
"title": "Device create events",
"trigger": [
{
"resource": "Device",
"supportedInteraction": [
"create"
],
"canFilterBy": [
{
"resource": "Device",
"filterParameter": "manufacturer"
}
]
}
]
}
In this example, device-create is a customer-defined name within the topic's canonical url. It is not the DDFS resource ID. DDFS assigns the resource ID when it creates the topic; use the returned ID in read, update, and delete request URLs.
- Use a stable, absolute canonical URL under a namespace that you control. Choose a value that globally identifies the topic.
- Canonical URLs are case-sensitive. Avoid spaces, vertical bars (
|), and hash characters (#). - A short lowercase name with words separated by hyphens, such as
device-create, is recommended for readability; DDFS does not assign a special meaning to that naming pattern. - Supported topic statuses are
draft,active,retired, andunknown. Only an active topic can be referenced by a Subscription. - Each trigger must identify a supported resource.
trigger.queryCriteria.previousandtrigger.queryCriteria.current, when present, must use supported FHIR-style search criteria.- Every filter declared in
trigger.canFilterBymust be supported for the trigger resource. - Use either
versionAlgorithmStringorversionAlgorithmCoding. A topic cannot contain both alternatives. - Unsupported resources, search parameters, or field values are rejected with an
OperationOutcome.
Supported topic filter parameters
The following canFilterBy parameters are supported for SubscriptionTopic trigger resources. Base Resource parameters _id and _tag can apply across resources.
| Trigger resource | Supported filter parameters |
|---|---|
Device | _id, _tag, identifier, manufacturer, model, status, type |
DeviceAssociation | _id, _tag, device, patient, status, subject |
Encounter | _id, _tag, class, location, patient, status, type |
Location | _id, _tag, status |
Observation | _id, _tag, category, code, device, encounter, patient, status |
Patient | _id, _tag, identifier |
Practitioner | _id, _tag, identifier |
Modifier support is intentionally narrow. Device string filters manufacturer and model support :exact. Resource _tag supports :not. Most token and reference filters do not support modifiers.
Configure notification authorization
If the REST-hook endpoint requires an outbound Authorization header, store the complete header value in an OCI Vault secret. Grant the DDFS instance permission to read that specific secret, and add the secret extension to the Subscription.
For the extension contract and fragment, see FHIR R6 Subscription OCI Vault Secret Extension. For the required resource-principal policy, see Grant DDFS Access to a Subscription Authorization Secret.
Omit the extension when the endpoint does not require an outbound Authorization header.
Create a Subscription
Use Create Subscription to create a FHIR R6 Subscription that references the active topic.
| Subscription field | DDFS behavior |
|---|---|
status | Must be requested on create. Clients cannot set active directly. |
topic | Must be a well-formed URL that resolves to an existing active SubscriptionTopic. |
channelType | Must include rest-hook. Other channel types are rejected. |
endpoint | Required for REST-hook delivery; must be a publicly routable HTTPS URL that uses port 443. |
contentType | Use application/fhir+json so DDFS sends a FHIR R6 notification Bundle in the request body. |
content | Optional. Supported values are empty and id-only. full-resource is rejected. |
filterBy | Optional. Each filter must be declared by a matching topic trigger and supported for that trigger resource. |
heartbeatPeriod, timeout, and maxCount | Optional. DDFS preserves valid values through create, read, and update operations. Values outside the supported FHIR integer representation are rejected. |
parameter | Optional outbound headers. Restricted HTTP headers are rejected. |
| OCI Vault secret extension | Optional root-level extension. A Subscription can contain at most one instance. |
Configure the fields in the preceding table for your topic, receiver, and authorization requirements. Validate that the HTTPS receiver is ready to accept the handshake before creating a production Subscription.
Subscription filters
Each Subscription.filterBy entry must use a filter declared by a matching trigger in the referenced SubscriptionTopic. The filter must also be supported for that trigger resource. If no trigger supports the provided filters, the Subscription is rejected.
A filterBy entry can contain one or more event CodeableConcept values. DDFS preserves multiple event values in the supplied order.
REST-hook endpoint and header requirements
- The endpoint URI must be absolute and non-opaque.
- The endpoint scheme must be
httpsand the endpoint must use port 443. - The endpoint must include a host and resolve to a publicly routable address.
- Header names in
Subscription.parametermust be valid HTTP token names. - Header values must be present and must not contain CR or LF characters.
- Hop-by-hop, proxy, routing, content, cookie, and authorization-related headers are blocked.
- Header names beginning with
x-forwarded-are blocked. Authorizationmust not be supplied throughSubscription.parameter.
Handshake and event notification delivery
After returning the created Subscription, DDFS sends an HTTP POST handshake request to the endpoint. Supported Subscription.parameter entries are copied as outbound headers. When configured, the OCI Vault extension supplies the outbound Authorization header.
With contentType=application/fhir+json, the request body is a FHIR R6 Bundle with type=subscription-notification. The Bundle contains a SubscriptionStatus resource with type=handshake.
Any 2xx handshake response changes the Subscription status to active. A request-preparation, secret-resolution, transport, or non-2xx response failure changes the status to error. DDFS does not follow redirects.
After activation, a matching resource event causes an HTTP POST event notification. Its notification Bundle contains SubscriptionStatus.type=event-notification. An unsuccessful later notification is a delivery failure; it is not another handshake status transition.
Retrieve Subscription status
Use GET /api/fhir/r6-ballot4/Subscription/$status to retrieve status for subscriptions, or GET /api/fhir/r6-ballot4/Subscription/{rid}/$status to retrieve status for one Subscription. The type-level operation accepts optional status and id parameters; repeat id to request multiple logical IDs.
Although these operations are invoked on Subscription, authorization requires both SubscriptionStatus and Subscription authority. For the type-level operation, grant and request ddfssystem/SubscriptionStatus.s and ddfssystem/Subscription.s; for the instance-level operation, use ddfssystem/SubscriptionStatus.r and ddfssystem/Subscription.r. Issued access tokens contain the corresponding system/SubscriptionStatus.s and system/Subscription.s pair, or the corresponding system/SubscriptionStatus.r and system/Subscription.r pair. If the token includes the SubscriptionStatus scope but omits the matching Subscription scope, the operation can return HTTP 200 with an empty search-set Bundle instead of HTTP 403 because no Subscription results are authorized.
These operations return a FHIR search-set Bundle. Each matching entry has a fullUrl and contains a SubscriptionStatus with the Subscription reference, topic, current status, type=query-status, and eventsSinceSubscriptionStart. A result can report status=error without an error element. SubscriptionStatus is an operation result, not a separately managed CRUD resource.
Expected results
| Scenario | Expected result |
|---|---|
| Active topic and valid requested Subscription | The Subscription is created in requested status and the handshake is attempted asynchronously. |
| Topic is not active | The Subscription is rejected. |
content is empty or id-only | The Subscription can be accepted. |
content is full-resource | The Subscription is rejected. |
| Endpoint uses HTTP, is not publicly routable, or does not use port 443 | The Subscription is rejected. |
Subscription.parameter contains Authorization | The Subscription is rejected; use the OCI Vault extension. |
OCI Vault extension is present without valueString | The Subscription is rejected. |
| Handshake receives a 2xx response | The Subscription status becomes active. |
| Handshake preparation or delivery fails | The Subscription status becomes error. |
| A later event notification is unsuccessful | The event notification is a delivery failure. |