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

# Retries & dead-letter

> Schedule, dead-letter behaviour, and idempotency expectations for inbound webhooks.

Zest delivers events with **at-least-once** semantics. Any non-2xx response — or no response within 10 seconds — schedules the next retry attempt.

## Retry schedule

| Attempt     | Delay from previous | Cumulative wait |
| ----------- | ------------------- | --------------- |
| 1 (initial) | 0                   | 0               |
| 2           | 30 seconds          | 30s             |
| 3           | 5 minutes           | 5m 30s          |
| 4           | 30 minutes          | 35m 30s         |
| 5           | 2 hours             | 2h 35m 30s      |
| 6           | 12 hours            | 14h 35m 30s     |

After attempt 6 fails, the delivery moves to the **dead-letter** state. Zest retains dead-letter deliveries indefinitely for later replay.

## What counts as a failure

* Any response with status `>= 300`.
* Any TCP / TLS handshake failure.
* Any response that takes longer than 10 seconds.

## Idempotency expectations

Because retries are guaranteed under failure conditions and possible under transient successes, your handler **must** be idempotent. The `eventId` field is purpose-built for dedup — persist it with at least a 24-hour TTL and short-circuit on replays. The full retry chain spans just under 15 hours, so a 24-hour window safely covers duplicates from any attempt.

## If you suspect a dropped event

Contact `sara@zestholdco.com` with the affected resource slug and a time window.

## Recommendations

* Process the event **after** acknowledging with 200. Long synchronous processing inside the request hot path will hit the 10-second timeout and trigger spurious retries.
* Log `eventId`, `eventType`, and `occurredAt` on every receipt for support correlation.
