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

# Idempotency

> Safely retry a request without creating the same thing twice.

Networks fail. Your server may create a delivery successfully but lose the response before it reaches you. If you simply send a fresh create request, you could create two deliveries.

An idempotency key solves this. Think of it as a receipt number for one action: “create order 1842.” When HaulStow sees the same receipt number and the same request again, it returns the first result.

## When it is required

Send an `Idempotency-Key` header on these requests:

* `POST /recipients`
* `POST /recipients/{recipient_id}/addresses`
* `POST /deliveries`
* `POST /test-helpers/deliveries/{delivery_id}/transition`

Cancellation already has the same outcome when repeated, but it also accepts the header so your code can use one rule for every mutation. `GET` requests and quote requests do not need it.

```http theme={null}
Idempotency-Key: shop-order-1842-create-v1
```

The value must contain 8–255 characters. A UUID is a good default:

```javascript Node.js theme={null}
import { randomUUID } from "node:crypto";

const idempotencyKey = randomUUID();
```

You can also derive it from an ID that is already unique in your system:

```text theme={null}
checkout_1842_create_delivery_v1
```

Save the value with your local order or job. HaulStow retains it for 24 hours.

## The rule that prevents mistakes

Use:

* the **same key** when retrying the same HTTP method, URL, environment, and JSON body;
* a **new key** for a new action or any changed request body.

Do not use one global key for every request.

```bash theme={null}
curl --request POST "$HAULSTOW_BASE_URL/deliveries" \
  --header "Authorization: Bearer $HAULSTOW_API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: checkout_1842_create_delivery_v1" \
  --data @delivery.json
```

If the connection times out, run that exact command again. Do not invent a new key while the first result is unknown.

## Retry behavior

| Situation                                | Result                                                         |                                                                        |
| ---------------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------- |
| What happened                            | What HaulStow returns                                          | What your code should do                                               |
| ---                                      | ---                                                            | ---                                                                    |
| Same key + same request already finished | The original status and body, plus `Idempotent-Replayed: true` | Treat it exactly like the original response.                           |
| Same key + different request             | `409 IDEMPOTENCY_CONFLICT`                                     | Fix the bug: use the old body or a new key for the changed action.     |
| The first request is still running       | `409 IDEMPOTENCY_IN_PROGRESS` plus `Retry-After`               | Wait for the number of seconds in `Retry-After`, then retry unchanged. |
| A required key is missing                | `400 IDEMPOTENCY_KEY_REQUIRED`                                 | Add a unique `Idempotency-Key` header.                                 |

Authentication and validation failures are not stored because no mutation was attempted. Deterministic failures after a mutation claim may be stored to prevent repeated side effects.

## What a replay looks like

The JSON is the same as the original response. This response header tells you it was replayed:

```http theme={null}
Idempotent-Replayed: true
```

You usually do not need special business logic for a replay. If the status and response body indicate success, handle them as success.

## A safe retry checklist

Before retrying a create request, confirm that you kept all four things unchanged:

1. The sandbox or live base URL.
2. The HTTP method and path.
3. The JSON request body.
4. The `Idempotency-Key` value.
