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

# Idempotency

> Retry a POST safely after a timeout or a dropped connection.

Send an `Idempotency-Key` header on a `POST` request. If the connection drops before you get the response, send the
same request again with the same key: Payra returns the original result instead of doing the work twice.

The header is **required** on `POST /payments` and `POST /refunds` (`400 idempotency_key_required` without it),
and optional on every other `POST`.

```bash theme={null}
curl -X POST https://api-dashboard.payra.com/v1/... \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: 5f6c8a4e-3b0d-4a8e-9a57-1f2b3c4d5e6f" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
```

* Use a unique value per operation, up to 255 characters. A UUID v4 works.
* Keys are scoped to your workspace, and stored responses replay for 24 hours. On `POST /payments` and
  `POST /refunds` a key also stays bound, for good, to the payment or refund it created and to the API key that
  sent it. After the 24 hours, that API key sending the key again gets that payment or refund back as it is
  now (a declined one as its `402`) when `payment_method`, `amount` and `currency` match (for a refund,
  `payment` and `amount`), and `idempotency_key_reused` otherwise. Never recycle keys.
* Only `POST` uses the header; `GET` and `DELETE` ignore it. Reading is always safe to repeat.
* "Same request" means the same body byte for byte: JSON re-serialized with another key order or spacing
  counts as a different request.

## How a retry is answered

| Situation                                                         | Response                                                                                                                                                                                                                |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Same key, same request, first one finished                        | The stored response, status and body included, with `Idempotent-Replayed: true`                                                                                                                                         |
| Same key, first request still running                             | `409 idempotency_key_in_flight`. Retry shortly. A first request that has been running for more than five minutes is considered lost, and the retry runs in its place; if the first was in fact still running, both run. |
| Same key within 24 hours, different API key, method, path or body | `400 idempotency_key_reused`                                                                                                                                                                                            |

Responses the endpoint produced after it started are stored and replayed, including `409 conflict` and `500`:
retrying those with the same key returns the same error. Read the object back first (retrieve, or list), then
retry with a new key. A request refused before
it started is not stored, so you can fix it and reuse the key: a body that is not JSON, a parameter that fails
validation (missing, wrong type, out of range), a key without the scope, or an unknown URL. A `parameter_invalid`
the endpoint returns once it runs, such as an unknown `payment_method` or `payment`, is stored: send the corrected
request with a new key.

On a replay, the body's `request_id` is the original request's, and the `Request-Id` header is the retry's.
