> ## 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.

# Yeniden Deneme Politikası

> Webhook teslimi başarısız olduğunda Payven'in yeniden deneme davranışı.

Payven webhook teslimini **at-least-once** garantili çalıştırır. İlk denemede başarısız olursa belirli aralıklarla yeniden dener.

## Yeniden deneme programı

Bir webhook için varsayılan **`max_retry_count: 5`**. Denemeler arası süreler:

| Deneme | Yaklaşık bekleme süresi |
| ------ | ----------------------- |
| 1      | Hemen                   |
| 2      | 1 dakika sonra          |
| 3      | 5 dakika sonra          |
| 4      | 30 dakika sonra         |
| 5      | 2 saat sonra            |
| 6      | 24 saat sonra           |

5 başarısız denemeden sonra teslim **kalıcı olarak başarısız** kabul edilir ve daha fazla otomatik deneme yapılmaz. Konsoldan manuel replay tetiklenebilir.

<Note>
  Bekleme sürelerine **±%20 jitter** uygulanır — eşzamanlı tetiklenen bin webhook'un retry'leri sabit aralıklarla çakışmaz, pencereye yayılır.
</Note>

## Hangi durumlarda retry tetiklenir?

| Durum                                | Retry tetiklenir mi?                                                    |
| ------------------------------------ | ----------------------------------------------------------------------- |
| Sizin endpoint'iniz HTTP `2xx` döndü | Başarılı kabul edilir                                                   |
| HTTP `3xx` redirect                  | Takip edilmez, başarısız sayılır                                        |
| HTTP `4xx` (sizin tarafta hata)      | Retry edilir — handler'ınız muhtemelen geçici bir kontrol bug'ı yaşıyor |
| HTTP `5xx` (sizin sunucu hatası)     | Retry edilir                                                            |
| Network timeout (15sn)               | Retry edilir                                                            |
| TLS handshake / DNS hatası           | Retry edilir                                                            |

<Tip>
  **4xx'de retry niçin?** Eğer endpoint'iniz bir olayı yanlışlıkla 400 dönerse (örn. transaction\_id'yi DB'de bulamadığı için), Payven 5 deneme boyunca tekrarlar. Bu deneme süresinde DB sync olabilir veya konfigürasyonunuzu düzeltebilirsiniz. Ek not: olay almak istemediğiniz tipler için **subscription'a hiç eklemeyin** — hiç gönderilmemesi 4xx döndürmekten daha temizdir.
</Tip>

## Timeout

Her teslim isteği için **15 saniye** timeout uygulanır. Bu süreyi aşan istekler timeout sayılır ve retry edilir.

Endpoint'iniz uzun süren bir iş yapacaksa:

```javascript theme={null}
app.post("/webhooks/payven", async (req, res) => {
  // 1. İmzayı doğrula (hızlı)
  if (!verify(req)) return res.status(401).end();

  // 2. Olayı bir queue'ya at, hemen 200 dön
  await queue.publish({ topic: "payven-webhook", payload: req.body });

  // 3. ✓ 15sn'den çok önce ack
  res.status(200).end();
});

// Worker async işler:
// queue.consume("payven-webhook", processEvent);
```

## Manuel replay

Konsol → **Webhook Teslim Logları** ekranından bir teslimin **Tekrar Gönder** butonuyla manuel replay yapabilirsiniz. Replay edilen olay aynı `X-Payven-Event-Id` ile gelir; idempotent handler'ınız bunu zaten işlenmiş olarak görüp duplicate işlem yapmaz.

Senaryolar:

* Sizin endpoint'iniz down idi → eski olayları replay ederek yetiştirin
* Bir bug nedeniyle olayları yanlış işlediniz → fix sonrası replay edip yeniden işleyin
* Yeni bir feature için historical event'leri yeniden tüketmek istiyorsunuz

## Subscription başına retry sayısı

Default `max_retry_count: 5`'tir. Yüksek hassasiyet gerektiren entegrasyonlar (örn. ERP) için daha fazla retry isterseniz subscription oluşturma / güncelleme sırasında bu değeri ayarlayabilirsiniz:

```bash theme={null}
curl -X POST https://vpos.payven.com.tr/api/v1/webhook-subscriptions \
  -H "Authorization: Bearer $PAYVEN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url":             "https://erp.example.com/webhooks/payven",
    "events":          ["payment.completed", "refund.completed"],
    "max_retry_count": 10
  }'
```

`max_retry_count` 0-20 arasında kabul edilir. Üst sınır aşılırsa `422 validation_failed`.

## En iyi pratikler

<Check>**Hızlı yanıt verin** — 15sn'den çok önce 200 dönün. Long-running işleri queue'ya atın.</Check>
<Check>**Idempotent yazın** — `X-Payven-Event-Id`'yi DB'de tut ve duplicate'leri ack edip skip edin.</Check>
<Check>**HTTP 2xx mantığına saygı gösterin** — başarılı işleme `200`, başarısız (retry isteyen) durumlara `5xx` dönün; deliberate retry isteğinizde 4xx kullanmaktan kaçının.</Check>
<Check>**Production'da loglayın** — gelen her olayın `event_id`, `delivery_id`, body'sini saklayın; debug için kritik.</Check>
<Check>**Sırasız geldiklerini varsayın** — `payment.completed` `refund.completed`'tan sonra gelebilir (retry kuyruğundan çıkış sırası). `created_at` veya `transaction.status` ile durumu yeniden doğrulayın.</Check>
