---
title: Delivery and retries
description: When a delivery counts as delivered, how it is retried for about 24 hours, when a webhook is disabled without notice, and what to answer so it is not.
canonical: https://developers.coevera.com/webhooks/delivery-and-retries/
section: webhooks
publisher: Coevera
---

# Delivery and retries

**Answer:** A delivery succeeds on any 2xx within 10 seconds. Otherwise it is retried up to 10 times, 11 attempts over about 24 hours with exponential backoff. A 403 or 410 disables the webhook at once; running out of retries disables it too, silently. Deliveries are not ordered, and deleting a webhook sends DELETE to its URL.

## Success

A delivery is one `POST` of a chunk of events to the webhook's URL. It counts as delivered when
your endpoint answers any 2xx status within 10 seconds. Any other status, a timeout or a refused
connection counts as a failure. Redirects are followed and the last response's status counts, so
register the final URL.

Answer first, then process: put the events in a queue and return 200, so slow work never runs
into the timeout. The [webhook receiver recipe](/recipes/webhook-receiver/) does this.

## Retries

A failed delivery is retried up to 10 times, 11 attempts in all, with exponential backoff. Each
retry sends the same body, signed the same way; `Webhook-Delivery-Retry` says which attempt it
is.

| `Webhook-Delivery-Retry` | Sent after the previous attempt | Since the first attempt, about |
| ------------------------ | ------------------------------- | ------------------------------ |
| `0`                      | (first attempt)                 | 0                              |
| `1`                      | 30 s                            | 30 s                           |
| `2`                      | 68 s                            | 1.6 min                        |
| `3`                      | 2.6 min                         | 4.2 min                        |
| `4`                      | 5.8 min                         | 10 min                         |
| `5`                      | 13.3 min                        | 23 min                         |
| `6`                      | 30.2 min                        | 54 min                         |
| `7`                      | 69 min                          | 2 h                            |
| `8`                      | 2.6 h                           | 4.6 h                          |
| `9`                      | 5.9 h                           | 10.6 h                         |
| `10`                     | 13.4 h                          | 24 h                           |

The times are the waits the platform schedules; the request time and queueing add to them.

## When a webhook is disabled

| Your endpoint                   | What happens                                                                                                                                     |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Answers 403 or 410              | Disabled at once, with no retry.                                                                                                                 |
| Answers 404 on the last attempt | Disabled. A 404 on an earlier attempt is retried.                                                                                                |
| Fails every attempt             | Disabled after the last one, unless the last failure was a timeout and the webhook delivered successfully, or was changed, in the 3 days before. |

Disabling deletes the webhook (a soft delete): it drops out of the list of webhooks (a list with
`include-deleted=true` still returns it, with `is_deleted: true`), its pending deliveries and
retries are dropped, and no one is notified. So:

- Never answer 403 or 410 by accident, for example on a signature that does not match: answer
  401 ([security and signatures](/webhooks/security-and-signatures/)).
- [List your webhooks](/reference/rest/webhooks/#list) on a schedule, and create the webhook
  again if it is gone. The events it missed meanwhile are not sent again: read the changes from
  the API, filtered on `modified` ([querying](/concepts/querying/#filter)) and page by page
  ([pagination](/concepts/pagination/)), as the [two-way contact sync](/recipes/two-way-contact-sync/)
  recipe does.

## Order and chunks

- Deliveries are not ordered. Each chunk is retried on its own, so an older change can arrive
  after a newer one. Keep the highest `entity.revision` per record.
- One change to many records is sent in chunks of up to `chunk_size` events (100 by default).
  With `chunk_delay`, chunk N, counted from 0, waits N × `chunk_delay` seconds
  ([filtering and options](/webhooks/filtering-and-options/)).
- The record in a delivery is read when the delivery is built, after the change, not at the
  moment of the change. A retry hours later still carries the record as it was read then.

## When you delete a webhook

Deleting a webhook through the API makes Coevera send `DELETE` to its URL, with a 10-second
timeout. The request has no body and no signature header. The answer is not checked, but accept
it with a 2xx so your logs stay clean. Your delete call waits for that request, so a slow
receiver makes the delete slow. A webhook disabled after failures gets no such `DELETE`.

## Limits

- There is no delivery log, no replay and no test event in Coevera, and no way to re-send what a
  disabled webhook missed.
- No notification is sent when a webhook is disabled.
- The retry schedule and the 10-second timeout are not configurable.
