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

# Idempotency

> Aynı isteği güvenle tekrar göndermek için Idempotency-Key kullanımı.

Ağ kesintisi, timeout veya istemci tarafı hata durumlarında bir isteği iki kez göndermiş olabilirsiniz. **Idempotency**, aynı işlemin iki kez gerçekleştirilmemesini garanti eder.

## Nasıl çalışır?

Yazma işlemi yapan tüm `POST` endpoint'leri `Idempotency-Key` header'ını kabul eder. Aynı anahtarla gönderilen ikinci istek, **ilk yanıtın birebir aynısını** döner — yeni bir işlem oluşmaz.

```http theme={null}
POST /api/v1/payments
Authorization: Bearer eyJhbGc...
Idempotency-Key: order-1001-payment
```

Replay edilen yanıtlarda Payven `Idempotent-Replayed: true` header'ını ekler:

```http theme={null}
HTTP/1.1 200 OK
Idempotent-Replayed: true
```

## Anahtar kuralları

| Kural              | Değer                                                                                                                                                                                                 |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Format             | **UUID v7** önerilir (RFC 9562, zaman-sıralı — debug ve audit'te kronolojiyi korur). UUID v4 veya başka herhangi bir string de kabul edilir.                                                          |
| Maksimum uzunluk   | 128 karakter                                                                                                                                                                                          |
| Saklama süresi     | Ödeme endpoint'lerinde (`POST /payments` ve alt-akışlar) **24 saat**; diğer yazma endpoint'lerinde **3 dakika**. Hassas işlemler (refund, void, capture, transfer) ödeme endpoint'leri kapsamındadır. |
| Eşsiz olma kapsamı | Tenant + endpoint kombinasyonu içinde                                                                                                                                                                 |
| Body değişikliği   | Aynı anahtarla **farklı** body → `409 idempotency_key_in_use`                                                                                                                                         |

<Note>
  Anahtar tenant düzeyinde scope'lanır — farklı bir tenant aynı anahtarla başka bir
  işlem oluşturabilir, bu beklenen davranıştır.
</Note>

## Senaryolar

<AccordionGroup>
  <Accordion title="Başarılı istek + tekrar deneme">
    1. İstemci `POST /payments` gönderir, `Idempotency-Key: order-1001-payment`.
    2. Payven işlemi başarıyla yapar, `200 OK` döner.
    3. İstemci network timeout aldığını sanıp aynı isteği aynı anahtarla tekrar gönderir.
    4. Payven yeni ödeme oluşturmaz; ilk yanıtı döner ve `Idempotent-Replayed: true` header'ı ekler.
  </Accordion>

  <Accordion title="Eşzamanlı tekrar istek">
    1. İki istek aynı anda atılır, ikisinde de `Idempotency-Key: ABC123`.
    2. Birinci istek işlenmeye başlar — cache'e eklenir.
    3. İkinci istek cache'e ulaştığında ilk yanıt henüz hazırsa onu döner; değilse (race) backend'in deduplication mantığı devreye girer.
  </Accordion>

  <Accordion title="Aynı anahtar farklı payload ile">
    1. İstemci `Idempotency-Key: ABC123` ile `15000` kuruşluk ödeme atar.
    2. Aynı anahtarla `25000` kuruşluk ödeme atar.
    3. Payven `409 Conflict` döner — anahtar farklı body için kullanılmış:

    ```json theme={null}
    {
      "type":   "https://docs.payven.com.tr/errors/idempotency_key_in_use",
      "title":  "Idempotency-Key çakışması",
      "status": 409,
      "code":   "idempotency_key_in_use",
      "detail": "Bu Idempotency-Key daha önce farklı bir request body ile kullanıldı."
    }
    ```

    Çözüm: ya farklı bir anahtar kullanın, ya da bilinçli retry için aynı body'yi gönderin.
  </Accordion>

  <Accordion title="TTL süresi sonrası">
    1. Saklama süresi dolmuş bir anahtar (ödemeler için 24 saat, diğer endpoint'ler için 3 dakika).
    2. Aynı anahtar tekrar kullanılırsa **yeni** bir işlem oluşur — cache temizlenmiş.
    3. Bu nedenle uzun süreli retry mantığında her seferinde anahtar üretmek değil, üst seviye iş kimliğini (örn. `order_id`) anahtar olarak kullanmak daha güvenlidir.
  </Accordion>
</AccordionGroup>

## Önerilen kullanım

İstemci tarafında **yüksek seviye iş kimliğini** anahtar olarak kullanın. Böylece aynı sipariş için yapılan tüm tekrar denemeler aynı işleme yönlendirilir.

```text theme={null}
Idempotency-Key: order-2026-001-payment
Idempotency-Key: order-2026-001-refund-1
```

<CodeGroup>
  ```csharp C# theme={null}
  var idempotencyKey = $"order-{order.Id}-payment";

  var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/payments")
  {
      Content = JsonContent.Create(payload)
  };
  request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
  request.Headers.Add("Idempotency-Key", idempotencyKey);

  // Network timeout / 5xx durumunda aynı request'i tekrar gönder.
  var response = await SendWithRetryAsync(() => CloneRequest(request));
  ```

  ```javascript Node.js theme={null}
  const idempotencyKey = `order-${order.id}-payment`;

  await retry(() =>
    fetch("https://vpos.payven.com.tr/api/v1/payments", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "Idempotency-Key": idempotencyKey,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(payload),
    }),
  );
  ```

  ```python Python theme={null}
  import httpx

  idempotency_key = f"order-{order.id}-payment"

  await retry(lambda: client.post(
      "/api/v1/payments",
      json=payload,
      headers={
          "Authorization": f"Bearer {access_token}",
          "Idempotency-Key": idempotency_key,
      },
  ))
  ```
</CodeGroup>

## Hangi endpoint'lerde kullanın

| Kategori                                                   | Idempotency                                                           |
| ---------------------------------------------------------- | --------------------------------------------------------------------- |
| `POST /api/v1/payments` (Non-3D ödeme)                     | Önerilir                                                              |
| `POST /api/v1/payments/3d/init` (3DS init)                 | Önerilir                                                              |
| `POST /api/v1/payments/{id}/refund` (iade)                 | **Şiddetle önerilir** — aynı tutarın iki kez iade edilmesini engeller |
| `POST /api/v1/payments/{id}/void` (iptal)                  | **Şiddetle önerilir**                                                 |
| `POST /api/v1/payments/{id}/capture` (ön provizyon çekimi) | **Şiddetle önerilir**                                                 |
| `POST /api/v1/checkout/sessions` (hosted checkout)         | Önerilir                                                              |
| `POST /api/v1/transfers/...` (para transferi)              | **Şiddetle önerilir**                                                 |
| `POST /api/v1/webhook-subscriptions`                       | Opsiyonel                                                             |
| `GET` istekleri                                            | İhtiyaç yok — `GET` doğası gereği idempotenttir                       |

## Sınırlar ve dikkat

<Warning>
  **`Idempotency-Key`'i mantıksız geniş ölçekte kullanmayın.** Saatler önceki bir
  işlemin yanıtını "replay" amacıyla almak için anahtar saklamak yerine, gerçek
  durumu **`GET /api/v1/payments/{id}`** ile sorgulayın. Idempotency-Key sadece
  **istemci taraflı tekrar gönderim** korumasıdır, kalıcı bir "transaction lookup"
  mekanizması değildir.
</Warning>

<Tip>
  Refund ve void gibi hassas işlemleri **deterministik anahtar** ile gönderin
  (örn. `refund-{transaction_id}-{slot}`) — operatörün UI'da iki kez butona basması
  durumunda da sadece tek iade oluşur.
</Tip>
