Subscriptions
Fire Arrow Server supports FHIR Subscriptions for real-time notifications when resources change. Define criteria-based subscriptions to receive webhooks, emails, websocket messages, or Azure Storage Queue messages whenever matching resources are created or updated.
Supported Channels
| Channel Type | Description | Use Case |
|---|---|---|
rest-hook | HTTP POST to a URL | Backend integrations, webhooks |
email | Send email notification | Alerts to practitioners, administrators |
websocket | Push via WebSocket connection | Real-time UI updates in web apps |
message | Azure Storage Queue message | Async processing, decoupled architectures |
Creating a Subscription
Create a FHIR Subscription resource with your desired criteria and channel:
REST Hook
curl -X POST http://localhost:8080/fhir/Subscription \
-H "Content-Type: application/fhir+json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"resourceType": "Subscription",
"status": "requested",
"criteria": "Observation?patient=Patient/123",
"channel": {
"type": "rest-hook",
"endpoint": "https://your-app.example.com/webhooks/observations",
"payload": "application/fhir+json",
"header": ["Authorization: Bearer webhook-secret-123"]
},
"end": "2026-06-28T00:00:00Z"
}'
The criteria field uses the same search syntax as FHIR REST search. When a resource matching the criteria is created or updated, Fire Arrow Server sends an HTTP POST to the specified endpoint.
Email
curl -X POST http://localhost:8080/fhir/Subscription \
-H "Content-Type: application/fhir+json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"resourceType": "Subscription",
"status": "requested",
"criteria": "Task?status=failed",
"channel": {
"type": "email",
"endpoint": "mailto:[email protected]",
"payload": "application/fhir+json"
},
"end": "2026-06-28T00:00:00Z"
}'
WebSocket
curl -X POST http://localhost:8080/fhir/Subscription \
-H "Content-Type: application/fhir+json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"resourceType": "Subscription",
"status": "requested",
"criteria": "Encounter?patient=Patient/123&status=in-progress",
"channel": {
"type": "websocket"
},
"end": "2026-06-28T00:00:00Z"
}'
Connect to the WebSocket endpoint at ws://localhost:8080/websocket to receive notifications for this subscription.
Azure Storage Queue
For decoupled, asynchronous processing, Fire Arrow Server can deliver subscription notifications to an Azure Storage Queue:
curl -X POST http://localhost:8080/fhir/Subscription \
-H "Content-Type: application/fhir+json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"resourceType": "Subscription",
"status": "requested",
"criteria": "DiagnosticReport?status=final",
"channel": {
"type": "message"
},
"end": "2026-06-28T00:00:00Z"
}'
By default, messages are delivered to the queue configured in fire-arrow.subscription.azure-queue.queue-name. Each message contains the resource reference and subscription ID, allowing your queue consumer to fetch the full resource.
Per-Subscription Queue Routing
To fan notifications out to different queues from a single Fire Arrow Server, set the Subscription's channel.endpoint to the well-known prefix (channel:fire-arrow-azure-queue by default) followed by :<queue-name>. The endpoint suffix names a separate Azure Storage Queue resource in the same storage account — not a sub-channel inside one queue — so suffix-based routing is deny-by-default: operators must add each acceptable queue name to allowed-override-queues before suffix-based routing takes effect.
fire-arrow:
subscription:
azure-queue:
enabled: true
connection-string: "${AZURE_STORAGE_CONNECTION_STRING}"
queue-name: "fhir-subscription-events"
allowed-override-queues:
- identity-resolution-events
- whatsapp-events
curl -X POST http://localhost:8080/fhir/Subscription \
-H "Content-Type: application/fhir+json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"resourceType": "Subscription",
"status": "requested",
"criteria": "CommunicationRequest?status=active&category=https://example.org/cr-category|identity-resolution-required",
"channel": {
"type": "message",
"endpoint": "channel:fire-arrow-azure-queue:identity-resolution-events",
"payload": "application/fhir+json"
},
"end": "2026-06-28T00:00:00Z"
}'
Endpoint resolution rules:
channel.endpoint | Destination queue |
|---|---|
omitted / blank / channel:fire-arrow-azure-queue | configured queue-name (default queue) |
channel:fire-arrow-azure-queue:<queue-name> and <queue-name> is in allowed-override-queues | <queue-name> (override) |
channel:fire-arrow-azure-queue:<queue-name> and <queue-name> is not in allowed-override-queues | configured queue-name + a warning is logged |
channel:fire-arrow-azure-queue:<invalid-name> | configured queue-name + a warning is logged |
anything else (e.g. an https:// REST Hook URL) | configured queue-name (default queue) |
auto-create-queue controls only the configured default queue at boot. Suffix-derived override queues are not auto-created unless auto-create-override-queues: true is set explicitly. The recommended workflow is to provision per-tenant queues out-of-band (Bicep, Terraform, deploy script) and add their names to allowed-override-queues. If an override queue does not exist when a notification is delivered to it, the delivery is recorded as a permanent failure (counting toward delivery.failure-threshold) so it shows up in subscription health tracking.
Queue names must conform to the Azure Storage Queue naming rules (3-63 chars, lowercase alphanumeric and non-consecutive hyphens, starting and ending with a letter or digit).
The endpoint prefix can be customised via fire-arrow.subscription.azure-queue.endpoint-prefix if you want to carve out a tenant-specific endpoint namespace.
Subscription Lifecycle
Subscriptions go through the following statuses:
requested- you create the Subscription with this statusactive- the server validates and activates the Subscriptionoff- the Subscription'senddate has passederror- too many consecutive delivery failures (configurable threshold)
The end field is required on all Subscriptions. The server enforces a maximum TTL - if your end date exceeds the allowed maximum, the server will reject the Subscription. Use a reasonable end date and renew subscriptions as needed.
Authorization
Subscription creation requires a subscribe authorization rule:
fire-arrow:
authorization:
validation-rules:
- client-role: "Practitioner"
resource: "Subscription"
operation: "subscribe"
validator: "LegitimateInterest"
- client-role: "Patient"
resource: "Subscription"
operation: "subscribe"
validator: "PatientCompartment"
Configuration
Enabling Subscriptions
Enable subscription support in your application.yaml:
hapi:
fhir:
subscription:
resthook_enabled: true
email:
enabled: true
websocket_enabled: true
Azure Storage Queue
To use the Azure Storage Queue channel, configure the queue connection:
fire-arrow:
subscription:
azure-queue:
enabled: true
connection-string: "${AZURE_STORAGE_CONNECTION_STRING}"
queue-name: "fhir-subscription-events"
endpoint-prefix: "channel:fire-arrow-azure-queue"
auto-create-queue: true
| Property | Description | Default |
|---|---|---|
enabled | Enable the Azure Storage Queue channel | false |
connection-string | Azure Storage account connection string | -- |
service-url | Azure Queue service URL (alternative to connection-string when using managed identity) | -- |
credential-mode | Credential type when using service-url (default or managed-identity) | default |
queue-name | Default queue used when a Subscription doesn't specify an override | fhir-subscription-events |
endpoint-prefix | Well-known endpoint prefix that opts a Subscription into per-Subscription routing | channel:fire-arrow-azure-queue |
allowed-override-queues | Allow-list of queue names that may be selected via the endpoint suffix. Empty means no overrides accepted (deny-by-default). See per-Subscription routing. | [] |
auto-create-queue | Auto-create the default queue at boot | true |
auto-create-override-queues | Auto-create suffix-derived override queues on first delivery. Off by default so that an authenticated subscription writer cannot drive Azure into provisioning new queue resources. | false |
override-queue-cache-max-size | Maximum number of distinct override QueueClients kept cached in memory. Bounded LRU; eviction is essentially free. | 256 |
include-full-resource | Include the full FHIR resource payload in each message | true |
payload-format | Serialisation format for the payload (JSON or XML) | JSON |
channel-type | Restrict delivery to a single Subscription channel type (message, rest-hook, or all) | message |
Full Subscription Configuration
hapi:
fhir:
subscription:
resthook_enabled: true
websocket_enabled: true
email:
enabled: true
fire-arrow:
subscription:
azure-queue:
enabled: true
connection-string: "${AZURE_STORAGE_CONNECTION_STRING}"
queue-name: "fhir-subscription-events"
Environment Variable Overrides
| YAML Path | Environment Variable |
|---|---|
hapi.fhir.subscription.resthook_enabled | HAPI_FHIR_SUBSCRIPTION_RESTHOOK_ENABLED |
hapi.fhir.subscription.websocket_enabled | HAPI_FHIR_SUBSCRIPTION_WEBSOCKET_ENABLED |
hapi.fhir.subscription.email.enabled | HAPI_FHIR_SUBSCRIPTION_EMAIL_ENABLED |
fire-arrow.subscription.azure-queue.connection-string | FIRE_ARROW_SUBSCRIPTION_AZURE_QUEUE_CONNECTION_STRING |
fire-arrow.subscription.azure-queue.service-url | FIRE_ARROW_SUBSCRIPTION_AZURE_QUEUE_SERVICE_URL |
fire-arrow.subscription.azure-queue.queue-name | FIRE_ARROW_SUBSCRIPTION_AZURE_QUEUE_QUEUE_NAME |
fire-arrow.subscription.azure-queue.endpoint-prefix | FIRE_ARROW_SUBSCRIPTION_AZURE_QUEUE_ENDPOINT_PREFIX |
fire-arrow.subscription.azure-queue.allowed-override-queues | FIRE_ARROW_SUBSCRIPTION_AZURE_QUEUE_ALLOWED_OVERRIDE_QUEUES |
fire-arrow.subscription.azure-queue.auto-create-queue | FIRE_ARROW_SUBSCRIPTION_AZURE_QUEUE_AUTO_CREATE_QUEUE |
fire-arrow.subscription.azure-queue.auto-create-override-queues | FIRE_ARROW_SUBSCRIPTION_AZURE_QUEUE_AUTO_CREATE_OVERRIDE_QUEUES |
fire-arrow.subscription.azure-queue.override-queue-cache-max-size | FIRE_ARROW_SUBSCRIPTION_AZURE_QUEUE_OVERRIDE_QUEUE_CACHE_MAX_SIZE |
Related
- CarePlan Events - server-side scheduling of CarePlan activities into Task resources, with webhook notifications via subscriptions.
- Custom Operations -
$subscribe-due-eventsconvenience operation for CarePlan subscriptions.