💳 Step 8 : Integrating a Secure Payment Gateway (Stripe & PayPal)
Up until now, your Laravel shop can:
- Display products on the storefront
- Add items to the cart
- Checkout and place orders
- Store order details and show order history in the admin panel
But right now, all orders are created without any actual money changing hands. That’s fine for testing, but in the real world, you need to collect secure payments from customers.
This step is all about transforming your store from a basic shop into a real revenue-generating platform by integrating Stripe and/or PayPal.
🧭 What You’ll Learn in This Step
- Why payment gateways matter (and how to choose the right one)
- Setting up a Stripe account and test keys
- Installing and configuring Stripe in Laravel
- Building a payment page connected to Stripe Checkout
- Processing payments and updating order status
- Setting up PayPal as an optional alternative (for more customer flexibility)
- Real-world security and usability tips
⚡ Why Stripe (and PayPal) Are Popular Choices
There are hundreds of payment gateways, but Stripe and PayPal dominate small to medium e-commerce businesses for a reason:
| Feature | Stripe | PayPal |
|---|---|---|
| Setup speed | Very easy | Easy |
| Developer friendly | Excellent APIs & docs | Good APIs |
| Global availability | 40+ countries | 200+ countries |
| Payment methods | Cards, Apple Pay, Google Pay | PayPal balance, cards, banks |
| Fees | ~2.9% + 30¢ per transaction | Similar |
Tip: It’s common to offer both: Stripe for credit/debit cards, and PayPal for customers who prefer that wallet.
🧩 Step 1 : Setting Up Stripe
1. Create a Stripe Account
- Go to https://stripe.com and sign up
- Verify your email and activate test mode
- Get your Publishable key and Secret key from your Stripe Dashboard → Developers → API keys
For testing, you can use test cards like 4242 4242 4242 4242 with any future date and any CVC.
🧩 Step 2 : Installing Stripe PHP SDK in Laravel
In your Laravel project folder, run:
composer require stripe/stripe-php
This installs the official Stripe PHP library.
Then add your keys to .env:
STRIPE_KEY=pk_test_your_publishable_key
STRIPE_SECRET=sk_test_your_secret_key
And add them to config/services.php for convenience:
'stripe' => [
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
🧩 Step 3 : Adding a Payment Button to Checkout
Let’s connect your checkout flow to Stripe.
Create a PaymentController:
php artisan make:controller PaymentController
Open app/Http/Controllers/PaymentController.php and add:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Stripe\Stripe;
use Stripe\Checkout\Session as StripeSession;
use App\Models\Order;
class PaymentController extends Controller
{
public function createCheckout($orderId)
{
$order = Order::with('items.product')->findOrFail($orderId);
Stripe::setApiKey(config('services.stripe.secret'));
$lineItems = [];
foreach ($order->items as $item) {
$lineItems[] = [
'price_data' => [
'currency' => 'usd',
'product_data' => [
'name' => $item->product->name
],
'unit_amount' => $item->price * 100,
],
'quantity' => $item->quantity,
];
}
$checkoutSession = StripeSession::create([
'payment_method_types' => ['card'],
'line_items' => $lineItems,
'mode' => 'payment',
'success_url' => route('payment.success', $order->id) . '?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('payment.cancel', $order->id),
]);
return redirect($checkoutSession->url);
}
public function success(Request $request, $orderId)
{
$order = Order::findOrFail($orderId);
$order->update(['status' => 'paid']);
return view('payment.success', compact('order'));
}
public function cancel($orderId)
{
$order = Order::findOrFail($orderId);
return view('payment.cancel', compact('order'));
}
}
🧩 Step 4 : Adding Routes for Payment
In routes/web.php:
use App\Http\Controllers\PaymentController;
Route::get('/pay/{order}', [PaymentController::class, 'createCheckout'])->name('payment.checkout');
Route::get('/payment-success/{order}', [PaymentController::class, 'success'])->name('payment.success');
Route::get('/payment-cancel/{order}', [PaymentController::class, 'cancel'])->name('payment.cancel');
🧩 Step 5 : Payment Views
resources/views/payment/success.blade.php
@extends('layouts.app')
@section('content')
<div class="container text-center my-5">
<h2 class="text-success">Payment Successful!</h2>
<p>Thank you for your purchase. Your order #{{ $order->id }} has been paid.</p>
<a href="{{ route('shop.index') }}" class="btn btn-primary mt-4">Back to Store</a>
</div>
@endsection
resources/views/payment/cancel.blade.php
@extends('layouts.app')
@section('content')
<div class="container text-center my-5">
<h2 class="text-danger">Payment Canceled</h2>
<p>Your payment was not completed. You can try again below.</p>
<a href="{{ route('payment.checkout', $order->id) }}" class="btn btn-warning mt-4">Try Again</a>
</div>
@endsection
🧩 Step 6 : Linking Checkout to Payment
Update your thank-you page (Step 7) to show a “Pay Now” button if the order is still pending:
@if($order->status === 'pending')
<a href="{{ route('payment.checkout', $order->id) }}" class="btn btn-success mt-3">Pay Now</a>
@endif
This lets the user pay immediately after placing their order.
🧩 Step 7 : Optional: Adding PayPal Integration
If you want to offer PayPal as well, the easiest way is to use the official PayPal Checkout JavaScript SDK.
Basic steps:
- Create a PayPal business account on https://developer.paypal.com
- Get your Client ID and Secret for the sandbox (test) environment
- Install the PayPal SDK:
composer require paypal/rest-api-sdk-php
- Create a controller
PayPalControllerthat:
- Creates a payment request
- Redirects user to PayPal
- Handles success/cancel callbacks
- Updates the order status to
paid
Because Stripe and PayPal flows are similar, you can mirror the logic of PaymentController but use the PayPal SDK.
💡 Real-World Tips for Secure Payments
- ✅ Always use HTTPS (SSL) in production. Payment gateways will refuse callbacks if your site is not secure.
- 🔒 Never store raw card data — let Stripe/PayPal handle it entirely.
- 📩 Send a payment confirmation email after successful payment using Laravel’s
Mailfeature. - 💰 Show order totals and items again on the payment page for user trust.
- 📊 Track
statusaspending,paid,failed, andrefundedfor clarity. - 💳 Test thoroughly using Stripe test cards and PayPal sandbox before going live.
✅ Summary of Step 8
At this point, your Laravel e-commerce store is now capable of:
- Accepting real payments securely
- Supporting Stripe credit/debit card checkout
- Optionally integrating PayPal for flexibility
- Automatically marking orders as paid
- Giving customers a seamless checkout → payment → confirmation flow
⚡ Coming Next : Step 9: Building User Accounts and Order History
Right now, customers checkout as “guests.” In the next part, we’ll:
- Add user registration/login
- Link orders to users
- Let customers view past orders
- Let admin see which user placed which order