This functionality is available in Aidbox versions 2512 and later and requires FHIR Schema validation engine to be enabled. If you started Aidbox using the Run Aidbox Locally guide, FHIR Schema is already enabled.

For concepts, supported fields, and configuration details, see FHIR Topic-Based Subscriptions.

In this tutorial, we will set up Aidbox to implement the DaVinci PAS SubscriptionTopic (http://hl7.org/fhir/us/davinci-pas/SubscriptionTopic/PASSubscriptionTopic). This topic notifies subscribers when a Prior Authorization response (ClaimResponse) becomes available.

Prerequisites

Step 1: Install the Subscriptions Backport Package

Install the FHIR Subscriptions Backport IG package. This package contains the Subscription profile that Aidbox uses to validate Subscription resources created by clients:

Request:

POST /fhir/$fhir-package-install
Content-Type: application/json

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "package",
      "valueString": "hl7.fhir.uv.subscriptions-backport.r4@1.1.0"
    }
  ]
}

Response:

{
  "resourceType": "Parameters",
  "parameter": [
    {"name": "result", "valueBoolean": true},
    {"name": "package", "part": [
      {"name": "name", "valueString": "hl7.fhir.uv.subscriptions-backport.r4@1.1.0"},
      {"name": "installedCanonicals", "valueInteger": 23}
    ]}
  ]
}

Step 2: Create AidboxSubscriptionTopic

Create an AidboxSubscriptionTopic that implements the PAS SubscriptionTopic logic:

Request:

POST /fhir/AidboxSubscriptionTopic
Content-Type: application/json

{
  "resourceType": "AidboxSubscriptionTopic",
  "url": "http://example.org/SubscriptionTopic/pas-claim-response",
  "status": "active",
  "trigger": [
    {
      "resource": "ClaimResponse",
      "fhirPathCriteria": "status = 'active'",
      "canFilterBy": [
        {
          "description": "Filter by insurer organization",
          "filterParameter": "orgIdentifier",
          "filterDefinitionFhirPathExpression": "insurer",
          "comparator": ["eq"]
        }
      ]
    }
  ]
}

Response:

{
  "url": "http://example.org/SubscriptionTopic/pas-claim-response",
  "status": "active",
  "trigger": [
    {
      "resource": "ClaimResponse",
      "canFilterBy": [
        {
          "comparator": ["eq"],
          "description": "Filter by insurer organization",
          "filterParameter": "orgIdentifier",
          "filterDefinitionFhirPathExpression": "insurer"
        }
      ],
      "fhirPathCriteria": "status = 'active'"
    }
  ],
  "id": "d9c47c9f-c215-4192-80ed-0ee792598445",
  "resourceType": "AidboxSubscriptionTopic",
  "meta": {
    "lastUpdated": "2025-01-05T14:17:39.601439Z",
    "versionId": "4",
    "extension": [
      {
        "url": "ex:createdAt",
        "valueInstant": "2025-01-05T14:17:39.601439Z"
      }
    ]
  }
}

Key Elements

ElementDescription
urlYour internal canonical URL for this topic (NOT the PAS topic URL). This is used to link with AidboxTopicDestination.
trigger.fhirPathCriteriaDefines what "result-available" means in your specific system. In this example, we trigger when ClaimResponse status becomes active. Adjust this expression to match your business logic.
trigger.canFilterBy.filterParameterThe name that subscribers use in their filter criteria. Must match the parameter name defined in the FHIR SubscriptionTopic (e.g., orgIdentifier from PAS SubscriptionTopic ).
trigger.canFilterBy.filterDefinitionFhirPathExpressionFHIRPath expression to extract the filter value from the resource. Here insurer extracts the insurer reference from ClaimResponse.
trigger.canFilterBy.comparatorComparison operators allowed for this filter. Currently only eq (equals) is supported.

Step 3: Create AidboxTopicDestination

Create an AidboxTopicDestination that binds your AidboxSubscriptionTopic to the FHIR SubscriptionTopic URL and enables FHIR Subscription support:

Request:

POST /fhir/AidboxTopicDestination
Content-Type: application/json

