İçeriğe geç
PaymentGateway
Entegrasyon

Webhook'lar

Ödemenin son durumunu tarayıcıya güvenmeden, imzalı sunucu-sunucu bildirimleriyle öğrenin.

Kurulum

Panel → Geliştirici → Webhook'larUç nokta ekle. Https adresinizi, dinlenecek olayları ve modu (test/canlı) seçin. Oluşturmada bir imza sırrı gösterilir; yalnızca bir kez görüntülenir ve gerektiğinde döndürülebilir (rotate). Panelden Test olayı gönder ile uç noktanızı deneyebilir, teslimat geçmişini görüp başarısız teslimatı yeniden gönderebilirsiniz.

Güvenlik gereği webhook adresleri özel/yerel ağ IP'lerine (10.x, 192.168.x, 127.x, link-local …) çözümleniyorsa gönderim yapılmaz (SSRF koruması).

Olaylar

typeNe zaman
payment.requires_action3D doğrulaması bekleniyor.
payment.authorizedÖn provizyon alındı.
payment.capturedÖdeme tahsil edildi (satış ya da ön provizyon kapama).
payment.failedÖdeme reddedildi ya da başarısız oldu.
payment.cancelledÖdeme iptal edildi.
payment.refundedKısmi ya da tam iade yapıldı.
webhook.testPanelden gönderilen deneme olayı.

İstek gövdesi ve başlıklar

POST https://sizin-adresiniz/webhook
{
  "id": "evt_01J...",
  "type": "payment.captured",
  "mode": "live",
  "createdAt": "2026-03-02T09:14:23Z",
  "data": { "id": "pay_01J...", "object": "payment", "status": "captured", "amount": 15990, "...": "..." }
}
Başlıkİçerik
X-Pgw-EventOlay türü.
X-Pgw-DeliveryTeslimat numarası (yeniden denemelerde aynı kalır).
X-Pgw-Signaturet=<unix>,v1=<hex>

İmza doğrulama

İmza: HMAC-SHA256(secret, "<t>.<ham gövde>") değerinin küçük harfli hex çıktısıdır. Gövdeyi ayrıştırmadan, gelen ham haliyle imzalayın; zaman damgasını da kontrol ederek (ör. ±5 dakika) tekrar saldırılarını engelleyin ve karşılaştırmayı sabit zamanlı yapın.

import crypto from "node:crypto";

// rawBody: Buffer/string — JSON.parse ETMEDEN, gelen ham gövde
export function verify(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(parts.v1 ?? "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Yanıtınız ve yeniden deneme

  • İsteği 2xx ile yanıtlayın; başka her yanıt ya da 10 saniyeyi aşan zaman aşımı başarısız sayılır.
  • Başarısız teslimatlar artan aralıklarla yeniden denenir: 30 sn, 2 dk, 10 dk, 30 dk, 2 sa, 6 sa, 12 sa, 24 sa. Sonuncudan sonra teslimat failed olarak işaretlenir; panelden elle yeniden gönderilebilir.
  • Aynı olay birden fazla kez gelebilir. İşlemi id (olay) ya da ödeme id + status ile idempotent yapın.
  • Olayların sırası garanti edilmez; durumu kesinleştirmek gerekirse ödemeyi GET /v1/payments/{id} ile okuyun.