Laravel Cashier : gérer les abonnements et paiements avec Stripe

L
Laravel Actu
2 min

Gérer les paiements récurrents et les abonnements représente un défi technique majeur. Laravel Cashier élimine cette complexité en proposant une interface fluide et expressive pour Stripe. Le package officiel gère tout : abonnements, périodes d’essai, coupons, factures PDF et webhooks.

Qu’est-ce que Laravel Cashier ?

Laravel Cashier Stripe est le package officiel de Laravel pour intégrer les services de facturation par abonnement de Stripe. Plutôt que d’écrire des centaines de lignes de code pour gérer les paiements récurrents, Cashier fournit une API élégante qui s’intègre naturellement avec Eloquent.

Le package prend en charge :

  • La gestion complète des abonnements (création, modification, annulation)
  • Les périodes d’essai avec ou sans carte bancaire
  • Les coupons et codes promotionnels
  • La génération automatique de factures PDF
  • La facturation à l’usage (metered billing)
  • Les webhooks Stripe avec vérification de signature
  • Le portail client Stripe Checkout

Installation et configuration

L’installation se fait en quelques commandes Composer et Artisan :

# Installation du package
composer require laravel/cashier

# Publication des migrations
php artisan vendor:publish --tag="cashier-migrations"

# Exécution des migrations
php artisan migrate

Cashier ajoute plusieurs colonnes à la table users et crée les tables subscriptions et subscription_items.

Configurez ensuite vos clés API Stripe dans le fichier .env :

STRIPE_KEY=pk_test_votre_cle_publique
STRIPE_SECRET=sk_test_votre_cle_secrete
STRIPE_WEBHOOK_SECRET=whsec_votre_secret_webhook

Ajoutez le trait Billable à votre modèle User :

<?php

namespace App\Models;

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

class User extends Authenticatable
{
    // Trait qui ajoute toutes les méthodes de facturation
    use Billable;
}

Ce trait injecte automatiquement les méthodes subscribe(), subscribed(), charge(), invoices() et des dizaines d’autres sur votre modèle.

Créer un abonnement

La création d’un abonnement s’effectue via la méthode newSubscription(). Vous devez au préalable créer vos produits et prix dans le dashboard Stripe.

<?php

use Illuminate\Http\Request;

Route::post('/subscribe', function (Request $request) {
    // Création de l'abonnement avec le moyen de paiement fourni
    $request->user()->newSubscription('default', 'price_basic_monthly')
        ->create($request->paymentMethodId);

    return redirect('/dashboard')->with('success', 'Abonnement activé !');
});

Le premier argument 'default' représente le type d’abonnement (utile si un utilisateur peut avoir plusieurs abonnements). Le second correspond à l’identifiant du prix Stripe.

Pour ajouter une période d’essai :

<?php

// Abonnement avec 14 jours d'essai gratuit
$user->newSubscription('default', 'price_pro_monthly')
    ->trialDays(14)
    ->create($paymentMethodId);

Utiliser Stripe Checkout

Stripe Checkout offre une page de paiement hébergée, sécurisée et optimisée pour la conversion. Cashier s’intègre parfaitement avec cette solution :

<?php

use Illuminate\Http\Request;

Route::get('/checkout', function (Request $request) {
    // Redirection vers la page Stripe Checkout
    return $request->user()
        ->newSubscription('default', 'price_premium_yearly')
        ->trialDays(7)
        ->allowPromotionCodes() // Autorise les codes promo
        ->checkout([
            'success_url' => route('subscription.success'),
            'cancel_url' => route('subscription.cancel'),
        ]);
});

L’utilisateur est redirigé vers Stripe, effectue son paiement, puis revient sur votre application. Les webhooks Stripe synchronisent automatiquement l’état de l’abonnement.

Vérifier le statut d’un abonnement

Cashier propose plusieurs méthodes pour vérifier l’état des abonnements :

<?php

// Vérifie si l'utilisateur a un abonnement actif
if ($user->subscribed('default')) {
    // Accès aux fonctionnalités premium
}

// Vérifie l'abonnement à un produit spécifique
if ($user->subscribedToProduct('prod_premium')) {
    // L'utilisateur a le produit Premium
}

// Vérifie si l'utilisateur est en période d'essai
if ($user->subscription('default')->onTrial()) {
    // Afficher un message sur les jours restants
}

// Vérifie si l'abonnement est annulé mais encore actif (période de grâce)
if ($user->subscription('default')->onGracePeriod()) {
    // L'utilisateur peut encore utiliser le service
}