{
  "resourceType": "AidboxTopicDestination",
  "meta": {
    "profile": [
      "http://aidbox.app/StructureDefinition/aidboxtopicdestination-fhir-native-topic-based-subscription"
    ]
  },
  "kind": "fhir-native-topic-based-subscription",
  "topic": "http://example.org/SubscriptionTopic/pas-claim-response",
  "status": "active",
  "content": "full-resource",
  "parameter": [
    {
      "name": "subscription-specification-version",
      "valueString": "R4-backported"
    },
    {
      "name": "fhir-topic",
      "valueCanonical": "http://hl7.org/fhir/us/davinci-pas/SubscriptionTopic/PASSubscriptionTopic"
    },
    {
      "name": "number-of-deliverer",
      "valueUnsignedInt": 2
    },
    {
      "name": "keep-events-for-period",
      "valueUnsignedInt": 86400
    }
  ]
}

Response:

{
  "topic": "http://example.org/SubscriptionTopic/pas-claim-response",
  "kind": "fhir-native-topic-based-subscription",
  "status": "active",
  "content": "full-resource",
  "parameter": [
    {
      "name": "subscription-specification-version",
      "valueString": "R4-backported"
    },
    {
      "name": "fhir-topic",
      "valueCanonical": "http://hl7.org/fhir/us/davinci-pas/SubscriptionTopic/PASSubscriptionTopic"
    },
    {
      "name": "number-of-deliverer",
      "valueUnsignedInt": 2
    },
    {
      "name": "keep-events-for-period",
      "valueUnsignedInt": 86400
    }
  ],
  "id": "b5f1b2a3-c4d5-4e6f-8a9b-0c1d2e3f4a5b",
  "resourceType": "AidboxTopicDestination",
  "meta": {
    "profile": [
      "http://aidbox.app/StructureDefinition/aidboxtopicdestination-fhir-native-topic-based-subscription"
    ],
    "lastUpdated": "2025-01-05T14:18:12.345678Z",
    "versionId": "1",
    "extension": [
      {
        "url": "ex:createdAt",
        "valueInstant": "2025-01-05T14:18:12.345678Z"
      }
    ]
  }
}

Key Parameters

ParameterTypeDescription
topic-URL of your AidboxSubscriptionTopic from Step 2.
fhir-topic *valueCanonicalThe canonical FHIR SubscriptionTopic URL that clients will use in their Subscription resources.
subscription-specification-version *valueStringFHIR version of the Subscription spec. Determines the format of notification bundles and operation responses. Currently only R4-backported is supported.
keep-events-for-periodvalueUnsignedIntEvent retention period in seconds for $events operation. If not specified, events are stored indefinitely.
number-of-deliverervalueUnsignedIntNumber of parallel delivery workers (default: 4).

* required

Step 4: Create Test Data

Create the Organization and Patient resources that will be referenced:

Request:

PUT /fhir/Organization/org-1
Content-Type: application/json

{
  "resourceType": "Organization",
  "id": "org-1",
  "name": "Example Insurance Company"
}

Response:

{
  "name": "Example Insurance Company",
  "id": "org-1",
  "resourceType": "Organization",
  "meta": {
    "lastUpdated": "2025-01-05T14:19:00.123456Z",
    "versionId": "1",
    "extension": [
      {
        "url": "ex:createdAt",
        "valueInstant": "2025-01-05T14:19:00.123456Z"
      }
    ]
  }
}

Request:

PUT /fhir/Patient/example
Content-Type: application/json

{
  "resourceType": "Patient",
  "id": "example",
  "name": [{"family": "Test", "given": ["Patient"]}]
}

Response:

{
  "name": [{"family": "Test", "given": ["Patient"]}],
  "id": "example",
  "resourceType": "Patient",
  "meta": {
    "lastUpdated": "2025-01-05T14:19:05.234567Z",
    "versionId": "1",
    "extension": [
      {
        "url": "ex:createdAt",
        "valueInstant": "2025-01-05T14:19:05.234567Z"
      }
    ]
  }
}

Step 5: Create a FHIR Subscription

Now clients can create standard FHIR Subscription resources:

Request:

POST /fhir/Subscription
Content-Type: application/json

