For AI agents: the documentation index is at /docs/aidbox/llms.txt. A Markdown version of this page is available at /docs/aidbox/tutorials/security-access-control-tutorials/how-to-subscribe-to-audit-events.md or by requesting it with the Accept: text/markdown header.
Aidbox Docs

How to subscribe to audit events

This functionality is available starting from version 2609. For earlier versions, see How to configure FHIR Audit Log (deprecated).

Aidbox publishes audit events to a built-in AidboxSubscriptionTopic. You receive them by creating an AidboxTopicDestination on that topic. This tutorial uses a webhook destination; Kafka, GCP Pub/Sub, and the other destination kinds work the same way.

Objectives

  • Subscribe a webhook to the audit events topic.
  • Produce an audit event and inspect the notification.
  • Check delivery status and stop audit logging.

Not all operations generate AuditEvents. See Audit coverage and Known limitations for details.

The audit events topic

PropertyValue
Topic URLhttp://health-samurai.io/fhir/core/StructureDefinition/AuditEventsR4BALP
Event formatFHIR R4 AuditEvent with IHE BALP profiles

The topic ships with Aidbox, so there is no AidboxSubscriptionTopic resource to create. No setting turns audit logging on or off: Aidbox produces audit events while at least one destination is subscribed to the topic.

Create a destination

Create an AidboxTopicDestination with the audit topic URL in the topic element. Replace the endpoint value with the URL of your receiver.

POST /fhir/AidboxTopicDestination
content-type: application/json
accept: application/json

{
  "resourceType": "AidboxTopicDestination",
  "id": "audit-log-webhook",
  "meta": {
    "profile": [
      "http://health-samurai.io/fhir/core/StructureDefinition/aidboxtopicdestination-webhookAtLeastOnceProfile"
    ]
  },
  "kind": "webhook-at-least-once",
  "topic": "http://health-samurai.io/fhir/core/StructureDefinition/AuditEventsR4BALP",
  "content": "full-resource",
  "parameter": [
    {
      "name": "endpoint",
      "valueUrl": "https://audit.example.com/events"
    }
  ]
}

Aidbox responds with 201 Created and starts producing audit events. See Webhook AidboxTopicDestination for the full parameter list, including custom headers, batch size, and timeouts.

Produce an audit event

Run any audited operation, for example create a patient:

PUT /fhir/Patient/pt-1
content-type: application/json
accept: application/json

{
  "name": [{"given": ["John"], "family": "Smith"}]
}

Inspect the notification

Aidbox sends a POST request to the endpoint. The body is a FHIR Bundle of type history. The first entry is an AidboxSubscriptionStatus, and every other entry carries one AuditEvent. The example below shortens the AuditEvent:

{
  "resourceType": "Bundle",
  "type": "history",
  "timestamp": "2026-09-30T10:07:55Z",
  "entry": [
    {
      "resource": {
        "resourceType": "AidboxSubscriptionStatus",
        "status": "active",
        "type": "event-notification",
        "notificationEvent": [
          {
            "eventNumber": 1,
            "focus": {
              "reference": "AuditEvent/1f6f7a5e-2f0f-4f0b-9a3c-0b7a0a1d2c3e"
            }
          }
        ],
        "topic": "http://health-samurai.io/fhir/core/StructureDefinition/AuditEventsR4BALP",
        "topic-destination": {
          "reference": "AidboxTopicDestination/audit-log-webhook"
        }
      }
    },
    {
      "fullUrl": "https://aidbox.example.com/fhir/AuditEvent/1f6f7a5e-2f0f-4f0b-9a3c-0b7a0a1d2c3e",
      "request": {
        "method": "POST",
        "url": "/fhir/AuditEvent"
      },
      "resource": {
        "resourceType": "AuditEvent",
        "id": "1f6f7a5e-2f0f-4f0b-9a3c-0b7a0a1d2c3e",
        "meta": {
          "profile": [
            "https://profiles.ihe.net/ITI/BALP/StructureDefinition/IHE.BasicAudit.PatientCreate"
          ]
        },
        "type": {
          "system": "http://terminology.hl7.org/CodeSystem/audit-event-type",
          "code": "rest",
          "display": "RESTful Operation"
        },
        "subtype": [
          {
            "system": "http://hl7.org/fhir/restful-interaction",
            "code": "create",
            "display": "create"
          }
        ],
        "action": "C",
        "outcome": "0",
        "entity": [
          {
            "what": {
              "reference": "Patient/pt-1"
            }
          }
        ]
      }
    }
  ]
}

Aidbox assigns a random UUID to each AuditEvent id. Use it to deduplicate events on the receiver, because an at-least-once destination can deliver the same event twice.

An operation that touches several patients produces one AuditEvent per patient. A search that returns resources of 100 patients yields 100 events.

See Notification shape for the id-only and empty content modes.

Check delivery status

Use the $status operation to see how many events Aidbox delivered and how many wait in the queue:

GET /fhir/AidboxTopicDestination/audit-log-webhook/$status

If the endpoint is unavailable, the webhook destination keeps events in the queue and retries until delivery succeeds.

Stop audit logging

Delete the destination:

DELETE /fhir/AidboxTopicDestination/audit-log-webhook

Aidbox drops the undelivered events of a deleted destination. Wait until messagesQueued in $status reaches zero before the DELETE if you need them. Once the topic has no destinations, Aidbox stops producing audit events.

Performance considerations

Audit logging costs nothing while the topic has no destinations. With a destination, the cost grows with the number of events per request.

The webhook-at-least-once destination writes every event to the Aidbox database before the request returns:

  • Create, update, and delete operations store the event in the same transaction as the resource change.
  • Read and search operations add one database write per event. A search that returns resources of many patients pays for each of them.

Migrate from the security.audit-log settings

Before 2609, the security.audit-log.enabled setting turned audit logging on, and security.audit-log.repository-url forwarded events to an external repository. Since 2609 these settings are deprecated and no longer control event production.

If you forwarded events to an external repository, create a webhook destination with the same endpoint. Move custom headers from security.audit-log.request-headers to header parameters of the destination, and the batch size from security.audit-log.batch-count to maxMessagesInBatch.

The payload changed. The deprecated sender posted a Bundle of type collection that contained AuditEvent resources only. A topic destination posts a Bundle of type history with an AidboxSubscriptionStatus in the first entry. Check that your repository accepts this shape before you switch.

See How to configure FHIR Audit Log (deprecated) for the previous behavior.

Last updated: