> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bbrands.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Outbound webhooks

> First release of signed outbound webhooks in horizon-api.

<Update label="2026-09-16" description="Replay keeps the delivery attempt counter">
  Operator replay of a `webhook_dispatch` row no longer resets `attempts`.
  The next POST increments the same lifetime counter so Entregas and the
  subscriber `attempt` field keep a full history. Automatic retries still
  stop at five POSTs; replaying an `exhausted` row performs one additional
  POST. See [Retries and failures](/webhooks/retries-and-failures).
</Update>

<Update label="2026-09-11" description="Outbound webhooks — first release">
  ## Outbound webhooks (first release)

  `horizon-api` now notifies external systems when a resource changes.

  **What shipped**

  * **Event catalogue** generated from the v3 route tree
    (`<resource>.<action>`), synced to the `event` table on every
    deploy and checked in CI. See the
    [catalogue](/webhooks/event-catalogue).
  * **Subscriptions** — global or per-account webhooks with a one-shot
    `whsec_` secret, `PUT /webhook/webhook/{id}/events` to manage the event
    set, secret rotation and test deliveries.
    See [Subscriptions](/webhooks/subscriptions).
  * **Signed deliveries** — `x-bbrands-signature: t=<ts>,v1=<hmac>` over
    `<ts>.<raw body>`, 300 s tolerance, thin body with `api_version`
    `2026-09-11`. See [Delivery and signature](/webhooks/delivery-and-signature).
  * **Retries** — `1 m → 5 m → 30 m → 2 h`, then `exhausted`; automatic
    disable after 20 consecutive failed deliveries; operator replay with
    `confirm_duplicate`. See [Retries and failures](/webhooks/retries-and-failures).
  * **Operations** — `GET /webhook/dashboard/summary`,
    `GET /webhook/catalogue/status`, health component `webhook-out`, metric
    `webhook_out_deliveries_total{status}`, development/certification sink.
    See [Operations](/webhooks/operations).
  * **API reference** — every webhook endpoint documented from a real
    OpenAPI spec: [Webhook](/api-reference/webhook/webhook/find-all),
    [Webhook Event](/api-reference/webhook/webhook-event/find-all),
    [Webhook Dispatch](/api-reference/webhook/webhook-dispatch/find-all),
    [Event](/api-reference/webhook/event/find-all).

  **Breaking / migration notes**

  * Webhooks created before this release are disabled with
    `disabled_reason = "legacy-secret-rotation-required"`. Rotate the secret,
    deploy it on the subscriber, then activate.
  * Callback URLs must be HTTPS on a public host. Existing rows that no
    longer pass validation are rejected on the next update.
  * Publishing is behind `ENABLE_API_EVENT_QUEUE`, enabled per environment
    by the platform team after the catalogue sync.
  * Redirects (`3xx`) are never followed and count as terminal failures.

  **Schema** — migration `0236` splits the `webhook-in` / `webhook-out`
  queue lanes; `0237` adds `webhook.is_global`, `description`,
  `consecutive_failures`, `disabled_at`, `disabled_reason`, makes
  `webhook.account` nullable, renames `webhook_dispatch.retry` to `attempts`
  and adds `event.account_scope`, `method`, `route`. See the
  [Webhook schema](/schemas/webhook/webhook).
</Update>
