Node.js İle Stripe Kullanarak Güvenli Ödeme Entegrasyonu Nasıl Yapılır?

Node.js İle Stripe Kullanarak Güvenli Ödeme Entegrasyonu Nasıl Yapılır?
Node.js İle Stripe Kullanarak Güvenli Ödeme Entegrasyonu Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Projenize başlamadan önce bilgisayarınızda Node.js'in güncel LTS (Long Term Support) sürümünün yüklü olduğundan emin olmalısınız. Ayrıca Stripe üzerinde bir hesap oluşturarak "Test Mode" anahtarlarınıza erişim sağlamanız gerekmektedir.

  • Node.js (v20 veya üzeri önerilir)
  • npm veya pnpm paket yöneticisi
  • Stripe hesabı (Dashboard üzerinden API Secret Key ve Publishable Key)
  • Postman veya Stripe CLI (Test süreçleri için)

Projenizi başlatmak için terminalinizde gerekli kütüphaneleri kurarak işe koyulalım. Aşağıdaki komut, temel bağımlılıkları projenize dahil edecektir.

npm init -y
npm install express stripe dotenv cors

Bu komutlar; sunucu çatısı için express, Stripe ile iletişim kurmak için stripe, ortam değişkenlerini yönetmek için dotenv ve tarayıcı kaynaklı erişim hatalarını önlemek için cors paketlerini yükler.

Stripe API Anahtarlarının Güvenli Yönetimi

Güvenlik, ödeme sistemlerinde en önemli husustur. API anahtarlarınızı asla kodun içine doğrudan yazmamalısınız. Bunun yerine .env dosyasını kullanarak anahtarları gizli tutmak, üretim ortamında (production) güvenliği sağlamanın ilk adımıdır.

Proje dizininizde .env adında bir dosya oluşturun ve içerisine aşağıdaki değişkenleri ekleyin:

STRIPE_SECRET_KEY=sk_test_51...
STRIPE_PUBLISHABLE_KEY=pk_test_51...
PORT=3000

Bu değişkenleri Node.js uygulamanızda kullanmak için dotenv paketini yapılandırmanız gerekir. Aşağıdaki kod bloğu, sunucunuzun temel başlangıç ayarlarını gösterir.

require('dotenv').config();
const express = require('express');
const app = express();

app.use(express.json());
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

app.listen(process.env.PORT, () => {
    console.log(`Sunucu ${process.env.PORT} portunda çalışıyor.`);
});
Kritik Güvenlik Uyarısı: .env dosyanızı asla GitHub gibi herkese açık versiyon kontrol sistemlerine yüklemeyin. .gitignore dosyanıza .env eklediğinizden emin olun.

Payment Intent (Ödeme Niyeti) Oluşturma

Stripe'ın güncel API'si, doğrudan kart numarasıyla işlem yapmak yerine "Payment Intent" (Ödeme Niyeti) yapısını kullanır. Bu, ödeme sürecinin durumunu (başarılı, başarısız, onay bekliyor) takip etmemizi sağlar. Aşağıdaki örnek, istemciden gelen bir tutar bilgisiyle ödeme niyetini nasıl oluşturacağınızı gösterir.

app.post('/create-payment-intent', async (req, res) => {
    const { amount } = req.body; // Tutar kuruş cinsinden (örn: 1000 = 10.00 TL)

    try {
        const paymentIntent = await stripe.paymentIntents.create({
            amount: amount,
            currency: 'try',
            automatic_payment_methods: { enabled: true },
        });

        res.send({ clientSecret: paymentIntent.client_secret });
    } catch (error) {
        res.status(500).send({ error: error.message });
    }
});

Bu endpoint, istemci tarafına bir client_secret döner. Frontend (React, Vue veya düz JavaScript) bu anahtarı kullanarak Stripe Elements kütüphanesi ile güvenli bir ödeme formu oluşturur.

Ödeme Yöntemlerinin Karşılaştırılması

Stripe entegrasyonunda farklı yöntemler mevcuttur. İhtiyacınıza en uygun olanı seçmek için aşağıdaki tabloyu inceleyebilirsiniz.

Yöntem Avantajı Dezavantajı
Stripe Elements Tam özelleştirme, yüksek güvenlik Daha fazla frontend kodu
Stripe Checkout Hızlı entegrasyon, hazır UI Düşük özelleştirme

