# Idempotency

The `Idempotency-Key` header lets you safely retry a request without risk of double-processing.

## When is it required, when is it recommended

| Endpoint                 | Header                                         |
| ------------------------ | ---------------------------------------------- |
| `POST /api/v1/payments`  | **Required**                                   |
| `POST /api/v1/customers` | Recommended (especially for unattended writes) |
| Everything else (`GET`)  | Not used                                       |

If you call `POST /payments` without an `Idempotency-Key`, you'll get:

```
HTTP/1.1 400 Bad Request
{
  "error": {
    "code": "missing_idempotency_key",
    "message": "Idempotency-Key header is required on POST /api/v1/payments"
  }
}
```

## How it works

```
Idempotency-Key: 9c6a5a52-1aa3-4f6f-9b1d-7d8a5d4e3a2b
```

* Pick a stable, unique key per logical attempt — a fresh UUID, or a structured key like `order_1234:attempt_1`.
* Send the same key + same body to retry safely. We return the **original response** — your retry never creates a duplicate payment.
* Reuse the same key with a **different body** and we return:

```
HTTP/1.1 409 Conflict
{
  "error": {
    "code": "key_reused",
    "message": "Idempotency-Key already used with a different request body"
  }
}
```

The fix is to pick a new key — the new request is genuinely a different operation.

## When to pick what

| Situation                               | Suggested key                                                                                                |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| One-shot charge from a fresh checkout   | A fresh UUID: `uuidgen` or `crypto.randomUUID()`.                                                            |
| Charge tied to an order in your system  | `order_<id>:attempt_<n>` where you bump `n` only when the request body actually differs.                     |
| Scheduled charge                        | `subscription_<id>:cycle_<yyyymmdd>` — stable across retries within the same cycle, different across cycles. |
| Customer creation tied to a user signup | `signup_<user_id>` — guarantees that double-clicks don't create two customers.                               |

## Key lifetime

* We retain the idempotency record for **24 hours**.
* Within that window, replays return the original response (with the exact same fields, timestamps, and IDs).
* After 24 hours, the same key submitted again is treated as a new request.

## What it doesn't help with

* Idempotency-Key isn't a duplicate-charge prevention mechanism beyond the 24-hour window — your own application should still avoid charging the same shopper twice for the same logical order.
* It doesn't change the outcome of a declined card — a `failed` response is still the original response, and replaying the key returns the same failure.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://support.swisspay.ai/api-reference/idempotency.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
