Merhaba,

 

Bu yazıda Laravel ile Stripe Ödeme Sistemi Entegrasyonu'ndan bahsedeceğim.

 

İlk olarak boş bir Laravel projesi oluşturduğunuzu varsayıyorum. Terminali açıp Stripe için gerekli paketi kuracak olan şu kodu yazıyoruz:

composer require stripe/stripe-php

 

Sonrasında bir Stripe hesabı oluşturup API keys verilerine ulaşmamız gerekiyor. Stripe'ın resmi sitesi üzerinden üyelik kaydınızı oluşturmak için buraya tıklayabilirsiniz. Kayıt olup giriş yaptıktan sonra Home ekranında Get your test API keys kısmında yer alan Publishable key ve Secret key değerlerini kopyalayıp .env dosyamıza yapıştırıyoruz:

STRIPE_PUBLISHABLE_KEY=pk_test_xxx
STRIPE_SECRET_KEY=sk_test_xxx

 

Bu bilgileri projemizde kullanmak adına config klasörü altına stripe.php şeklinde bir dosya oluşturuyoruz:

<?php

return [
  'publishable_key' => env('STRIPE_PUBLISHABLE_KEY'),
  'secret_key' => env('STRIPE_SECRET_KEY'),
  'merchant_url' => env('APP_URL')
];

 

Bu değişikliklerin aktif olması için terminalde gerekli komutu çalıştırıyoruz:

php artisan config:cache

 

Kart bilgilerini yazıp ödeme yapabileceğimiz basit bir ekran arayüz için resources/views klasörü altına payment.blade.php dosyası oluşturuyoruz:

<html>
  <head>
    <title>Stripe Integration Sample</title>
    <style>
      .form {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
      }
      .input {
        border-radius: 8px;
        padding: 8px;
        margin-bottom: 8px;
      }
      .button {
        padding: 8px;
        border-radius: 8px;
        background: green;
        color: white;
        width: 100px;
      }
    </style>
  </head>
  <body>
    <form action="{{ route('payment_post') }}" method="post">
      @csrf
      <div class="form">
        <input type="text" class="input" name="holder_name" placeholder="Holder Name" />
        <input type="text" class="input" name="card_number" placeholder="Card Number" />
        <input type="number" class="input" name="month" placeholder="Month" />
        <input type="number" class="input" name="year" placeholder="Year" />
        <input type="number" class="input" name="cvc" placeholder="Cvc" />
        <input type="submit" class="button" value="Pay" />
      </div>
    </form>
  </body>
</html>

 

Controller dosyamızı oluşturmak için gerekli kodu terminale yazıyoruz:

php artisan make:controller PaymentController

 

routes/web.php altında ihtiyacımız olan route dosyalarını tanımlıyoruz:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PaymentController;

Route::get('/payment', [PaymentController::class, 'index'])->name('payment');
Route::post('/payment', [PaymentController::class, 'store'])->name('payment_post');
Route::get('/stripe-3ds-result', [PaymentController::class, 'stripe3dsResult'])->name('stripe_3ds_result');
  • /payment (GET) => Kredi kartı bilgilerinin yazılacağı view'i döndürmek için kullanılacak url
  • /payment (POST) => Gerekli bilgileri (kredi kartı, fiyat, müşteri) Stripe'a gönderip gelen sonuca göre işlem yapmak için kullanılacak url
  • /stripe-3ds-result (GET) => Ödemenin 3ds ile gerçekleşmesi durumunda Stripe'ın geri dönüş yapacağı url

 

PaymentController dosyamızı açıp gerekli kodları yazıyoruz, gerekli açıklamaları kod üzerinde bulabilirsiniz:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Redirect;

class PaymentController extends Controller
{
    public function index()
    {
        return view('payment');
    }