Webhooks ile Ödeme Sonuçlarını Doğrulama

Ödeme işlemi tamamlandığında, Stripe sunucunuza bir bildirim gönderir. Bu işleme "Webhook" denir. Ödeme başarılı olduktan sonra veritabanınızda siparişi güncellemek için bu mekanizmayı kullanmalısınız. Webhook uç noktası, Stripe'ın gönderdiği verinin doğruluğunu kontrol etmek için bir imza (signature) doğrulaması gerektirir.

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
    const sig = req.headers['stripe-signature'];
    let event;

    try {
        event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
    } catch (err) {
        return res.status(400).send(`Webhook Hatası: ${err.message}`);
    }

    if (event.type === 'payment_intent.succeeded') {
        const paymentIntent = event.data.object;
        console.log('Ödeme başarılı:', paymentIntent.id);
        // Burada veritabanı güncelleme işlemlerinizi yapın
    }

    res.json({received: true});
});

Bu kod bloğu, gelen isteğin gerçekten Stripe'tan geldiğini doğrular. stripe-signature kontrolü yapılmadan işlem yapmak, kötü niyetli kişilerin sahte bildirimler göndermesine yol açabilir.

Önemli: Webhook uç noktalarınızın express.json() değil, express.raw() ile işlenmesi gerekir çünkü imza doğrulaması için ham (raw) buffer verisine ihtiyaç vardır.

Yaygın Hatalar ve Debug İpuçları

Entegrasyon sırasında en sık karşılaşılan sorunlar genellikle yanlış yapılandırılmış API anahtarları veya geçersiz para birimi kodlarıdır. Stripe'ın sağladığı "Logs" sekmesi, hata ayıklama sürecinde en büyük yardımcınızdır.

  • 401 Unauthorized: API anahtarınızın yanlış veya kısıtlı olduğunu gösterir.
  • 400 Bad Request: Gönderilen tutarın veya para biriminin yanlış formatta olduğunu belirtir.
  • Webhook Hatası: Webhook Secret anahtarınızın güncel olmadığını veya imza doğrulaması yapılamadığını gösterir.

Sıkça Sorulan Sorular

Stripe ödemeleri için veritabanında hangi verileri tutmalıyım?

Kullanıcının kart bilgilerini asla veritabanınızda tutmayın. Sadece Stripe'ın size döndüğü payment_intent_id, customer_id ve işlem durumu gibi meta verileri saklamanız yeterlidir.

Ödeme sırasında para birimi olarak ne kullanmalıyım?

Stripe, tutarları en küçük birim üzerinden hesaplar. Örneğin, Türk Lirası (TRY) için 10 TL, 1000 kuruş olarak gönderilmelidir.

Test ortamından canlı ortama nasıl geçerim?

Stripe Dashboard üzerinden "Test Mode" anahtarlarını, "Live Mode" anahtarlarıyla değiştirmeniz ve webhook URL'lerinizi canlı sunucunuza göre güncellemeniz yeterlidir.

Stripe güvenli mi?

Stripe, PCI-DSS Level 1 uyumludur; yani dünyanın en yüksek ödeme güvenliği standartlarına sahiptir. Kart verileri sizin sunucunuza uğramadan doğrudan Stripe'a gider.

Ödeme başarısız olursa ne yapmalıyım?

Stripe, payment_intent.payment_failed gibi olayları webhook üzerinden size bildirir. Bu durumda kullanıcıyı bilgilendiren bir e-posta veya uygulama içi bildirim tetiklemelisiniz.

Stripe Entegrasyonunda Performans ve Ölçeklenebilirlik İpuçları

Ödeme sistemleri, uygulamanızın en kritik noktalarından biridir. Yüksek trafikli bir uygulamada, Stripe API çağrılarını yönetirken performans darboğazlarını önlemek ve sistemin ölçeklenebilirliğini sağlamak için aşağıdaki stratejileri uygulamalısınız.

1. Asenkron İşlemler ve Kuyruk Yönetimi