{
  "resourceType": "Subscription",
  "id": "pas-subscription-1",
  "meta": {
    "profile": [
      "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription"
    ]
  },
  "status": "requested",
  "reason": "Receive notifications about claim responses for my organization.",
  "criteria": "http://hl7.org/fhir/us/davinci-pas/SubscriptionTopic/PASSubscriptionTopic",
  "_criteria": {
    "extension": [
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
        "valueString": "orgIdentifier=Organization/org-1"
      }
    ]
  },
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://your-endpoint.example.com/webhook",
    "payload": "application/fhir+json",
    "_payload": {
      "extension": [
        {
          "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-payload-content",
          "valueCode": "full-resource"
        }
      ]
    },
    "header": [
      "Authorization: Bearer your-token"
    ],
    "extension": [
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-heartbeat-period",
        "valueUnsignedInt": 60
      },
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-timeout",
        "valueUnsignedInt": 30
      },
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-max-count",
        "valuePositiveInt": 10
      }
    ]
  }
}

Response:

{
  "meta": {
    "profile": [
      "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription"
    ],
    "lastUpdated": "2025-01-05T14:20:00.567890Z",
    "versionId": "1",
    "extension": [
      {
        "url": "ex:createdAt",
        "valueInstant": "2025-01-05T14:20:00.567890Z"
      }
    ]
  },
  "reason": "Receive notifications about claim responses for my organization.",
  "channel": {
    "type": "rest-hook",
    "header": ["Authorization: Bearer your-token"],
    "payload": "application/fhir+json",
    "endpoint": "https://your-endpoint.example.com/webhook",
    "_payload": {
      "extension": [
        {
          "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-payload-content",
          "valueCode": "full-resource"
        }
      ]
    },
    "extension": [
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-heartbeat-period",
        "valueUnsignedInt": 60
      },
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-timeout",
        "valueUnsignedInt": 30
      },
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-max-count",
        "valuePositiveInt": 10
      }
    ]
  },
  "status": "requested",
  "criteria": "http://hl7.org/fhir/us/davinci-pas/SubscriptionTopic/PASSubscriptionTopic",
  "_criteria": {
    "extension": [
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
        "valueString": "orgIdentifier=Organization/org-1"
      }
    ]
  },
  "id": "pas-subscription-1",
  "resourceType": "Subscription"
}

Subscription Elements

ElementDescription
criteriaCanonical URL of the SubscriptionTopic (must match fhir-topic in AidboxTopicDestination)
_criteria.extensionFilter criteria using parameters defined in canFilterBy
channel.typeChannel type: rest-hook
channel.endpointURL to receive notifications
channel.payloadMIME type for notifications
channel._payload.extensionPayload content: full-resource, id-only, or empty
channel.headerCustom HTTP headers for notifications
backport-heartbeat-periodInterval in seconds for sending keep-alive notifications during inactivity. Helps maintain active connection.
backport-timeoutMaximum time in seconds the server will wait before failing a notification delivery attempt.
backport-max-countMaximum number of events to include in a single notification bundle. Events are batched up to this limit before sending.

Step 6: Verify Handshake

After creating the subscription, Aidbox sends a handshake notification to your endpoint. If the handshake succeeds (HTTP 2xx response), the subscription status changes to active.

Check subscription status:

Request:

GET /fhir/Subscription/pas-subscription-1

Response:

{
  "meta": {
    "profile": [
      "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription"
    ],
    "lastUpdated": "2025-01-05T14:20:01.234567Z",
    "versionId": "2",
    "extension": [
      {
        "url": "ex:createdAt",
        "valueInstant": "2025-01-05T14:20:00.567890Z"
      }
    ]
  },
  "reason": "Receive notifications about claim responses for my organization.",
  "channel": {
    "type": "rest-hook",
    "header": ["Authorization: Bearer your-token"],
    "payload": "application/fhir+json",
    "endpoint": "https://your-endpoint.example.com/webhook",
    "_payload": {
      "extension": [
        {
          "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-payload-content",
          "valueCode": "full-resource"
        }
      ]
    },
    "extension": [
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-heartbeat-period",
        "valueUnsignedInt": 60
      },
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-timeout",
        "valueUnsignedInt": 30
      },
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-max-count",
        "valuePositiveInt": 10
      }
    ]
  },
  "status": "active",
  "criteria": "http://hl7.org/fhir/us/davinci-pas/SubscriptionTopic/PASSubscriptionTopic",
  "_criteria": {
    "extension": [
      {
        "url": "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
        "valueString": "orgIdentifier=Organization/org-1"
      }
    ]
  },
  "id": "pas-subscription-1",
  "resourceType": "Subscription"
}

