# Idempotency

> Safely retry payment creation without ever creating a duplicate payment.

Networks fail. If your request times out you can't tell whether the payment was created. An **idempotency key** makes retrying safe: the same key with the same request returns the **original** result instead of creating a second payment.

> **Tip:** **Using the SDK? Nothing to do.** In the Quickstart you never touch this: the SDK automatically protects supported requests. `devzity.payments.create(...)` generates a secure key for you and reuses it on every automatic retry. Pass your own (for example your order id) with `{ idempotencyKey: "order-123" }`.

## What the SDK retries

Only when it is safe. A create is retried after a network failure, a `429` (waiting for `Retry-After`) or a `502/503/504`, always with the **same** idempotency key, so a retry can never create a second payment. Reads are retried the same way. A cancel is retried only after a `429`. Ordinary `4xx` errors are never retried.

## REST

Send an `Idempotency-Key` header on `POST /v1/payments`:

```bash
curl https://api.devzity.com/v1/payments \
  -X POST \
  -H "Authorization: Bearer $DEVZITY_SECRET_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"amount":"500.00"}'
```

- Use a random value (a UUID) per **logical** payment, and reuse it for every retry of that payment.
- **Same key + same body** → the original response is returned; no new payment.
- **Same key + different body** → `409 idempotency_conflict`.
- A request with that key still being processed → `409 idempotency_in_progress`; retry shortly.
- Keys are remembered for **24 hours** and are scoped to the API key.

Idempotency keys protect retries of the *same request*. To prevent two *different* requests for the same order, also set `external_id`: a second payment with the same `external_id` returns `external_id_conflict`.
