ServerAvatar Logo

Quick Stripe Integration Guide for Laravel Users

  • Author: Suresh Ramani
  • Published: 9 August 2025
  • Last Updated: 8 August 2025
Stripe Integration Laravel

Table Of Contents

Introduction

Have you ever wondered why some websites make online payments feel as smooth as butter while others leave you frustrated and clicking away? The secret often lies in their payment gateway integration. If you’re a Laravel developer looking to Stripe integrate into your application, you’re in the right place!

Think of Stripe as the Swiss Army knife of payment processing – it’s versatile, reliable, and packed with features that make handling online payments a breeze. When combined with Laravel’s elegant framework, you get a powerhouse combination that can handle everything from simple one-time payments to complex subscription billing.

Understanding Stripe and Laravel Integration

What Makes Stripe Perfect for Laravel?

Stripe isn’t just another payment processor – it’s a complete payment infrastructure that speaks the same language as modern web developers. When you combine it with Laravel, you’re essentially pairing a Ferrari engine with a Formula 1 chassis.

Laravel’s built-in features like middlewarevalidation, and Eloquent ORM work seamlessly with Stripe’s API structure. The framework’s service container makes it easy to inject Stripe services wherever you need them, while Laravel’s event system perfectly complements Stripe’s webhook functionality.

Key Benefits of This Integration

The stripe laravel combination offers several advantages:

  • Rapid development with pre-built components
  • Robust security through Laravel’s built-in protections
  • Scalable architecture that grows with your business
  • Comprehensive documentation and community support

Prerequisites and Setup Requirements

What You’ll Need Before Starting

Before diving into the integration, make sure you have these essentials ready:

Technical Requirements:

  • PHP 8.0 or higher
  • Laravel 9.x or 10.x
  • Composer installed globally
  • A Stripe account (free to create)
  • Basic knowledge of Laravel routing and controllers

Stripe Account Setup:

  1. Create your free Stripe account at stripe.com
  2. Verify your email address
  3. Complete your business profile
  4. Obtain your API keys from the dashboard

Understanding API Keys

Stripe provides two types of API keys:

  • Publishable keys (safe for client-side code)
  • Secret keys (must be kept server-side only)

Think of these like a house key and a master key – the publishable key opens the front door, while the secret key gives you access to everything inside.

Installing Stripe in Your Laravel Project

Using Composer for Installation

The easiest way to add Stripe to your Laravel project is through Composer:

Bash
composer require stripe/stripe-php

Laravel Cashier Alternative

For more advanced features, consider Laravel Cashier:

Bash
composer require laravel/cashier

Advanced Laravel Features

For more complex integrations, you might want to explore Laravel’s official documentation on payment processing patterns and best practices. The Laravel Documentation provides excellent guidance on structuring payment-related services and implementing proper error handling strategies.

Laravel Cashier provides a more Laravel-centric approach to Stripe integration, offering:

  • Built-in subscription management
  • Invoice handling
  • Webhook management
  • Customer portal integration

Publishing Configuration Files

If using Cashier, publish the migration files:

Bash
php artisan vendor:publish --tag="cashier-migrations"
php artisan migrate

Configuring Environment Variables

Setting Up Your .env File

Add your Stripe credentials to your .env file:

Plaintext
STRIPE_KEY=pk_test_your_publishable_key_here
STRIPE_SECRET=sk_test_your_secret_key_here
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here

Config File Setup

Create a dedicated config file for Stripe settings:

PHP
// config/stripe.php
return [
    'key' => env('STRIPE_KEY'),
    'secret' => env('STRIPE_SECRET'),
    'webhook_secret' => env('STRIPE_WEBHOOK_SECRET'),
];

Pro Tip: Never commit your actual API keys to version control. Always use environment variables!

Creating Your First Payment Form

Frontend Payment Form

Create a simple payment form using Stripe Elements:

HTML
<form id="payment-form">
    <div id="payment-element">
        <!-- Stripe Elements will create form elements here -->
    </div>
    <button id="submit" type="submit">Pay Now</button>
</form>

JavaScript Integration

