From a14fe70a7f156b66ef81f02d07bec43fb2959a67 Mon Sep 17 00:00:00 2001 From: Andrey Fedorov Date: Mon, 22 Jun 2026 18:45:53 +0200 Subject: [PATCH 1/2] docs(run-payerbox): document AidboxTopicDestination event notifications --- SUMMARY.md | 1 + docs/run-payerbox/maintain/README.md | 1 + .../maintain/event-notifications.md | 234 ++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 docs/run-payerbox/maintain/event-notifications.md diff --git a/SUMMARY.md b/SUMMARY.md index 91ffd24..3fd086c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -12,6 +12,7 @@ * [MPF Pipeline](run-payerbox/provider-directory-pipeline.md) * [Maintain](run-payerbox/maintain/README.md) * [Observability](run-payerbox/maintain/observability.md) + * [Event Notifications](run-payerbox/maintain/event-notifications.md) * [Upgrade](run-payerbox/maintain/upgrade.md) * [Interop APIs](interop-apis/README.md) * [Patient Access](interop-apis/patient-access.md) diff --git a/docs/run-payerbox/maintain/README.md b/docs/run-payerbox/maintain/README.md index 231eaa3..3adb4d4 100644 --- a/docs/run-payerbox/maintain/README.md +++ b/docs/run-payerbox/maintain/README.md @@ -5,4 +5,5 @@ Day-2 operations for a running Payerbox deployment. | Page | What it covers | |---|---| | [Observability](observability.md) | Prometheus metrics, BALP audit logs, runbooks | +| [Event Notifications](event-notifications.md) | Push FHIR events to AWS SNS or webhooks via topic-based subscriptions | | [Upgrade](upgrade.md) | Bundle and per-image upgrade, breaking changes, rollback | diff --git a/docs/run-payerbox/maintain/event-notifications.md b/docs/run-payerbox/maintain/event-notifications.md new file mode 100644 index 0000000..5d5cc35 --- /dev/null +++ b/docs/run-payerbox/maintain/event-notifications.md @@ -0,0 +1,234 @@ +# Event Notifications + +Payerbox can push FHIR resource events to external systems as they happen — for example, notifying a downstream system the moment a prior-authorization decision is recorded. This is built on Aidbox **topic-based subscriptions** and is configured entirely through FHIR resources. + +This page is an operator how-to: how to define what to notify on, where to send it, and how to keep that configuration healthy. + +## How it works + +Two resources work together: + +| Resource | Role | +|---|---| +| `AidboxSubscriptionTopic` | The trigger — which resource type, an optional FHIRPath criterion, and which interactions (create / update / delete) fire it. | +| `AidboxTopicDestination` | The sink — where matching events go. Its `kind` selects the transport (AWS SNS or HTTP webhook); `content` controls the payload shape. | + +When a CRUD operation matches a topic's trigger, the engine writes one event per bound destination. Senders drain those events asynchronously, so a slow or unavailable subscriber never blocks the originating FHIR write. + +```mermaid +flowchart LR + write(FHIR write
create / update / delete):::violet2 + topic(AidboxSubscriptionTopic
trigger + FHIRPath):::violet2 + dest(AidboxTopicDestination
SNS or webhook):::violet2 + ext(External system
SNS topic / HTTP endpoint):::yellow2 + + write --> topic --> dest --> ext +``` + +### Delivery guarantees + +Two delivery modes are available, selected by the destination `kind`: + +- **At-least-once** — events are persisted to a database queue and retried until acknowledged. A subscriber may see the same event more than once, so handlers must be idempotent. Use this for anything where a missed notification matters (claim and decision notifications). +- **Best-effort** — fire-and-forget. Lower latency, no retry. Use only where an occasional drop is acceptable. + +## Destination kinds + +| `kind` | Transport | Profile (`meta.profile`) | +|---|---|---| +| `webhook-at-least-once` | HTTP POST to an endpoint | `http://aidbox.app/StructureDefinition/aidboxtopicdestination-webhook-at-least-once` | +| `aws-sns-at-least-once` | AWS SNS, queued + retried | `http://aidbox.app/StructureDefinition/aidboxtopicdestination-aws-sns-at-least-once` | +| `aws-sns-best-effort` | AWS SNS, fire-and-forget | `http://aidbox.app/StructureDefinition/aidboxtopicdestination-aws-sns-best-effort` | +| `custom-aws-sns-at-least-once` | AWS SNS, queued + retried, with reference enrichment | `http://health-samurai.io/fhir/core/StructureDefinition/aidboxtopicdestination-customAWSSNSAtLeastOnceProfile` | +| `custom-aws-sns-best-effort` | AWS SNS, fire-and-forget, with reference enrichment | `http://health-samurai.io/fhir/core/StructureDefinition/aidboxtopicdestination-customAWSSNSBestEffortProfile` | + +The `custom-aws-sns-*` kinds are a Payerbox extension of the AWS SNS senders. When the `aidboxUrl` and `aidboxAuth` parameters are set, the sender resolves the triggering resource's references and ships an enriched payload instead of the bare resource; without those parameters they behave exactly like the plain `aws-sns-*` kinds. + +The `webhook-at-least-once` kind and the plain `aws-sns-*` kinds are shipped by Aidbox and are accepted out of the box. The `custom-aws-sns-*` kinds use Payerbox-specific profiles that must be whitelisted before use — see Step 1 below. + +## Configure a notification + +{% stepper %} +{% step %} +### Whitelist the destination profile (custom SNS kinds only) + +`AidboxTopicDestination` is constrained by an `allow-destinations` rule that lists the accepted `meta.profile` URLs. Built-in kinds (`webhook-at-least-once`, `aws-sns-*`) are already on this list. The Payerbox `custom-aws-sns-*` profiles are not, so they must be added **before** any destination that uses them is created — otherwise the destination is rejected at creation. + +Patch the constraint to include the custom profile URLs: + +{% code title="patch-allow-destinations.json" %} +```json +{ + "resourceType": "Parameters", + "parameter": [ + { + "name": "operation", + "part": [ + {"name": "type", "valueCode": "add"}, + {"name": "path", "valueString": "differential.element.where(id='AidboxTopicDestination.meta.profile').binding.extension.valueSet"}, + {"name": "value", "valueUri": "http://health-samurai.io/fhir/core/StructureDefinition/aidboxtopicdestination-customAWSSNSAtLeastOnceProfile"} + ] + } + ] +} +``` +{% endcode %} + +```bash +curl -sS -u "$ROOT_CLIENT" \ + -H "Content-Type: application/json" \ + -X PATCH "$AIDBOX_URL/fhir/StructureDefinition/AidboxTopicDestination" \ + -d @patch-allow-destinations.json +``` + +Repeat with the `customAWSSNSBestEffortProfile` URL if you use the best-effort variant. The list is additive — each PATCH appends one profile. +{% endstep %} + +{% step %} +### Define the subscription topic + +Declare what to notify on. The `trigger.fhirPathCriteria` narrows the firing condition; omit it to fire on every interaction of the resource type. + +{% code title="subscription-topic.json" %} +```json +{ + "resourceType": "AidboxSubscriptionTopic", + "id": "pas-claimresponse-status", + "url": "http://prior-auth.example.org/SubscriptionTopic/pas-claimresponse-status", + "status": "active", + "description": "Notify when PAS ClaimResponses are created or updated", + "trigger": [ + {"resource": "ClaimResponse", "fhirPathCriteria": "use = 'preauthorization'"} + ] +} +``` +{% endcode %} + +```bash +curl -sS -u "$ROOT_CLIENT" \ + -H "Content-Type: application/json" \ + -X PUT "$AIDBOX_URL/AidboxSubscriptionTopic/pas-claimresponse-status" \ + -d @subscription-topic.json +``` +{% endstep %} + +{% step %} +### Create the topic destination + +Bind a destination to the topic's `url`. Pick the tab that matches your transport. + +{% tabs %} +{% tab title="AWS SNS" %} +{% code title="topic-destination-sns.json" %} +```json +{ + "resourceType": "AidboxTopicDestination", + "id": "pas-claimresponse-sns", + "kind": "custom-aws-sns-at-least-once", + "meta": { + "profile": ["http://health-samurai.io/fhir/core/StructureDefinition/aidboxtopicdestination-customAWSSNSAtLeastOnceProfile"] + }, + "status": "active", + "topic": "http://prior-auth.example.org/SubscriptionTopic/pas-claimresponse-status", + "parameter": [ + {"name": "topicArn", "valueString": "arn:aws:sns:us-east-1:123456789012:pas-claimresponse"}, + {"name": "region", "valueString": "us-east-1"}, + {"name": "batchSize", "valueInteger": 1} + ], + "content": "full-resource" +} +``` +{% endcode %} + +SNS parameters: + +| Parameter | Required | Notes | +|---|---|---| +| `topicArn` | Yes | Target SNS topic ARN. For a FIFO topic (ARN ends in `.fifo`), also set `messageGroupId`. | +| `region` | Yes | AWS region, e.g. `us-east-1`. | +| `accessKeyId` / `secretAccessKey` | No | Explicit credentials. If omitted, the default AWS credential chain is used (IAM role, environment, etc.). `secretAccessKey` is required when `accessKeyId` is set. | +| `endpointOverride` | No | Alternate SNS endpoint URL — used for local testing against an SNS emulator. | +| `messageGroupId` | FIFO only | Required when the topic ARN ends in `.fifo`. | +| `batchSize` | No | At-least-once only; 1–10. Number of events published per batch. | +| `aidboxUrl` / `aidboxAuth` | No | `custom-aws-sns-*` kinds only. Set both to enable reference enrichment; `aidboxAuth` is `username:password` for Basic auth. | + +Prefer the default credential chain (IAM role) in production and avoid putting long-lived `secretAccessKey` values in the destination resource. +{% endtab %} + +{% tab title="HTTP webhook" %} +{% code title="topic-destination-webhook.json" %} +```json +{ + "resourceType": "AidboxTopicDestination", + "id": "pas-claimresponse-webhook", + "kind": "webhook-at-least-once", + "meta": { + "profile": ["http://aidbox.app/StructureDefinition/aidboxtopicdestination-webhook-at-least-once"] + }, + "status": "active", + "topic": "http://prior-auth.example.org/SubscriptionTopic/pas-claimresponse-status", + "parameter": [ + {"name": "endpoint", "valueUrl": "https://downstream.example.org/webhooks/claimresponse"}, + {"name": "timeout", "valueUnsignedInt": 5000} + ], + "content": "full-resource" +} +``` +{% endcode %} + +Webhook parameters: `endpoint` (target URL, required) and `timeout` (per-delivery timeout in milliseconds). If the endpoint requires Basic auth, configure the corresponding Aidbox client with `grant_types: ["basic"]`. +{% endtab %} +{% endtabs %} + +```bash +curl -sS -u "$ROOT_CLIENT" \ + -H "Content-Type: application/json" \ + -X PUT "$AIDBOX_URL/AidboxTopicDestination/pas-claimresponse-sns" \ + -d @topic-destination-sns.json +``` + +`content: "full-resource"` ships the complete triggering resource in the notification. With a `custom-aws-sns-*` kind and `aidboxUrl`/`aidboxAuth` set, the payload additionally carries the resolved referenced resources. +{% endstep %} + +{% step %} +### Verify + +Trigger a matching write and confirm delivery downstream — for SNS, watch the topic's `NumberOfMessagesPublished` metric; for a webhook, check the receiver's logs. Do not rely on the internal event queue to confirm activity: the at-least-once queue is drained and the row deleted on successful delivery, so a healthy pipeline shows an empty queue within seconds. +{% endstep %} +{% endstepper %} + +## Provisioning at deploy time + +In production these resources are typically created from an init-bundle rather than by hand, with environment-variable substitution for environment-specific values (topic ARN, region, credentials). Two ordering rules apply: + +- The `allow-destinations` whitelist PATCH must come **before** any destination that uses a custom profile. +- A subscription topic should exist before the destinations that reference its `url`. + +## Updating a destination + +`AidboxTopicDestination` resources are **immutable** — Aidbox rejects `PUT` and `PATCH` on an existing destination. To change one (a new ARN, a different endpoint), **delete and re-create** it: + +```bash +curl -sS -u "$ROOT_CLIENT" -X DELETE "$AIDBOX_URL/AidboxTopicDestination/pas-claimresponse-sns" +# then re-create with the new configuration (Step 3) +``` + +Re-creation is also what registers the destination with the in-memory delivery engine. A destination that exists in the database but was never created against a running engine (for example, an init-bundle entry that was a no-op because the resource already existed) will not deliver events. If a topic stops firing after a restart, delete and re-create the destination to force re-registration. + +## Gotchas + +- **Handlers must be idempotent.** At-least-once delivery can repeat an event. Deduplicate on the resource id and version, or guard with your own idempotency key. +- **Updates re-fire.** The engine fires on every interaction matching the criterion, including writes your own subscriber makes back into Aidbox. Avoid feedback loops when subscribing to a resource your downstream also updates. +- **Stale configuration does not self-correct.** Because destinations are immutable and init-bundles commonly create them only when absent, a wrong value set at first boot persists silently. Re-create the destination to fix it. + +## Current limitations + +- Destinations cannot be edited in place — every change is delete-and-re-create. +- There is no built-in dead-letter queue; an at-least-once event retries until delivered. +- Reference enrichment is available only on the `custom-aws-sns-*` kinds, not on webhooks. + +## Related + +- [Observability](observability.md) — metrics and audit logs for a running deployment +- [Architecture](../architecture.md) — where notifications fit in the component view +- [PAS](../../prior-auth/pas.md) — the prior-authorization flow that drives most notifications From 8cfc2b7577645343bf56afd1f0c45d640800cec6 Mon Sep 17 00:00:00 2001 From: Andrey Fedorov Date: Tue, 23 Jun 2026 09:46:35 +0200 Subject: [PATCH 2/2] docs(run-payerbox): align Event Notifications page with house style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add description frontmatter, a Prerequisites section, and lead-in linking to Architecture. Move warnings into hint callouts, title code blocks by HTTP method/path, cross-link steps by anchor, and switch the Related section to content-ref cards — matching the deploy and MPF pipeline pages. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../maintain/event-notifications.md | 145 +++++++++--------- 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/docs/run-payerbox/maintain/event-notifications.md b/docs/run-payerbox/maintain/event-notifications.md index 5d5cc35..4b9692c 100644 --- a/docs/run-payerbox/maintain/event-notifications.md +++ b/docs/run-payerbox/maintain/event-notifications.md @@ -1,8 +1,13 @@ -# Event Notifications +--- +description: >- + Push FHIR resource events from Payerbox to AWS SNS or HTTP webhooks using + Aidbox topic-based subscriptions — triggers, destinations, and how to + configure them. +--- -Payerbox can push FHIR resource events to external systems as they happen — for example, notifying a downstream system the moment a prior-authorization decision is recorded. This is built on Aidbox **topic-based subscriptions** and is configured entirely through FHIR resources. +# Event Notifications -This page is an operator how-to: how to define what to notify on, where to send it, and how to keep that configuration healthy. +Payerbox can push FHIR resource events to external systems as they happen — for example, notifying a downstream system the moment a prior-authorization decision is recorded. It is built on Aidbox **topic-based subscriptions** and configured entirely through FHIR resources. For where this sits in the stack, see [Architecture](../architecture.md). ## How it works @@ -16,20 +21,17 @@ Two resources work together: When a CRUD operation matches a topic's trigger, the engine writes one event per bound destination. Senders drain those events asynchronously, so a slow or unavailable subscriber never blocks the originating FHIR write. ```mermaid -flowchart LR - write(FHIR write
create / update / delete):::violet2 - topic(AidboxSubscriptionTopic
trigger + FHIRPath):::violet2 - dest(AidboxTopicDestination
SNS or webhook):::violet2 - ext(External system
SNS topic / HTTP endpoint):::yellow2 - - write --> topic --> dest --> ext +graph LR + W(FHIR write
create / update / delete):::blue2 --> T(AidboxSubscriptionTopic
trigger + FHIRPath):::blue2 + T --> D(AidboxTopicDestination
SNS or webhook):::blue2 + D --> E(External system
SNS topic / HTTP endpoint):::green2 ``` ### Delivery guarantees Two delivery modes are available, selected by the destination `kind`: -- **At-least-once** — events are persisted to a database queue and retried until acknowledged. A subscriber may see the same event more than once, so handlers must be idempotent. Use this for anything where a missed notification matters (claim and decision notifications). +- **At-least-once** — events are persisted to a database queue and retried until acknowledged. A subscriber may see the same event more than once, so handlers must be idempotent. Use this whenever a missed notification matters (claim and decision notifications). - **Best-effort** — fire-and-forget. Lower latency, no retry. Use only where an occasional drop is acceptable. ## Destination kinds @@ -44,19 +46,27 @@ Two delivery modes are available, selected by the destination `kind`: The `custom-aws-sns-*` kinds are a Payerbox extension of the AWS SNS senders. When the `aidboxUrl` and `aidboxAuth` parameters are set, the sender resolves the triggering resource's references and ships an enriched payload instead of the bare resource; without those parameters they behave exactly like the plain `aws-sns-*` kinds. -The `webhook-at-least-once` kind and the plain `aws-sns-*` kinds are shipped by Aidbox and are accepted out of the box. The `custom-aws-sns-*` kinds use Payerbox-specific profiles that must be whitelisted before use — see Step 1 below. +The `webhook-at-least-once` kind and the plain `aws-sns-*` kinds are shipped by Aidbox and accepted out of the box. The `custom-aws-sns-*` kinds use Payerbox-specific profiles that must be whitelisted first — see [step 1](#whitelist-the-destination-profile). + +## Prerequisites + +- Admin access to Aidbox to create the resources below (root client or the admin API). +- A delivery target: for SNS, a topic ARN and either an IAM role on the Aidbox workload or explicit AWS credentials; for a webhook, a reachable HTTP endpoint. ## Configure a notification +Create the resources below with admin credentials. In production they are usually provisioned from an init-bundle — see [Provisioning at deploy time](#provisioning-at-deploy-time). + {% stepper %} {% step %} -### Whitelist the destination profile (custom SNS kinds only) -`AidboxTopicDestination` is constrained by an `allow-destinations` rule that lists the accepted `meta.profile` URLs. Built-in kinds (`webhook-at-least-once`, `aws-sns-*`) are already on this list. The Payerbox `custom-aws-sns-*` profiles are not, so they must be added **before** any destination that uses them is created — otherwise the destination is rejected at creation. +### Whitelist the destination profile -Patch the constraint to include the custom profile URLs: +`AidboxTopicDestination` is constrained by an `allow-destinations` rule listing the accepted `meta.profile` URLs. Built-in kinds (`webhook-at-least-once`, `aws-sns-*`) are already on this list — skip to [step 2](#define-the-subscription-topic) if you use one of them. The Payerbox `custom-aws-sns-*` profiles are not, so they must be added **before** any destination that uses them is created, or the destination is rejected. -{% code title="patch-allow-destinations.json" %} +Patch the constraint to include the custom profile URL: + +{% code title="PATCH /fhir/StructureDefinition/AidboxTopicDestination" %} ```json { "resourceType": "Parameters", @@ -74,22 +84,16 @@ Patch the constraint to include the custom profile URLs: ``` {% endcode %} -```bash -curl -sS -u "$ROOT_CLIENT" \ - -H "Content-Type: application/json" \ - -X PATCH "$AIDBOX_URL/fhir/StructureDefinition/AidboxTopicDestination" \ - -d @patch-allow-destinations.json -``` +The list is additive — repeat the PATCH with the `customAWSSNSBestEffortProfile` URL if you use the best-effort variant. -Repeat with the `customAWSSNSBestEffortProfile` URL if you use the best-effort variant. The list is additive — each PATCH appends one profile. {% endstep %} - {% step %} + ### Define the subscription topic Declare what to notify on. The `trigger.fhirPathCriteria` narrows the firing condition; omit it to fire on every interaction of the resource type. -{% code title="subscription-topic.json" %} +{% code title="PUT /AidboxSubscriptionTopic/pas-claimresponse-status" %} ```json { "resourceType": "AidboxSubscriptionTopic", @@ -104,22 +108,16 @@ Declare what to notify on. The `trigger.fhirPathCriteria` narrows the firing con ``` {% endcode %} -```bash -curl -sS -u "$ROOT_CLIENT" \ - -H "Content-Type: application/json" \ - -X PUT "$AIDBOX_URL/AidboxSubscriptionTopic/pas-claimresponse-status" \ - -d @subscription-topic.json -``` {% endstep %} - {% step %} + ### Create the topic destination Bind a destination to the topic's `url`. Pick the tab that matches your transport. {% tabs %} {% tab title="AWS SNS" %} -{% code title="topic-destination-sns.json" %} +{% code title="PUT /AidboxTopicDestination/pas-claimresponse-sns" %} ```json { "resourceType": "AidboxTopicDestination", @@ -140,23 +138,23 @@ Bind a destination to the topic's `url`. Pick the tab that matches your transpor ``` {% endcode %} -SNS parameters: - -| Parameter | Required | Notes | -|---|---|---| -| `topicArn` | Yes | Target SNS topic ARN. For a FIFO topic (ARN ends in `.fifo`), also set `messageGroupId`. | -| `region` | Yes | AWS region, e.g. `us-east-1`. | -| `accessKeyId` / `secretAccessKey` | No | Explicit credentials. If omitted, the default AWS credential chain is used (IAM role, environment, etc.). `secretAccessKey` is required when `accessKeyId` is set. | -| `endpointOverride` | No | Alternate SNS endpoint URL — used for local testing against an SNS emulator. | -| `messageGroupId` | FIFO only | Required when the topic ARN ends in `.fifo`. | -| `batchSize` | No | At-least-once only; 1–10. Number of events published per batch. | -| `aidboxUrl` / `aidboxAuth` | No | `custom-aws-sns-*` kinds only. Set both to enable reference enrichment; `aidboxAuth` is `username:password` for Basic auth. | - -Prefer the default credential chain (IAM role) in production and avoid putting long-lived `secretAccessKey` values in the destination resource. +| Parameter | Description | +|---|---| +| `topicArn` (required) | Target SNS topic ARN. For a FIFO topic (ARN ends in `.fifo`), also set `messageGroupId`. | +| `region` (required) | AWS region, e.g. `us-east-1`. | +| `accessKeyId`, `secretAccessKey` | Explicit credentials. If omitted, the default AWS credential chain is used (IAM role, environment, etc.). `secretAccessKey` is required when `accessKeyId` is set. | +| `endpointOverride` | Alternate SNS endpoint URL — used for local testing against an SNS emulator. | +| `messageGroupId` | Required when the topic ARN ends in `.fifo`. | +| `batchSize` | At-least-once only; 1–10. Events published per batch. Default `1`. | +| `aidboxUrl`, `aidboxAuth` | `custom-aws-sns-*` kinds only. Set both to enable reference enrichment; `aidboxAuth` is `username:password` for Basic auth. | + +{% hint style="warning" %} +Prefer the default credential chain (an IAM role on the Aidbox workload) in production. Avoid storing a long-lived `secretAccessKey` in the destination resource. +{% endhint %} {% endtab %} {% tab title="HTTP webhook" %} -{% code title="topic-destination-webhook.json" %} +{% code title="PUT /AidboxTopicDestination/pas-claimresponse-webhook" %} ```json { "resourceType": "AidboxTopicDestination", @@ -176,44 +174,45 @@ Prefer the default credential chain (IAM role) in production and avoid putting l ``` {% endcode %} -Webhook parameters: `endpoint` (target URL, required) and `timeout` (per-delivery timeout in milliseconds). If the endpoint requires Basic auth, configure the corresponding Aidbox client with `grant_types: ["basic"]`. +| Parameter | Description | +|---|---| +| `endpoint` (required) | Target URL the event is POSTed to. | +| `timeout` | Per-delivery timeout in milliseconds. | + +If the endpoint requires Basic auth, configure the corresponding Aidbox client with `grant_types: ["basic"]`. {% endtab %} {% endtabs %} -```bash -curl -sS -u "$ROOT_CLIENT" \ - -H "Content-Type: application/json" \ - -X PUT "$AIDBOX_URL/AidboxTopicDestination/pas-claimresponse-sns" \ - -d @topic-destination-sns.json -``` - `content: "full-resource"` ships the complete triggering resource in the notification. With a `custom-aws-sns-*` kind and `aidboxUrl`/`aidboxAuth` set, the payload additionally carries the resolved referenced resources. -{% endstep %} +{% endstep %} {% step %} + ### Verify -Trigger a matching write and confirm delivery downstream — for SNS, watch the topic's `NumberOfMessagesPublished` metric; for a webhook, check the receiver's logs. Do not rely on the internal event queue to confirm activity: the at-least-once queue is drained and the row deleted on successful delivery, so a healthy pipeline shows an empty queue within seconds. +Trigger a matching write and confirm delivery downstream — for SNS, watch the topic's `NumberOfMessagesPublished` metric; for a webhook, check the receiver's logs. + +{% hint style="info" %} +Don't rely on the internal event queue to confirm activity: the at-least-once queue is drained and the row deleted on successful delivery, so a healthy pipeline shows an empty queue within seconds. +{% endhint %} + {% endstep %} {% endstepper %} ## Provisioning at deploy time -In production these resources are typically created from an init-bundle rather than by hand, with environment-variable substitution for environment-specific values (topic ARN, region, credentials). Two ordering rules apply: +In production these resources are created from an init-bundle rather than by hand, with environment-variable substitution for environment-specific values (topic ARN, region, credentials). Two ordering rules apply: - The `allow-destinations` whitelist PATCH must come **before** any destination that uses a custom profile. -- A subscription topic should exist before the destinations that reference its `url`. +- A subscription topic must exist before the destinations that reference its `url`. ## Updating a destination -`AidboxTopicDestination` resources are **immutable** — Aidbox rejects `PUT` and `PATCH` on an existing destination. To change one (a new ARN, a different endpoint), **delete and re-create** it: +{% hint style="warning" %} +`AidboxTopicDestination` resources are **immutable** — Aidbox rejects `PUT` and `PATCH` on an existing destination. To change one (a new ARN, a different endpoint), **delete and re-create** it. +{% endhint %} -```bash -curl -sS -u "$ROOT_CLIENT" -X DELETE "$AIDBOX_URL/AidboxTopicDestination/pas-claimresponse-sns" -# then re-create with the new configuration (Step 3) -``` - -Re-creation is also what registers the destination with the in-memory delivery engine. A destination that exists in the database but was never created against a running engine (for example, an init-bundle entry that was a no-op because the resource already existed) will not deliver events. If a topic stops firing after a restart, delete and re-create the destination to force re-registration. +Re-creation is also what registers the destination with the in-memory delivery engine. A destination that exists in the database but was never created against a running engine — for example, an init-bundle entry that was a no-op because the resource already existed — will not deliver events. If a topic stops firing after a restart, delete and re-create the destination to force re-registration. ## Gotchas @@ -229,6 +228,14 @@ Re-creation is also what registers the destination with the in-memory delivery e ## Related -- [Observability](observability.md) — metrics and audit logs for a running deployment -- [Architecture](../architecture.md) — where notifications fit in the component view -- [PAS](../../prior-auth/pas.md) — the prior-authorization flow that drives most notifications +{% content-ref url="observability.md" %} +[observability.md](observability.md) +{% endcontent-ref %} + +{% content-ref url="../architecture.md" %} +[architecture.md](../architecture.md) +{% endcontent-ref %} + +{% content-ref url="../../prior-auth/pas.md" %} +[pas.md](../../prior-auth/pas.md) +{% endcontent-ref %}