    public function store()
    {
        // kart bilgilerini alıyoruz.
        $holder_name = request()->holder_name;
        $card_number = request()->card_number;
        $month = request()->month;
        $year = request()->year;
        $cvc = request()->cvc;

        // örnek olarak karttan 1$ çekeceğiz. stripe dokümanında belirtildiği üzere karttan çekilecek değeri 100 ile çarpmamız gerekiyor.
        $currency = 'USD';
        $price = 1 * 100;

        // stripe secret_key bilgisini config'den alıyoruz.
        $stripe = new \Stripe\StripeClient(
            config('stripe.secret_key')
        );        

        try {
            // kart bilgilerini kullanarak stripe tarafında bir token elde ediyoruz.
            $stripeToken = $stripe->tokens->create([
                'card' => [
                    'number' => $card_number,
                    'exp_month' => $month,
                    'exp_year' => $year,
                    'cvc' => $cvc
                ]
            ]);

            // müşteri adını ve kart bilgisini stripe tarafında kaydediyoruz.
            $customer = $stripe->customers->create([
                'name' => $holder_name,
                'source' => $stripeToken['id']
            ]);

            // stripe tarafında bir setupIntent oluşturuyoruz. 
            // setupIntent işlemi sonucunda stripe, girilen kartın 3ds gerektirip gerektirmediğiyle ilgili bir doğrulama yapıyor.
            // stripe'ın ödeme sonucunu iletmesi için 'return_url' parametresini belirtiyoruz.
            // 3ds ekranı sonrası para çekme işleminde kullanmak için 'metadata' kısmında fiyat ve para birimi değerlerini gönderiyoruz.
            $setupIntent = $stripe->setupIntents->create([
                'customer' => $customer['id'],
                'description' => 'test',
                'payment_method' => $stripeToken['card']['id'],
                'payment_method_types' => ['card'],
                'payment_method_options' => [
                    'card' => [
                        'request_three_d_secure' => 'any'
                    ]
                ],
                'confirm' => true,
                'return_url' => config('stripe.merchant_url') .'/stripe-3ds-result',
                'metadata' => [
                    'price' => $price,
                    'currency' => $currency
                ]
            ]);
        }
        // hata oluşması durumunda hata mesajını json olarak ekrana yazdırıyoruz.
        catch (\Stripe\Exception\ApiErrorException $e) {
            return response()->json($e->getMessage(), 500);
        }

        // eğer doğrulama sonucunda ödeme normal (3ds olmadan) gerçekleşecekse direkt olarak para çekme işlemini yapıyoruz.
        if ($setupIntent['status'] == 'succeeded') {
            try {
                $charge = $stripe->charges->create([
                    'customer' => $setupIntent['customer'],
                    'amount' => $price,
                    'currency' => $currency,
                    'description' => 'test',
                    'source' => $stripeToken['card']['id']
                ]);
            } 
            // hata oluşması durumunda hata mesajını json olarak ekrana yazdırıyoruz.
            catch (\Stripe\Exception\ApiErrorException $e) {
                return response()->json($e->getMessage(), 500);
            }

            // para çekme işleminde bir sorun olursa ekrana hata yazdırıyoruz.
            if ($charge['status'] != 'succeeded') {
                return response()->json('Payment error!', 500);
            } else {
                // para çekme işlemi başarılı sonuçlanırsa stripe'dan dönen veriyi ekrana basıyoruz.
                return response()->json($charge, 200);
            }            
        }

        // eğer doğrulama sonucunda ödeme 3ds ile gerçekleşecekse kullanıcıyı stripe'ın gönderdiği 3ds ekranına yönlendiriyoruz.
        if ($setupIntent['status'] == 'requires_action') {
            return Redirect::to($setupIntent['next_action']['redirect_to_url']['url']);
        } else {
            // setupIntent işleminde bir sorun olursa ekrana hata yazdırıyoruz.
            return response()->json('3ds payment error!', 500);
        }        
    }

    public function stripe3dsResult()
    {
        $stripe = new \Stripe\StripeClient(
            config('stripe.secret_key')
        );

        // stripe tarafından gönderilen setupIntent id'yi kullanarak setupIntent'e ulaşıyoruz.
        $setupIntent = $stripe->setupIntents->retrieve(
            request()->setup_intent
        );        

        // 'metadata' ile gönderdiğimiz fiyat ve para birimi değerlerine ulaşıyoruz.
        $price = $setupIntent['metadata']['price'];
        $currency = $setupIntent['metadata']['currency'];

        // setupIntent'in sonucu başarılı ise para çekme işlemini yapıyoruz.
        if ($setupIntent['status'] == 'succeeded') {            
            try {
                $charge = $stripe->charges->create([
                    'customer' => $setupIntent['customer'],
                    'amount' => $price,
                    'currency' => $currency,
                    'description' => 'test',
                    'source' => $setupIntent['payment_method']
                ]);
            } 
            // hata oluşması durumunda hata mesajını json olarak ekrana yazdırıyoruz.
            catch (\Stripe\Exception\ApiErrorException $e) {
                return response()->json($e->getMessage(), 500);
            }

            // para çekme işleminde bir sorun olursa ekrana hata yazdırıyoruz.
            if ($charge['status'] != 'succeeded') {
                return response()->json('3ds payment error!', 500);
            } else {
                // para çekme işlemi başarılı sonuçlanırsa stripe'dan dönen veriyi ekrana basıyoruz.
                return response()->json($charge, 200);
            }
        } else {
            // setupIntent işleminde bir sorun olursa ekrana hata yazdırıyoruz.
            return response()->json('3ds payment error!', 500);
        }
    }
}

 

Ve artık projemizi ayağa kaldırabiliriz:

php artisan serve

 

Stripe'ın resmi sitesinde yer alan şu linkten test kartlarına bakabilirsiniz.

 

Normal (3ds olmadan) ödeme örneği;

3ds ile ödeme örneği;

 

Stripe panelinde ödemelerin görüntüsü;

 

Örnek projenin kaynak kodlarına buradan ulaşabilirsiniz.

 

Umarım yararlı olmuştur.

 

İyi çalışmalar.