Passer au contenu principal

Vue d’ensemble

Laravel Cashier (Stripe) est le package officiel qui interface Stripe avec Laravel. Il fournit une API unifiée pour créer des Subscriptions, vérifier leur état, les annuler, effectuer des paiements uniques, télécharger des factures et traiter les webhooks.

Installation et configuration

Installez Cashier et créez les tables nécessaires.
composer require laravel/cashier
php artisan vendor:publish --tag="cashier-migrations"
php artisan migrate
Ajoutez le trait Billable au modèle facturable (par ex. App\Models\User).
<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;
}
Configurez les clés Stripe dans .env.
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret

Gestion des clients

Si un Customer Stripe peut ne pas exister encore : createOrGetStripeCustomer().
$stripeCustomer = $user->createOrGetStripeCustomer();
Pour créer explicitement : createAsStripeCustomer().
$stripeCustomer = $user->createAsStripeCustomer();

Subscriptions

Création

newSubscription() + create(). $paymentMethodId : ID de méthode de paiement obtenu via Stripe.js, etc.
$user->newSubscription('default', 'price_monthly')
    ->create($paymentMethodId);
price_monthly est un exemple : utilisez le vrai Price ID créé dans Stripe.

État

subscribed() indique si un abonnement est actif.
if ($user->subscribed('default')) {
    // Abonnement actif...
}

Annulation et reprise

$user->subscription('default')->cancel();

if ($user->subscription('default')->onGracePeriod()) {
    // Période de grâce...
}

$user->subscription('default')->resume();

Paiement unique (Charge)

charge() facture une fois. Le montant est en plus petite unité (ex : 100 = 1,00 USD). Utilisez à nouveau $paymentMethodId.
$payment = $user->charge(100, $paymentMethodId);
En cas d’échec, charge() lance une exception.

Payment Element

Le Payment Element Stripe unifie carte, Apple Pay, Google Pay, iDEAL, etc.

Pour un abonnement

Créez un Setup Intent et passez-le à la vue.
return view('subscribe', [
    'intent' => $user->createSetupIntent()
]);
Montez le Payment Element avec le client_secret.
<div id="payment-element"></div>
<button id="submit">Subscribe</button>

<script src="https://js.stripe.com/v3/"></script>
<script>
    const stripe = Stripe('stripe-public-key');

    const elements = stripe.elements({
        clientSecret: '{{ $intent->client_secret }}'
    });

    const paymentElement = elements.create('payment');

    paymentElement.mount('#payment-element');

    document.getElementById('submit').addEventListener('click', async () => {
        const { error } = await stripe.confirmSetup({
            elements,
            confirmParams: {
                return_url: '{{ route("subscription.complete") }}',
            },
        });

        if (error) {
            // Afficher l'erreur à l'utilisateur...
        }
    });
</script>
L’URL de redirection Stripe reçoit setup_intent. Récupérez la méthode de paiement et créez l’abonnement.
use Illuminate\Http\Request;

Route::get('/subscription/complete', function (Request $request) {
    $setupIntent = $request->user()->findSetupIntent(
        $request->setup_intent
    );

    $paymentMethod = $setupIntent->payment_method;

    $request->user()
        ->newSubscription('default', 'price_xxx')
        ->create($paymentMethod);

    return redirect('/dashboard');
})->name('subscription.complete');

Pour un paiement unique

Utilisez pay() pour créer un Payment Intent. Votre modèle Order doit avoir user_id, amount, status, stripe_payment_intent_id.
use App\Models\Order;
use Illuminate\Http\Request;

Route::post('/pay', function (Request $request) {
    $amount = 1000;

    $payment = $request->user()->pay($amount);

    $order = Order::create([
        'user_id' => $request->user()->id,
        'amount' => $amount,
        'status' => 'pending',
        'stripe_payment_intent_id' => $payment->id,
    ]);

    return view('checkout', [
        'clientSecret' => $payment->client_secret,
        'order' => $order,
    ]);
});
Montez le Payment Element et confirmez.
<div id="payment-element"></div>
<button id="submit">Pay Now</button>

<script src="https://js.stripe.com/v3/"></script>
<script>
    const stripe = Stripe('stripe-public-key');

    const elements = stripe.elements({
        clientSecret: '{{ $clientSecret }}'
    });

    const paymentElement = elements.create('payment');

    paymentElement.mount('#payment-element');

    document.getElementById('submit').addEventListener('click', async () => {
        const { error } = await stripe.confirmPayment({
            elements,
            confirmParams: {
                return_url: '{{ route("payment.complete") }}',
            },
        });

        if (error) {
            // Afficher l'erreur à l'utilisateur...
        }
    });
</script>
Après redirection, retrouvez la commande via payment_intent, vérifiez qu’elle appartient à l’utilisateur et est en statut succeeded.
use App\Models\Order;
use Illuminate\Http\Request;

Route::get('/payment/complete', function (Request $request) {
    $order = Order::where('user_id', $request->user()->id)
        ->where('stripe_payment_intent_id', $request->payment_intent)
        ->firstOrFail();

    $paymentIntent = $request->user()
        ->stripe()
        ->paymentIntents
        ->retrieve($request->payment_intent);

    if ($paymentIntent->customer === $request->user()->stripe_id &&
        $paymentIntent->status === 'succeeded') {
        $order->update(['status' => 'paid']);

        // Finaliser la commande...
    }

    return redirect('/dashboard');
})->name('payment.complete');

Factures

Liste des factures : invoices().
$invoices = $user->invoices();
Pour le téléchargement PDF, installez dompdf/dompdf puis utilisez downloadInvoice().
composer require dompdf/dompdf
return $user->downloadInvoice($invoiceId);

Configuration des webhooks

Cashier enregistre une route webhook sur /stripe/webhook par défaut. Configurez cette URL dans Stripe. Créer le webhook :
php artisan cashier:webhook
Excluez stripe/* de la protection CSRF.
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(except: [
        'stripe/*',
    ]);
})
Définissez STRIPE_WEBHOOK_SECRET dans .env pour que le middleware de vérification de signature Cashier valide les requêtes.
Dernière modification le 13 juillet 2026