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

# Idempotency

> Deterministic retry safety for mutating requests

Idempotency ensures retries are safe for mutating requests. Retrying the same request with the same `Idempotency-Key` never executes side effects twice.

## How it works

Idempotency applies to specific mutating endpoints — creating payments, payment requests, wallet deposits and withdrawals, agents, and webhooks. Include an `Idempotency-Key` header on those requests; where an endpoint requires the key, omitting it returns a `400`.

```python theme={null}
response = await client.post(
    "https://api.natural.co/payments",
    headers={
        "Authorization": "Bearer sk_ntl_prod_abc123...",
        "Idempotency-Key": str(uuid.uuid4())
    },
    json={...}
)
```

Natural stores the key and response. On subsequent requests with the same key:

* **Same key + same request intent + completed** -> Replays the original response.
* **Same key + different request intent** -> Returns `409 Conflict`.
* **Same key + request still in progress** -> Returns `409 Conflict`.
* **Different key** -> Treated as a new mutation attempt.

Replayed responses include `X-Idempotency-Replayed: true`.

Idempotency keys are scoped by caller namespace, and records are retained in a replay window (currently 48 hours). Reusing a key after expiration starts a new request.

## Conflict reasons

When a request returns `409 Conflict` because of idempotency, the error payload includes a `reason` value:

* `IDEMPOTENCY_KEY_REUSED`: the same key was used with a different request intent.
* `IDEMPOTENCY_REQUEST_IN_PROGRESS`: the original request is still executing.

## Best practices

**Do:**

* Use UUIDv4/UUIDv7 for keys.
* Reuse the same key for network retries of the same submit intent.
* Generate a new key only when the user starts a new logical operation.

**Don't:**

* Use a fresh random key per HTTP retry.
* Reuse a key for different logical operations.
* Put sensitive data in keys.

## When to retry

| Error                                   | Action                                       |
| --------------------------------------- | -------------------------------------------- |
| Network/timeout                         | Retry with **same** key, exponential backoff |
| 5xx server error                        | Retry with **same** key, exponential backoff |
| 409 + `IDEMPOTENCY_REQUEST_IN_PROGRESS` | Wait, then retry with **same** key           |
| 409 + `IDEMPOTENCY_KEY_REUSED`          | Fix request mismatch and use a **new** key   |
| Other 4xx                               | Don't retry — fix request data first         |

## Related

* [Error Handling](/api-reference/errors/error-handling) - Handling conflicts and other errors