If handshake fails, the subscription status will be error.

Step 7: Trigger Events

Create or update resources matching your topic criteria:

Request:

POST /fhir/ClaimResponse
Content-Type: application/json

{
  "resourceType": "ClaimResponse",
  "status": "active",
  "type": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/claim-type",
        "code": "professional"
      }
    ]
  },
  "use": "preauthorization",
  "patient": {
    "reference": "Patient/example"
  },
  "created": "2024-01-01T00:00:00Z",
  "insurer": {
    "reference": "Organization/org-1"
  },
  "outcome": "complete"
}

Response:

{
  "use": "preauthorization",
  "type": {
    "coding": [
      {
        "code": "professional",
        "system": "http://terminology.hl7.org/CodeSystem/claim-type"
      }
    ]
  },
  "status": "active",
  "created": "2024-01-01T00:00:00Z",
  "insurer": {
    "reference": "Organization/org-1"
  },
  "outcome": "complete",
  "patient": {
    "reference": "Patient/example"
  },
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "resourceType": "ClaimResponse",
  "meta": {
    "lastUpdated": "2025-01-05T14:21:00.123456Z",
    "versionId": "1",
    "extension": [
      {
        "url": "ex:createdAt",
        "valueInstant": "2025-01-05T14:21:00.123456Z"
      }
    ]
  }
}

Your endpoint will receive a notification bundle containing the ClaimResponse.

Using $status Operation

Check subscription status and event counts:

Request:

GET /fhir/Subscription/pas-subscription-1/$status

Response:

{
  "resourceType": "Bundle",
  "type": "history",
  "entry": [
    {
      "resource": {
        "resourceType": "Parameters",
        "parameter": [
          {
            "name": "subscription",
            "valueReference": {
              "reference": "Subscription/pas-subscription-1"
            }
          },
          {
            "name": "status",
            "valueCode": "active"
          },
          {
            "name": "type",
            "valueCode": "query-status"
          },
          {
            "name": "events-since-subscription-start",
            "valueString": "5"
          }
        ]
      }
    }
  ]
}

Using $events Operation

Query past events for recovery:

Request:

POST /fhir/Subscription/pas-subscription-1/$events
Content-Type: application/json

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "eventsSinceNumber",
      "valueString": "1"
    },
    {
      "name": "eventsUntilNumber",
      "valueString": "10"
    },
    {
      "name": "content",
      "valueCode": "full-resource"
    }
  ]
}

Response:

{
  "resourceType": "Bundle",
  "type": "history",
  "entry": [
    {
      "resource": {
        "resourceType": "Parameters",
        "parameter": [
          {
            "name": "subscription",
            "valueReference": {
              "reference": "Subscription/pas-subscription-1"
            }
          },
          {
            "name": "status",
            "valueCode": "active"
          },
          {
            "name": "type",
            "valueCode": "query-event"
          },
          {
            "name": "events-since-subscription-start",
            "valueString": "1"
          }
        ]
      }
    },
    {
      "resource": {
        "use": "preauthorization",
        "type": {
          "coding": [
            {
              "code": "professional",
              "system": "http://terminology.hl7.org/CodeSystem/claim-type"
            }
          ]
        },
        "status": "active",
        "created": "2024-01-01T00:00:00Z",
        "insurer": {
          "reference": "Organization/org-1"
        },
        "outcome": "complete",
        "patient": {
          "reference": "Patient/example"
        },
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "resourceType": "ClaimResponse",
        "meta": {
          "lastUpdated": "2025-01-05T14:21:00.123456Z",
          "versionId": "1"
        }
      }
    }
  ]
}

Limitations

  • No subscription updates: Once created, subscriptions cannot be modified. Delete and recreate if changes are needed.
  • REST-hook only: Currently only the rest-hook channel type is supported.
  • Content level: Subscription's payload content cannot exceed the AidboxTopicDestination's content setting.

See Also

Last updated: