# Delivery & retries

> Deliveries are dispatched by a background sweep (not real-time) that polls for new events every 5 minutes. Each delivery is a POST to your targetUrl, with…

Source: https://warmerly.com/docs/webhooks/delivery-and-retries

Deliveries are dispatched by a background sweep (not real-time) that polls for new events every 5 minutes. Each delivery is a `POST` to your `targetUrl`, with `content-type: application/json` and the `X-Warmerly-Signature` header:

```json
{
  "id": "9d1e0b7a-5e7b-4f10-b2aa-1c8f0d3e6a4b",
  "type": "score_drop",
  "accountId": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
  "occurredAt": "2026-08-18T09:00:00.000Z",
  "data": { "severity": "warning", "title": "Health score dropped", "body": "...", "scoreBefore": 88, "scoreAfter": 61 }
}
```

`id` is the ID of the underlying event and `occurredAt` is when it was recorded. `data`'s shape varies by `type`. For `score_drop`, `score_floor`, `oauth_disconnected`, `auth_fail` and `dns_changed` it is `{ severity, title, body, scoreBefore, scoreAfter }` (`severity` is `info`, `warning` or `critical`; the score fields can be `null`). For the other event types it is the stored event payload as-is, which is not separately documented per type (see [Known gaps](https://warmerly.com/docs/webhooks/delivery-and-retries#known-gaps-in-this-page)).

- Each delivery is tried up to **3 times** (0.5 s, then 1 s, between attempts). An attempt fails if your endpoint doesn't respond `2xx` within **5 seconds**, or errors.
- Events are delivered in order. An event that fails all 3 attempts is **not redelivered** in a later sweep: the subscription moves on past it.
- A subscription is **automatically disabled** (`active: false`) after **10 consecutive sweeps in which a delivery failed**. Re-enable it with `PATCH .../{id}`.
- Up to 50 events per subscription are delivered per sweep; if you have a burst larger than that, the remainder is delivered on the next sweep.
- Redirects are never followed; a `3xx` response counts as a failure, so respond `2xx` directly from `targetUrl`.
- `lastDeliveryStatus` is `success` or `failed`. On failure `lastDeliveryError` is one of `http_<status>`, `timeout`, `connection_failed`, `unsafe_target_url` or `dns_resolution_failed`.

## Verifying deliveries

Every delivery carries an `X-Warmerly-Signature` header: the hex-encoded HMAC-SHA256 of the raw request body, signed with your subscription's `secret`.

```text
X-Warmerly-Signature: 3f9a7c2e...  (hex-encoded HMAC-SHA256 of the raw body)
```

Verify it by recomputing the HMAC over the exact bytes of the received body and comparing:

```js
const crypto = require("crypto");
const expected = crypto.createHmac("sha256", subscriptionSecret).update(rawBody).digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(receivedSignature));
```

## More from Webhooks

- [Update a subscription](https://warmerly.com/docs/webhooks/update-a-subscription): Currently the only supported update is toggling active, there's no way to change targetUrl or eventTypes in…
- [Delete a subscription](https://warmerly.com/docs/webhooks/delete-a-subscription): Revokes (soft-deletes) the subscription; deliveries stop immediately. Not gated on plan tier, a downgraded…
- [Known gaps in this page](https://warmerly.com/docs/webhooks/known-gaps-in-this-page): Known gaps in this page in the Warmerly Webhooks API reference.
