Webhook Entegrasyonu

Abonelik olayları için ödeme sağlayıcısı webhook'larını kurma ve işleme.

Not: Bu içerik, tanıtım amacıyla hazırlanmış örnek/yer tutucu bir içeriktir.

Webhook'lar, faturalandırma olayları gerçekleştiğinde uygulamanızı bilgilendirerek uygulamanızın ödeme sağlayıcınızla senkronize kalmasını sağlar.

Neden Webhook'lar?

Webhook'lar şu açılardan vazgeçilmezdir:

  • Gerçek zamanlı güncellemeler - Ödeme olaylarından anında haberdar olma
  • Güvenilirlik - Kullanıcılar tarayıcılarını kapatsa bile olayları işler
  • Güvenlik - Sunucudan sunucuya iletişim
  • Otomasyon - Abonelik durumunun otomatik güncellenmesi

Webhook Uç Noktası

Webhook uç noktanız, ödeme sağlayıcısından gelen olayları alır:

// app/api/billing/webhook/route.ts
export async function POST(request: Request) {
  const body = await request.text();
  const signature = request.headers.get('stripe-signature');

  // Webhook imzasını doğrula
  const event = stripe.webhooks.constructEvent(
    body,
    signature,
    process.env.STRIPE_WEBHOOK_SECRET
  );

  // Olayı işle
  await handleBillingEvent(event);

  return new Response('OK', { status: 200 });
}

Yaygın Olaylar

Abonelik Oluşturuldu

case 'customer.subscription.created':
  await prisma.subscription.create({
    data: {
      id: event.data.object.id,
      accountId: event.data.object.metadata.accountId,
      status: 'active',
      planId: event.data.object.items.data[0].price.id,
      currentPeriodEnd: new Date(event.data.object.current_period_end * 1000),
    },
  });
  break;

Abonelik Güncellendi

case 'customer.subscription.updated':
  await prisma.subscription.update({
    where: { id: event.data.object.id },
    data: {
      status: event.data.object.status,
      planId: event.data.object.items.data[0].price.id,
      currentPeriodEnd: new Date(event.data.object.current_period_end * 1000),
    },
  });
  break;

Abonelik Silindi

case 'customer.subscription.deleted':
  await prisma.subscription.update({
    where: { id: event.data.object.id },
    data: {
      status: 'canceled',
      canceledAt: new Date(),
    },
  });
  break;

Ödeme Başarısız Oldu

case 'invoice.payment_failed':
  const subscription = await prisma.subscription.findUnique({
    where: { id: event.data.object.subscription },
  });

  // Ödeme başarısızlığı bildirimi gönder
  await sendPaymentFailureEmail(subscription.accountId);
  break;

Webhook'ları Kurma

Stripe

  1. Yerel Geliştirme (Stripe CLI kullanarak):
stripe listen --forward-to localhost:3000/api/billing/webhook
  1. Üretim:
  • Stripe Dashboard → Developers → Webhooks bölümüne gidin
  • Uç nokta ekleyin: https://yourdomain.com/api/billing/webhook
  • Dinlenecek olayları seçin
  • Webhook imzalama anahtarını .env dosyanıza kopyalayın

Paddle

  1. Webhook URL'sini Paddle panelinde yapılandırın
  2. Webhook anahtarını ortam değişkenlerine ekleyin
  3. Webhook imzasını doğrulayın:
const signature = request.headers.get('paddle-signature');
const verified = paddle.webhooks.verify(body, signature);

if (!verified) {
  return new Response('Invalid signature', { status: 401 });
}

Güvenlik İçin En İyi Uygulamalar

  1. İmzaları her zaman doğrulayın - Yetkisiz istekleri engeller
  2. HTTPS kullanın - Webhook verilerini aktarım sırasında şifreler
  3. Olay verilerini doğrulayın - Zorunlu alanları kontrol edin
  4. İdempotent şekilde işleyin - Yinelenen olayları güvenle işleyin
  5. Hızla 200 döndürün - Alındığını onaylayın, işlemeyi asenkron yapın

Hata Yönetimi

async function handleBillingEvent(event: Event) {
  try {
    await processEvent(event);
  } catch (error) {
    // Hata ayıklama için hatayı günlüğe kaydet
    console.error('Webhook error:', error);

    // Yeniden deneme için başarısız olayı sakla
    await prisma.failedWebhook.create({
      data: {
        eventId: event.id,
        type: event.type,
        payload: event,
        error: error.message,
      },
    });

    // Sağlayıcının yeniden denemesini tetiklemek için hatayı fırlat
    throw error;
  }
}

Webhook'ları Test Etme

Sağlayıcının CLI Araçlarını Kullanma

# Stripe
stripe trigger customer.subscription.created

# Belirli senaryoları test et
stripe trigger payment_intent.payment_failed

Manuel Test

curl -X POST https://your-app.com/api/billing/webhook \
  -H "Content-Type: application/json" \
  -H "stripe-signature: test_signature" \
  -d @test-event.json

İzleme

Webhook teslimatını takip edin:

  • Yanıt süreleri
  • Başarı/başarısızlık oranları
  • Olay işleme süresi
  • Manuel müdahale gerektiren başarısız olaylar

Çoğu sağlayıcı, teslimat denemelerini ve başarısızlıkları gösteren webhook izleme panelleri sunar.