Laravel 11 - Stripe Payment Gateway Integration

Touseef Afridi
07 Jan 25

Laravel 11 - Stripe Payment Gateway Integration

In this tutorial, we will discuss how to integrate Laravel 11 with Stripe Payment Gateway. Learn the setup, configuration, and best practices to simplify online payments in your Laravel applications.


If you're a video person, feel free to skip the post and check out the video instead!


Quick Overview

This guide walks you through integrating Stripe payment processing into a Laravel application. After setting up a fresh Laravel project and installing the Stripe PHP package, you'll configure the necessary API keys in the .env file. A CheckoutController is created to handle the payment flow, including generating a PaymentIntent with Stripe's API. A view is used to display the payment form with Stripe Elements for secure card input. The payment process is completed through a route, and users are shown a success message upon successful payment. This guide ensures a seamless integration of Stripe for secure payments in any Laravel project.

Step # 1 : Create a Fresh Laravel Project or Use an Existing Laravel Project.

If you have Laravel globally installed, use the following command
laravel new stripe
Or
Alternatively, if you do not have Laravel globally installed, use the Composer command.
composer create-project laravel/laravel --prefer-dist stripe
After running one of the above commands, you'll be prompted with the following options.
  1. Would you like to install the starter kit? — Select none.
  2. Select the testing framework. — Choose Pest.
  3. Select the database for your application. — Choose mysql.
  4. Run the default database migration? — Select yes.

Step # 2 : Access the project.

Open a terminal (e.g., Git Bash) and navigate to your Laravel project's root folder.
cd c:xampp/htdocs/stripe

Step # 3 : Install Stripe package.

To integrate Stripe into your Laravel project, use the following command to install the Stripe package.
composer require stripe/stripe-php

Step # 4 : Set Up a Stripe Account.