Initialize Stripe on the frontend:

JavaScript
const stripe = Stripe('{{ config('stripe.key') }}');
const elements = stripe.elements();
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');

Handling Form Submission

Process the form submission with client-side validation:

JavaScript
document.getElementById('payment-form').addEventListener('submit', async (event) => {
    event.preventDefault();
    
    const {error} = await stripe.confirmPayment({
        elements,
        confirmParams: {
            return_url: '{{ route('payment.success') }}'
        }
    });
    
    if (error) {
        console.error('Payment failed:', error);
    }
});

Processing Payments with Controllers

Creating the Payment Controller

Generate a controller to handle payment processing:

Bash
php artisan make:controller PaymentController

Payment Processing Logic

Implement the core payment processing method:

PHP
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Stripe\Stripe;
use Stripe\PaymentIntent;

class PaymentController extends Controller
{
    public function createPaymentIntent(Request $request)
    {
        Stripe::setApiKey(config('stripe.secret'));
        
        $paymentIntent = PaymentIntent::create([
            'amount' => $request->amount * 100, // Convert to cents
            'currency' => 'usd',
            'metadata' => [
                'user_id' => auth()->id(),
                'order_id' => $request->order_id
            ]
        ]);
        
        return response()->json([
            'client_secret' => $paymentIntent->client_secret
        ]);
    }
}

Route Configuration

Add routes for your payment endpoints:

PHP
Route::post('/create-payment-intent', [PaymentController::class, 'createPaymentIntent'])
    ->middleware('auth');
Route::get('/payment/success', [PaymentController::class, 'success'])
    ->name('payment.success');

Handling Payment Success and Failures

Success Page Implementation

Create a dedicated success page for completed payments:

PHP
public function success(Request $request)
{
    $paymentIntentId = $request->get('payment_intent');
    
    if ($paymentIntentId) {
        // Retrieve payment details from Stripe
        Stripe::setApiKey(config('stripe.secret'));
        $paymentIntent = PaymentIntent::retrieve($paymentIntentId);
        
        // Update your database
        // Send confirmation email
        // Redirect to thank you page
        
        return view('payment.success', compact('paymentIntent'));
    }
    
    return redirect()->route('home')->with('error', 'Payment verification failed');
}

Error Handling Best Practices

Implement comprehensive error handling:

PHP
try {
    $paymentIntent = PaymentIntent::create($paymentData);
} catch (\Stripe\Exception\CardException $e) {
    // Card was declined
    return back()->with('error', 'Your card was declined.');
} catch (\Stripe\Exception\InvalidRequestException $e) {
    // Invalid parameters
    return back()->with('error', 'Invalid payment request.');
} catch (\Exception $e) {
    // General error
    return back()->with('error', 'Something went wrong. Please try again.');
}

Implementing Stripe Webhooks

Why Webhooks Matter

Webhooks are like having a direct phone line between Stripe and your application. Instead of constantly asking “Has anything happened?”, Stripe calls you immediately when events occur.

Setting Up Webhook Endpoints

Create a webhook controller:

PHP
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Stripe\Webhook;
use Stripe\Exception\SignatureVerificationException;

class WebhookController extends Controller
{
    public function handleWebhook(Request $request)
    {
        $payload = $request->getContent();
        $sigHeader = $request->header('Stripe-Signature');
        $endpointSecret = config('stripe.webhook_secret');
        
        try {
            $event = Webhook::constructEvent($payload, $sigHeader, $endpointSecret);
        } catch (SignatureVerificationException $e) {
            return response('Invalid signature', 400);
        }
        
        switch ($event->type) {
            case 'payment_intent.succeeded':
                $this->handlePaymentSucceeded($event->data->object);
                break;
            case 'payment_intent.payment_failed':
                $this->handlePaymentFailed($event->data->object);
                break;
            default:
                \Log::info('Unhandled webhook event: ' . $event->type);
        }
        
        return response('Webhook handled', 200);
    }
    
    private function handlePaymentSucceeded($paymentIntent)
    {
        // Update order status
        // Send confirmation email
        // Update customer records
    }
}

