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.

  1. Create an active SubscriptionTopic that defines the resource events and filters.
  2. If the endpoint requires an outbound Authorization header, create an OCI Vault secret and grant the DDFS instance permission to read it.
  3. Create a Subscription in requested status that references the active topic and identifies the REST-hook endpoint.
  4. DDFS returns the created Subscription and then sends the handshake request. The create response does not confirm handshake success.
  5. A successful handshake changes the Subscription status to active. A failed handshake changes it to error.
  6. After activation, matching resource events cause event-notification requests.
  7. Use the type-level or instance-level $status operation to retrieve the current status.
ResourcePurpose in DDFS
SubscriptionTopicDefines the event topic, trigger resource, optional trigger criteria, and filters that subscriptions may use.
SubscriptionRequests REST-hook notifications for a topic.
SubscriptionStatusReports 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, and unknown. Only an active topic can be referenced by a Subscription.
  • Each trigger must identify a supported resource.
  • trigger.queryCriteria.previous and trigger.queryCriteria.current, when present, must use supported FHIR-style search criteria.
  • Every filter declared in trigger.canFilterBy must be supported for the trigger resource.
  • Use either versionAlgorithmString or versionAlgorithmCoding. 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 resourceSupported 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 fieldDDFS behavior
statusMust be requested on create. Clients cannot set active directly.
topicMust be a well-formed URL that resolves to an existing active SubscriptionTopic.
channelTypeMust include rest-hook. Other channel types are rejected.
endpointRequired for REST-hook delivery; must be a publicly routable HTTPS URL that uses port 443.
contentTypeUse application/fhir+json so DDFS sends a FHIR R6 notification Bundle in the request body.
contentOptional. Supported values are empty and id-only. full-resource is rejected.
filterByOptional. Each filter must be declared by a matching topic trigger and supported for that trigger resource.
heartbeatPeriod, timeout, and maxCountOptional. DDFS preserves valid values through create, read, and update operations. Values outside the supported FHIR integer representation are rejected.
parameterOptional outbound headers. Restricted HTTP headers are rejected.
OCI Vault secret extensionOptional 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 https and the endpoint must use port 443.
  • The endpoint must include a host and resolve to a publicly routable address.
  • Header names in Subscription.parameter must 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.
  • Authorization must not be supplied through Subscription.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

ScenarioExpected result
Active topic and valid requested SubscriptionThe Subscription is created in requested status and the handshake is attempted asynchronously.
Topic is not activeThe Subscription is rejected.
content is empty or id-onlyThe Subscription can be accepted.
content is full-resourceThe Subscription is rejected.
Endpoint uses HTTP, is not publicly routable, or does not use port 443The Subscription is rejected.
Subscription.parameter contains AuthorizationThe Subscription is rejected; use the OCI Vault extension.
OCI Vault extension is present without valueStringThe Subscription is rejected.
Handshake receives a 2xx responseThe Subscription status becomes active.
Handshake preparation or delivery failsThe Subscription status becomes error.
A later event notification is unsuccessfulThe event notification is a delivery failure.