# Retries and failures

> How Emailit retries failed webhook requests, when it emails you and disables an endpoint, and how to inspect and resend failed requests.

When your endpoint doesn't accept a webhook request, Emailit keeps the events and tries again on a schedule that lasts a little over three days. This page lists that schedule, explains the emails Emailit sends and when it disables an endpoint, and shows how to inspect and resend failed requests.

## What counts as a failure

A request fails when your endpoint:

- Returns any status outside `200`–`299`, including redirects (`3xx`).
- Doesn't respond within 30 seconds.
- Can't be reached: DNS errors, refused connections, TLS errors, or a URL that resolves to a private IP address.

A failure applies to the whole batch: every event in the request is retried together.

## Retry schedule

After each failed attempt, Emailit waits before trying again:

| Attempt | Wait after the previous attempt | Time since the first attempt |
| --- | --- | --- |
| 1 | Sent within seconds of the event | 0 |
| 2 | 5 minutes | 5 minutes |
| 3 | 30 minutes | 35 minutes |
| 4 | 2 hours | 2 hours 35 minutes |
| 5 | 5 hours | 7 hours 35 minutes |
| 6 | 12 hours | 19 hours 35 minutes |
| 7 | 12 hours | 1 day 7 hours |
| 8 | 12 hours | 1 day 19 hours |
| 9 | 12 hours | 2 days 7 hours |
| 10 | 12 hours | 2 days 19 hours |
| 11 | 12 hours | 3 days 7 hours |

If attempt 11 fails, the request is marked **Failed** and isn't retried automatically. You can still [resend it](#resend-failed-requests) for 7 days.

Each attempt is signed again with a fresh timestamp. Events that arrive while earlier requests are waiting for a retry are sent in their own batches, so one bad event doesn't block newer ones.

## Notification emails

Emailit emails the workspace owner at two points:

| When | Email |
| --- | --- |
| A request fails for the third time (about 35 minutes after the first failure) | The webhook is failing. Sent once per incident. You get another only after a successful delivery followed by new failures, or after 4 days. |
| The webhook is disabled automatically | The webhook was disabled, with the last status code. |

## Automatic disabling

If a webhook has had no successful delivery for 3 days since its oldest failing request, Emailit disables it at the next failed attempt. In practice that happens around the 11th attempt of the first failing request, or sooner if new events keep failing.

While a webhook is disabled:

- New events aren't queued for it. They're still recorded in the [event stream](/docs/logs/events/).
- Requests that were waiting for a retry stay pending and resume when you enable it.
- The webhook page shows the status **Disabled**.

To turn it back on, select **Enable webhook** in the webhook's actions menu, or call [Update a webhook](/docs/api-reference/webhooks/update/) with `{"enabled": true}`. **Retry failed** and retrying a single request also enable the webhook.

## The Requests tab

Open a webhook in **Email API → Webhooks** to see its **Requests** tab, newest first:

| Column | Description |
| --- | --- |
| **Event type** | The event in the request. |
| **Event ID** | The `evt_` ID, the same value your endpoint receives as `event_id`. |
| **Created** | When the request was queued. |
| **Attempts** | How many delivery attempts have failed so far. |
| **Status** | **Pending** (not tried yet), **Attempting** (failed at least once, will be retried), **Delivered**, or **Failed** (retries ran out). |

Filter by **Status code**, **Event** or **Created**. Test events from **Send test** aren't listed here.

For a **Failed** request, select **View** to open **Failure reason**: the status code your endpoint returned (`0` when there was no HTTP response), when the request was created and when it failed, and the first 2,000 characters of the response body.

## Resend failed requests

You can resend requests marked **Failed** whose last failure was within the past 7 days. Resent requests go back to **Pending** and start a new retry cycle from attempt 1. Delivery isn't instant: the next delivery run picks them up within seconds.

### Retry one request

On the **Requests** tab, select **Retry** on a failed row. The button only appears on failed requests from the last 7 days.

The API endpoint is [Retry one request](/docs/api-reference/webhooks/retry-request/), `POST /v2/webhooks/{id}/requests/{request_id}/retry`, which returns `{"retried": 1, "id": "whr_…"}`. It only accepts requests marked **Failed** and returns `400` for others. Request IDs (`whr_…`) aren't listed by any public endpoint, so for API automation use **Retry failed** instead.

### Retry failed requests

Open the webhook's actions menu and select **Retry failed**. Every request that failed in the last 7 days is queued again, and the dashboard shows "Queued 3 failed request(s) for retry" with the actual count, or "No failed requests in the last 7 days".

With the API, call [Retry failed requests](/docs/api-reference/webhooks/retry-failed/):

```bash
curl -X POST https://api.emailit.com/v2/webhooks/wh_2xGk8Hd3RvN6qT1mWsB9cL4pZ7e/retry-failed \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

```json
{ "retried": 42 }
```

## Recover from an outage

1. **Fix the endpoint.** Use **View** on a failed request to see what your endpoint returned.

2. **Confirm it works.** Use **Send test** from the actions menu, or [Send a test event](/docs/api-reference/webhooks/test/) with the API, and check for a `2xx`.

3. **Enable the webhook** if Emailit disabled it.

4. **Resend failures.** Select **Retry failed** to queue every request that failed in the last 7 days. Requests still marked **Attempting** are retried on their own schedule.

5. **Backfill gaps.** Events that happened while the webhook was disabled were never queued, and failures older than 7 days can't be resent. Read them with the [Events API](/docs/logs/events/#reconcile-missed-webhook-events) for the affected window and process the ones you're missing.

Because retries resend whole batches, make your handler idempotent: store each `event_id` and skip ones you've already processed. See [Webhook requests](/docs/webhooks/webhook-requests/#duplicates).

## Retention

Webhook requests follow the **Logs** retention window, so older rows disappear from the **Requests** tab over time.

| | Pay as you go | Pro | Business | Custom |
| --- | --- | --- | --- | --- |
| Request logs kept | 7 days | 30 days | 30 days | Flexible |

## Related

  - [Webhook requests](/docs/webhooks/webhook-requests/)
  - [Events](/docs/logs/events/)

---
Source: https://emailit.com/docs/webhooks/retries-and-failures/