Webhook Route Configuration

Add webhook routes with CSRF exemption:

PHP
// In routes/web.php
Route::post('/stripe/webhook', [WebhookController::class, 'handleWebhook'])
    ->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

Managing Customer Data

Creating Stripe Customers

Link your Laravel users with Stripe customers:

PHP
public function createStripeCustomer(User $user)
{
    Stripe::setApiKey(config('stripe.secret'));
    
    $customer = \Stripe\Customer::create([
        'email' => $user->email,
        'name' => $user->name,
        'metadata' => [
            'user_id' => $user->id
        ]
    ]);
    
    $user->update(['stripe_customer_id' => $customer->id]);
    
    return $customer;
}

Storing Payment Methods

Save customer payment methods for future use:

PHP
public function savePaymentMethod(Request $request)
{
    $user = auth()->user();
    
    if (!$user->stripe_customer_id) {
        $this->createStripeCustomer($user);
    }
    
    $paymentMethod = \Stripe\PaymentMethod::retrieve($request->payment_method_id);
    $paymentMethod->attach(['customer' => $user->stripe_customer_id]);
    
    return response()->json(['status' => 'success']);
}

Setting Up Subscription Billing

Creating Subscription Plans

Define subscription products and prices in your Stripe dashboard or programmatically:

PHP
public function createSubscriptionPlan($productName, $amount, $interval = 'month')
{
    Stripe::setApiKey(config('stripe.secret'));
    
    $product = \Stripe\Product::create([
        'name' => $productName,
    ]);
    
    $price = \Stripe\Price::create([
        'product' => $product->id,
        'unit_amount' => $amount * 100,
        'currency' => 'usd',
        'recurring' => ['interval' => $interval],
    ]);
    
    return $price;
}

Managing Subscriptions

Handle subscription creation and management:

PHP
public function createSubscription(Request $request)
{
    $user = auth()->user();
    
    $subscription = \Stripe\Subscription::create([
        'customer' => $user->stripe_customer_id,
        'items' => [[
            'price' => $request->price_id,
        ]],
        'payment_behavior' => 'default_incomplete',
        'expand' => ['latest_invoice.payment_intent'],
    ]);
    
    return response()->json([
        'subscription_id' => $subscription->id,
        'client_secret' => $subscription->latest_invoice->payment_intent->client_secret
    ]);
}

Security Best Practices

Protecting Sensitive Data

Never store sensitive payment information in your database:

  • Card numbers
  • CVV codes
  • Expiration dates

Instead, use Stripe’s tokenization system and store only:

  • Customer IDs
  • Payment method IDs
  • Transaction references

Implementing Request Validation

Always validate incoming requests:

PHP
public function createPaymentIntent(Request $request)
{
    $validated = $request->validate([
        'amount' => 'required|numeric|min:0.50',
        'currency' => 'required|string|in:usd,eur,gbp',
        'payment_method_id' => 'sometimes|string'
    ]);
    
    // Process payment...
}

Rate Limiting

Protect your payment endpoints with rate limiting:

PHP
Route::middleware(['throttle:payment'])
    ->post('/create-payment-intent', [PaymentController::class, 'createPaymentIntent']);

Testing Your Integration

Using Stripe Test Mode

Stripe provides test card numbers for different scenarios:

Successful payments:

  • 4242424242424242 (Visa)
  • 5555555555554444 (Mastercard)

Failed payments:

  • 4000000000000002 (Card declined)
  • 4000000000009995 (Insufficient funds)

Automated Testing

Create tests for your payment functionality:

PHP
<?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\User;

class PaymentTest extends TestCase
{
    public function test_payment_intent_creation()
    {
        $user = User::factory()->create();
        
        $response = $this->actingAs($user)->post('/create-payment-intent', [
            'amount' => 10.00,
            'currency' => 'usd'
        ]);
        
        $response->assertStatus(200)
                ->assertJsonStructure(['client_secret']);
    }
}

Common Troubleshooting Issues

CORS Configuration Issues

If you’re having CORS problems, add proper headers:

