# Webhook subscriptions report their health, and pause when the endpoint is dead

A subscription now says how its endpoint is doing, emails you when it keeps failing, and is paused after 25 failed deliveries over more than 48 hours.

Aug 12, 2026 · New

Until now a subscription whose endpoint had stopped answering stayed active forever and nobody was told. Each subscription now tracks the deliveries that never got through, tells its owner, and stops trying once the endpoint is clearly gone.

A healthy endpoint is unaffected: any successful delivery resets the count, so occasional failures never add up to a pause.

## What else changed

- **An email at 5 failed deliveries in a row**, with the last error, one per run of failures. A delivery counts as failed once it is given up on: all 5 attempts used, or rejected with a `4xx` that is not retried.
- **A pause at 25 failed deliveries in a row, over a run longer than 48 hours.** Both must hold, so a busy endpoint that fails for an afternoon while you fix it is not paused. The subscription moves to `active: false` with `deactivated_by: beel` and `deactivated_at`, and the owner gets a second email.
- **Reactivating a paused subscription runs a test delivery first.** `PATCH` with `active: true` sends a signed test to your URL: a `2xx` turns it back on, anything else answers `422 WEBHOOK_REACTIVATION_REQUIRES_LIVE_ENDPOINT` and it stays paused. A subscription you turned off yourself (`deactivated_by: owner`) reactivates without a test.
- **The health is on the subscription**: `consecutive_failures`, `last_error` and `last_error_cause`, cleared together by the first successful delivery. `last_used_at` now means the last delivery that **succeeded**, and is `null` if none ever has.
- **Failures carry a stable code.** `failure_cause` on a test result and `last_error_cause` on the subscription take one of `dns`, `connection`, `tls`, `timeout`, `http_client_error`, `http_server_error`, `invalid_url`, `forbidden_target` or `unknown`. Branch on it, never on the wording of `error`, and treat a value you do not know as `unknown`.
- **Creating a subscription tests your endpoint.** The `201` carries `test_delivery`, the result of one signed delivery sent while registering. It never blocks the subscription, which exists and is active whatever it says, and it is `null` when the test could not run.
- **`408` and `429` are retried**, with the same backoff as a `5xx`, since 6 July. Before that they were treated like any other `4xx` and the delivery was dropped. Answer `429` when you need BeeL. to slow down.

## Endpoints

- `POST /v1/accounts/{account_id}/webhooks` — The 201 carries test_delivery
- `PATCH /v1/accounts/{account_id}/webhooks/{webhook_id}` — Reactivating a paused subscription requires a passing test delivery
- `GET /v1/accounts/{account_id}/webhooks/{webhook_id}` — consecutive_failures, last_error, last_error_cause, deactivated_by, deactivated_at

## Where to go next

- [Endpoint health and automatic pause](/webhooks/retries#endpoint-health-and-automatic-pause)
- [Update a webhook subscription](/webhooks/patchAccountWebhookSubscription)

---

Full OpenAPI spec: https://docs.beel.es/api/openapi