Ces méthodes permettent de créer facilement un middleware pour protéger les routes premium :

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserIsSubscribed
{
    public function handle(Request $request, Closure $next): Response
    {
        // Redirige les non-abonnés vers la page de tarification
        if (! $request->user()?->subscribed('default')) {
            return redirect('/pricing');
        }

        return $next($request);
    }
}

Gérer les paiements uniques

Cashier gère également les paiements ponctuels sans abonnement :

<?php

use Illuminate\Http\Request;

Route::post('/purchase', function (Request $request) {
    // Paiement unique de 50€ (montant en centimes)
    $payment = $request->user()->charge(
        5000,
        $request->paymentMethodId
    );

    return response()->json(['success' => true]);
});

// Paiement avec génération automatique d'une facture
Route::post('/invoice-purchase', function (Request $request) {
    // Facture pour 3 articles à un prix défini dans Stripe
    $request->user()->invoicePrice('price_tshirt', 3);

    return redirect('/orders');
});

Portail de facturation client

Stripe propose un portail client hébergé où les utilisateurs peuvent gérer leurs abonnements, moyens de paiement et télécharger leurs factures. Cashier l’intègre en une ligne :

<?php

use Illuminate\Http\Request;

Route::get('/billing', function (Request $request) {
    // Redirige vers le portail Stripe Customer Portal
    return $request->user()->redirectToBillingPortal(
        route('dashboard') // URL de retour après gestion
    );
})->middleware('auth')->name('billing');

Vos utilisateurs peuvent ainsi modifier leur abonnement, changer de formule ou annuler leur souscription sans que vous n’ayez à développer d’interface.

Configurer les webhooks

Les webhooks sont essentiels pour synchroniser votre base de données avec Stripe. Cashier enregistre automatiquement une route /stripe/webhook.

Créez le webhook dans Stripe via Artisan :

php artisan cashier:webhook

N’oubliez pas d’exclure cette route de la protection CSRF dans bootstrap/app.php :

<?php

->withMiddleware(function (Middleware $middleware): void {
    $middleware->validateCsrfTokens(except: [
        'stripe/*', // Exclut les webhooks Stripe de la vérification CSRF
    ]);
})

Pour réagir à des événements Stripe personnalisés, écoutez les événements Cashier :

<?php

namespace App\Listeners;

use Laravel\Cashier\Events\WebhookReceived;

class HandleStripeWebhook
{
    public function handle(WebhookReceived $event): void
    {
        // Traitement personnalisé selon le type d'événement
        if ($event->payload['type'] === 'invoice.payment_succeeded') {
            $customerId = $event->payload['data']['object']['customer'];
            // Envoyer un email de remerciement, mettre à jour des statistiques...
        }
    }
}

Points d’attention

  • Collation MySQL : utilisez utf8_bin pour la colonne stripe_id afin de respecter la casse des identifiants Stripe
  • Webhooks obligatoires : configurez au minimum customer.subscription.created, customer.subscription.updated et invoice.payment_succeeded
  • Montants en centimes : la méthode charge() attend les montants en centimes (100 = 1€)
  • Tests : utilisez les clés de test Stripe et les numéros de carte de test (4242424242424242)
  • Mise à jour : consultez toujours le guide de migration avant de mettre à jour Cashier

Stripe vs Paddle : quel choix ?

Laravel propose deux packages Cashier : un pour Stripe et un pour Paddle. Stripe offre plus de contrôle et de fonctionnalités, mais vous devez gérer la TVA vous-même (sauf avec Stripe Tax). Paddle gère automatiquement la TVA mondiale, ce qui simplifie la conformité fiscale pour les entreprises vendant en Europe mais la tarification sur les transactions est quasiment double par rapport à Paddle.

Récapitulatif

Laravel Cashier transforme l’intégration des paiements Stripe & Paddle en une expérience fluide. Le package gère la complexité des abonnements récurrents, des webhooks et de la synchronisation des données. Quelques lignes de code suffisent pour proposer des formules d’abonnement professionnelles avec périodes d’essai, coupons et facturation automatique.

Ressources

À propos de Laravel Actu

Développeur passionné par Laravel et son écosystème.

Voir tous les articles
Partager :

Ne manquez aucune actualité Laravel

Recevez les meilleurs articles et tutoriels directement dans votre boîte mail.

Pas de spam. Désinscription possible à tout moment.