PHP
// In app/Http/Middleware/Cors.php
public function handle($request, Closure $next)
{
    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
        ->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}

SSL Certificate Requirements

Stripe requires HTTPS in production. Ensure your Laravel app uses SSL:

PHP
// In AppServiceProvider
public function boot()
{
    if (app()->environment('production')) {
        \URL::forceScheme('https');
    }
}

Debugging Webhook Issues

Log webhook events for debugging:

PHP
public function handleWebhook(Request $request)
{
    \Log::info('Webhook received', [
        'type' => $event->type ?? 'unknown',
        'id' => $event->id ?? 'unknown',
        'data' => $event->data ?? []
    ]);
    
    // Process webhook...
}

Performance Optimization Tips

Database Indexing

Add indexes to frequently queried payment-related fields:

PHP
// In your migration
$table->index('stripe_customer_id');
$table->index('stripe_subscription_id');
$table->index(['user_id', 'status']);

Caching Strategies

Cache customer data to reduce API calls:

PHP
public function getStripeCustomer(User $user)
{
    return Cache::remember("stripe_customer_{$user->id}", 3600, function () use ($user) {
        return \Stripe\Customer::retrieve($user->stripe_customer_id);
    });
}

Queued Processing

Use Laravel queues for webhook processing:

PHP
public function handleWebhook(Request $request)
{
    ProcessStripeWebhook::dispatch($request->all())->onQueue('webhooks');
    return response('Webhook queued', 200);
}

Going Live with Your Payment System

Pre-Launch Checklist

Before switching to live mode:

✅ Test all payment flows thoroughly
✅ Verify webhook endpoints are working
✅ Confirm SSL certificates are valid
✅ Review error handling and logging
✅ Set up monitoring and alerts
✅ Complete Stripe account verification

Switching to Live Mode

Update your environment variables:

Plaintext
STRIPE_KEY=pk_live_your_live_publishable_key
STRIPE_SECRET=sk_live_your_live_secret_key

Monitoring and Maintenance

Set up monitoring for:

  • Payment success rates
  • Error frequencies
  • Response times
  • Webhook delivery failures

Conclusion

Integrating Stripe with Laravel doesn’t have to be rocket science. With the right approach and understanding of both platforms, you can create a robust, secure payment system that serves your users well.

Remember, the key to successful stripe laravel integration lies in thorough testing, proper error handling, and following security best practices. Start with small, simple implementations and gradually add complexity as your understanding grows.

The combination of Stripe’s powerful payment infrastructure and Laravel’s elegant framework gives you everything you need to build world-class payment experiences. Whether you’re handling one-time payments or complex subscription billing, this integration will scale with your business needs.

Frequently Asked Questions

How long does it typically take to integrate Stripe with Laravel?

A basic integration can be completed in a few hours, while a full-featured implementation with subscriptions and advanced features might take several days. The timeline depends on your requirements and Laravel experience level.

Is it safe to store Stripe API keys in the .env file?

Yes, storing API keys in the .env file is the recommended approach for Laravel applications. Just ensure your .env file is never committed to version control and has proper file permissions (typically 600) on your server.

Can I use Stripe with Laravel for international payments?

Absolutely! Stripe supports payments in 135+ currencies and is available in 40+ countries. You can configure multiple currencies and handle international transactions seamlessly within your Laravel application.

What’s the difference between using raw Stripe PHP SDK versus Laravel Cashier?

The raw Stripe PHP SDK gives you complete control and flexibility, while Laravel Cashier provides a more Laravel-centric approach with built-in subscription management, invoicing, and customer portals. Choose Cashier if you need subscription billing features.

How do I handle failed payments and retry logic in my Laravel Stripe integration?

You can handle failed payments through webhook events, implement automatic retry mechanisms using Laravel queues, and provide customers with options to update payment methods. Set up proper error logging and customer notifications for the best user experience.

Deploy your first application in 10 minutes, Risk Free!

Learn how ServerAvatar simplifies server management with intuitive dashboards and automated processes.
  • No CC Info Required
  • Free 4-Days Trial
  • Deploy in Next 10 Minutes!