recurr.
Payment Flows

Tekrarlayan Ödeme

Cron tabanlı otomatik fatura kesme ve başarısız ödeme yeniden denemesi

Cron Zamanlaması

vercel.json
{
  "crons": [{
    "path": "/api/billing/cron",
    "schedule": "0 8,14,20 * * *"
  }]
}

Her gün 08:00, 14:00 ve 20:00'de çalışır.

Cron Akışı

GET /api/billing/cron
Authorization: Bearer {CRON_SECRET}
handleCronRequest() çalışır:


manager.processDuePayments(serverIp)


adapter.findSubscribersDueToday()
→ nextBillingDate <= şimdi
  VE status IN (active, past_due, trial)

        │  Her abone için (try/catch — bir hata diğerlerini etkilemez):

adapter.createPayment({ status: "pending" })   ← önce kayıt aç


client.chargeStoredCard({ utoken, ... })

        │  chargeStoredCard() içinde:
        │    POST paytr.com/odeme/capi/list → ctoken alınır
        │    POST paytr.com/odeme → utoken + ctoken ile ödeme

        ├── SUCCESS / WAIT_CALLBACK
        │     Payment "pending" kalır (webhook onaylayacak)

        └── FAILURE (senkron)
              Payment → "failed"
              failedAttempts++

              ├── failedAttempts < maxRetries
              │   Subscriber → status="past_due"
              │               nextBillingDate = şimdi + retryIntervalHours
              │   onPaymentFailed() tetiklenir

              └── failedAttempts >= maxRetries
                  Subscriber → status="cancelled"
                               cancelledAt = şimdi
                  onSubscriptionCancelled() tetiklenir

Webhook İşleme (Tekrarlayan Ödeme)

POST /api/billing/webhook
   ├─ HMAC-SHA256 hash doğrulanır
   ├─ Tekrarlayan ödeme olarak tanımlanır (merchant_oid prefix: BP...)

   │  Başarılı ise:
   │  ├─ Payment → "success"
   │  ├─ Subscriber → status="active", failedAttempts=0
   │  └─ nextBillingDate += interval

   │  Başarısız ise:
   │  ├─ Payment → "failed"
   │  ├─ failedAttempts++
   │  ├─ failedAttempts < maxRetries → past_due + retry zamanla
   │  └─ failedAttempts >= maxRetries → cancelled

   └─ "OK" döner

merchantOid Formatı (Tekrarlayan Ödeme)

BP{subscriberId_truncated}{base36-timestamp}
Örnek: BPsub4f2a8b9cM3X7KQ2
Maks. 64 karakter (PayTR limiti)

serverIp parametresi PayTR tarafından Non-3D işlemlerde doğrulanır. Sunucunuzun gerçek public IP'sini geçin. Test modunda "127.0.0.1" kullanabilirsiniz.

On this page