Ödeme onaylandıktan sonra veritabanı güncellemesi, fatura oluşturma veya e-posta gönderimi gibi işlemlerin kullanıcıyı bekletmemesi gerekir. Bu tür işlemleri ana iş akışından ayırarak bir mesaj kuyruğu (RabbitMQ, Redis veya BullMQ) üzerinden yönetmek, uygulamanızın yanıt süresini (latency) ciddi oranda düşürür.

// BullMQ kullanarak arka plan işi oluşturma örneği
const { Queue } = require('bullmq');
const emailQueue = new Queue('email-notifications');

// Webhook içerisinde e-posta gönderimini kuyruğa ekle
await emailQueue.add('send-receipt', {
  userId: user.id,
  amount: paymentIntent.amount,
  email: user.email
});

2. API İsteklerinde Rate Limiting (Hız Sınırlaması)

Stripe'ın kendi hız sınırlamaları olsa da, kendi sunucunuzu korumak için express-rate-limit gibi kütüphaneler kullanarak ödeme endpoint'lerinize gelen istekleri sınırlandırmalısınız. Bu, özellikle bot saldırılarına karşı uygulamanızı korur.

Stripe İleri Düzey Hata Ayıklama ve Loglama

Üretim ortamında (production) bir ödeme başarısız olduğunda, hatanın kaynağını hızlıca tespit etmek hayati önem taşır. Sadece hata mesajını loglamak yerine, bağlamsal verileri de içeren bir loglama stratejisi izlemelisiniz.

İzlenebilirlik (Observability) İçin Loglama

Stripe'tan dönen request_id değerini mutlaka veritabanınıza kaydedin. Bu ID, Stripe Dashboard üzerinde ilgili isteği saniyeler içinde bulmanızı sağlar. Ayrıca, hata anında gönderilen payload verisini (hassas kart bilgileri hariç) loglamak, sorunu yerel ortamda simüle etmenizi kolaylaştırır.

try {
  const paymentIntent = await stripe.paymentIntents.create({
    amount: 2000,
    currency: 'try',
  });
} catch (err) {
  console.error(`Stripe Hatası [${err.requestId}]:`, {
    type: err.type,
    code: err.code,
    message: err.message,
    param: err.param
  });
  // Hata izleme servisine (Sentry vb.) gönder
  throw err;
}

Ödeme Başarısızlık Senaryoları Tablosu

Hata Kodu Anlamı Önerilen Aksiyon
card_declined Kart yetersiz bakiye veya banka reddi. Kullanıcıya kart bilgilerini kontrol etmesini söyleyin.
expired_card Kartın son kullanma tarihi geçmiş. Kullanıcıdan yeni bir ödeme yöntemi girmesini isteyin.
rate_limit API istek limiti aşıldı. Exponential backoff (üstel geri çekilme) stratejisi uygulayın.

Bu yapıları uygulayarak, Stripe entegrasyonunuzu sadece çalışan bir kod yığını olmaktan çıkarıp, kurumsal düzeyde yönetilebilir ve güvenli bir ödeme altyapısına dönüştürebilirsiniz.

Sonuç

Node.js ile Stripe entegrasyonu, doğru adımları takip ettiğinizde oldukça güvenli ve sürdürülebilir bir süreçtir. Bu rehberde, bir ödeme niyetinin oluşturulmasından, webhook ile güvenli doğrulamaya kadar tüm süreci ele aldık. Bir sonraki adım olarak, Stripe'ın sunduğu "Customer" (Müşteri) nesnelerini kullanarak abonelik tabanlı ödeme modellerini (Stripe Billing) araştırmanızı öneririm.

Sorumluluk Reddi: Bu makale yazılım eğitimi amaçlıdır. Ödeme sistemleri finansal sorumluluk içerir. Üretim ortamına geçmeden önce PCI-DSS uyumluluğu ve Stripe'ın güncel dokümantasyonunu mutlaka inceleyin. Finansal veya hukuki konularda uzman görüşü almanız tavsiye edilir.
Bu yazıya tepkinizi paylaşın:
Selin Korkmaz

Kendin yap (DIY) projeleri ve sürdürülebilir yaşam ipuçları üzerine odaklanıyorum. Okuyucularıma bütçe dostu ve yaratıcı çözüm önerileri sunmaktan keyif alıyorum.

Yorumlar (0)

Yorum Yaz