Create an account on Stripe by visiting the (link: https://stripe.com/). Once your account is set up, navigate to the Stripe dashboard to access your publishable and secret keys, which you'll use for integrating Stripe into your application.

Step # 5: Configure Stripe Keys.

Open the .env file in your Laravel project and add the following entries, replacing YOUR_PUBLISHABLE_KEY and YOUR_SECRET_KEY with the actual keys from your Stripe dashboard.
STRIPE_KEY=YOUR_PUBLISHABLE_KEY
STRIPE_SECRET=YOUR_SECRET_KEY
These keys will allow your application to communicate securely with the Stripe API for payment processing.

Step # 6 : Create the CheckoutController.

Generate a new controller using the following Artisan command.
php artisan make:controller CheckoutController
This will create a CheckoutController.php file in the app/Http/Controllers directory, where you can define the logic for handling payments and checkout functionality. Next, update the CheckoutController with the provided code.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class CheckoutController extends Controller
{
    //Initiates the checkout process and creates a Stripe PaymentIntent.
    public function checkout()
    {
        // Set Stripe secret key from .env
        \Stripe\Stripe::setApiKey(env('STRIPE_SECRET'));
        // Amount in fils. Stripe uses the smallest unit of the currency, so for AED (1 AED = 100 fils), we multiply the desired amount by 100 to convert it to fils.
        $amount = 200 * 100; // Convert 200 AED to fils (1 AED = 100 fils)
        try {
            // Create a new PaymentIntent with Stripe
            $payment_intent = \Stripe\PaymentIntent::create([
                // Payment description
                'description' => 'Code Shotcut Stripe Test Payment',
                // Payment amount in fils
                'amount' => $amount,
                // Currency (AED in this case)
                'currency' => 'aed',
                // Payment method type (card)
                'payment_method_types' => ['card'],
            ]);
            // Get the client secret to authenticate the payment on the frontend
            $intent = $payment_intent->client_secret;
            // Return view with the payment intent client secret
            return view('credit-card', compact('intent'));
        } catch (\Exception $e) {
            // Handle any errors during the payment creation process
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }
    //Handles the post-payment process.
    public function afterPayment()
    {
        // Display a message confirming the payment was successful
        return 'Payment received. Thank you for using our services.';
    }
}
The CheckoutController handles the checkout and payment flow using Stripe's PaymentIntent. It ensures the payment amount is converted to the smallest unit (fils) for the AED currency and communicates with Stripe's API to create a payment intent and process payments securely.

Step # 7 : Create routes.

Import the CheckoutController class.
use App\Http\Controllers\CheckoutController;
Define routes for checkout and payment process.
Route::get('/checkout', [CheckoutController::class, 'checkout']);
Route::post('/checkout', [CheckoutController::class, 'afterPayment'])->name('credit-card');
These routes map the GET request to the /checkout route to initiate the checkout process, while the POST request to /checkout will handle the post-payment process after the payment is completed.

Step # 8 : Create a view.

Create a view named credit-card.blade.php and update it with the following code.
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Code Shotcut - Stripe Payment</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-900 flex items-center justify-center min-h-screen">
    <div class="w-full max-w-2xl">
        <!-- Container for Payment Process -->
        <div id="payment-container">
            <!-- Display the total amount -->
            <div class="text-lg font-semibold text-white mb-4 text-center">
                <p>Your Total Amount is 200 AED</p>
            </div>
            <!-- Payment form container -->
            <div class="bg-white shadow-md rounded-lg p-6">
                <form action="{{ route('credit-card') }}" method="post" id="payment-form">
                    @csrf
                    <!-- Card information input section -->
                    <div class="mb-4">
                        <div class="text-lg font-medium mb-2">
                            <label for="card-element">Enter your credit card information</label>
                        </div>
                        <div class="border rounded p-4" id="card-element">
                            <!-- A Stripe Element will be inserted here. -->
                        </div>
                        <!-- Display card input errors -->
                        <div class="text-red-500 text-sm mt-2" id="card-errors" role="alert"></div>
                        <input type="hidden" name="plan" value="" />
                    </div>
                    <!-- Submit button section -->
                    <div class="text-right">
                        <button
                            id="card-button"
                            class="bg-gray-800 text-white px-6 py-3 rounded hover:bg-gray-900"
                            type="submit"
                            data-secret="{{ $intent }}"
                        >
                            Pay
                        </button>
                    </div>
                </form>
            </div>
        </div>
        <!-- Success message container (hidden initially) -->
        <div id="success-container" class="hidden bg-green-100 border-l-4 border-green-500 text-green-700 p-4 rounded">
            <h2 class="text-xl font-semibold">Payment Successful!</h2>
            <p class="mt-2">Thank you for your payment. Your transaction has been processed successfully.</p>
        </div>
    </div>
    <!-- Stripe JS library -->
    <script src="https://js.stripe.com/v3/"></script>
    <script>
        // Define style for Stripe elements
        var style = {
            base: {
                color: '#32325d',
                lineHeight: '18px',
                fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
                fontSmoothing: 'antialiased',
                fontSize: '16px',
                '::placeholder': {
                    color: '#aab7c4'
                }
            },
            invalid: {
                color: '#fa755a',
                iconColor: '#fa755a'
            }
        };
        // Initialize Stripe and create card element
        const stripe = Stripe('{{ env('STRIPE_KEY') }}', { locale: 'en' });
        const elements = stripe.elements();
        const cardElement = elements.create('card', { style: style });
        const cardButton = document.getElementById('card-button');
        const clientSecret = cardButton.dataset.secret;
        // Mount the card element to the DOM
        cardElement.mount('#card-element');
        // Handle real-time validation errors from the card Element
        cardElement.addEventListener('change', function(event) {
            var displayError = document.getElementById('card-errors');
            if (event.error) {
                displayError.textContent = event.error.message;
            } else {
                displayError.textContent = '';
            }
        });
        // Handle form submission
        var form = document.getElementById('payment-form');
        form.addEventListener('submit', function(event) {
            event.preventDefault();
            // Confirm the card payment with Stripe
            stripe.handleCardPayment(clientSecret, cardElement, {
                payment_method_data: {}
            })
            .then(function(result) {
                if (result.error) {
                    // Display error if payment fails
                    var errorElement = document.getElementById('card-errors');
                    errorElement.textContent = result.error.message;
                } else {
                    // Hide the payment form and show the success message
                    document.getElementById('payment-container').classList.add('hidden');
                    document.getElementById('success-container').classList.remove('hidden');
                }
            });
        });
    </script>
</body>
</html>
This view handles Stripe payments by rendering the payment form and displaying success/failure messages. It uses Stripe's Elements for secure card details input, and upon successful payment, displays a success message to the user.

Step # 9 : It's time to test.

Start the Laravel development server by running the following command
php artisan serve
Then, visit the following URL in your browser
127.0.0.1/checkout

Step # 10 : Test Stripe integration using below dummy data.

Use the following dummy card details to test the Stripe integration.
Card Number - 4242 4242 4242 4242
EXP - 12/32
CVV - 123
ZIP - 12345

If you have followed all the steps correctly, you should see the success message

You can also view the transaction details in the Stripe Dashboard under Transactions.

Conclusion

By following this process, you can seamlessly integrate Stripe payment processing into your Laravel application. The Stripe PHP package simplifies handling secure payments, and the step-by-step guide ensures a smooth checkout experience for users. With this setup, you can easily process payments, display success messages, and manage transactions. This integration can be extended for more advanced payment features, such as subscription models or multi-currency support, making it ideal for various business applications, including e-commerce sites, subscription services, or donation platforms.
For more details, please refer to the Stripe documentation.
Share this with friends!


"Give this post some love and slap that 💖 button as if it owes you money! 💸😄"
0

0 Comments

To engage in commentary, kindly proceed by logging in or registering