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

# Delivery failure handling

> How Prequel recovers a failed delivery without data loss or manual backfills

Prequel has intentional retry, redelivery, and circuit breaking logic designed to protect data integrity in your pipeline and minimize the operational burden of failed deliveries.

## Retries

Prequel retries delivery to your destination for only `429`, `503`, and `504` responses that carry a `Retry-After` header, for a maximum of three attempts per delivery. Every other response, and every network failure, is attempted once. For which status code to return and the error code Prequel records for it, see the [Record API](/import/destination-specs/webhook-record#response-codes) or [Batch API](/import/destination-specs/webhook-batch#response-codes) spec.

The `Retry-After` value (in seconds) sets the wait before the next attempt, capped at 30 seconds.

## Redelivery

Each load selects every record that has not been delivered yet, plus any record whose content changed since its last delivery. A record that failed to reach your endpoint therefore remains eligible and is delivered again on the next scheduled load, with no backfill required.

<Warning>
  Because a record can be delivered more than once across attempts and loads, your endpoint must be idempotent.

  In your pipeline, deduplicate on the dataset's [`primary_key_column`](/import/core-concepts/datasets#1-dataset-type). Every delivery also carries an [`X-Prequel-Idempotency-Key`](/import/destination-specs/webhook-record#webhook-headers) header, which stays the same across retry attempts of the same request.
</Warning>

### Rejected records

A `5xx` means your endpoint could not accept the delivery. A `4xx` means something is wrong with the data being delivered, so Prequel treats a `400`, `412`, `413`, or `422` as a rejection. Prequel builds the batch request itself, so on a batch delivery every error status indicates the records were not delivered rather than that any record was bad. For these records, what happens on the next load depends on the delivery type:

| Delivery type                                      | Delivery status                              | Behavior on next load                                       |
| -------------------------------------------------- | -------------------------------------------- | ----------------------------------------------------------- |
| [Record](/import/destination-specs/webhook-record) | Delivered, with the rejection's error code   | Not delivered again until its content changes at the source |
| [Batch](/import/destination-specs/webhook-batch)   | Not delivered, for every record in the batch | Every record in the batch is delivered again                |

A record counts as delivered once your endpoint receives it, whether or not your endpoint accepted it. The outcome of an individual record in a batch reaches Prequel only through [acknowledgements](/import/features/acknowledgements).

## Circuit breaking

Retries and redelivery assume a failure will clear on its own. When it will not, such as a broken mapping or an unreachable endpoint, circuit breakers stop the pipeline and report the cause to preserve resources on your [Provider's](/import/core-concepts/providers) source and on your [destination](/import/core-concepts/destinations).

<Tip>
  **Subscribe a [webhook](/import/logging/webhooks-and-monitoring) to be alerted when an extract or load fails.**
</Tip>

### Source circuit breaker

Prequel halts an [extract](/import/core-concepts/dataflow#lifecycle-of-a-transfer) from the [source](/import/core-concepts/sources), or a load to the destination, when 100 or more of its records fail, which indicates a mapping or schema mismatch at the source.

The next scheduled extract or load runs as usual, and trips again if the same records still fail.

### Destination circuit breaker

Prequel sets `is_circuit_broken` on the [stream](/import/core-concepts/streams) when a load fails with a destination-side error, such as an unreachable host, a `403` or `404`, or a `5xx` response. The failure ends the load even when other records in it were delivered successfully, and cancels the delivery work still queued behind it.

A load sends one request per record for [record delivery](/import/destination-specs/webhook-record), or one per batch for [batch delivery](/import/destination-specs/webhook-batch), split by [`max_size_per_batch`](/import/destination-specs/webhook-batch#creating-your-destination-spec). Every record in a batch shares that batch's outcome, so a halt leaves a load's records in three states:

| Records within the halted load           | Delivery status | Behavior on next load |
| ---------------------------------------- | --------------- | --------------------- |
| Accepted with a `2xx` before the failure | Delivered       | Not delivered again   |
| In the request that ended the load       | None recorded   | Delivered again       |
| Never sent, because the load halted      | None recorded   | Delivered again       |

While the flag is set, extracts continue to run but produce no loads, and manual load triggers are rejected. To resume loads, set it back to `false` with [Update import stream](/import/api-reference/import-streams/update-import-stream).
