Vai al contenuto principale

Panoramica

Laravel Cashier (Stripe) è il pacchetto ufficiale per gestire le funzionalità di fatturazione di Stripe da Laravel. Implementi con un’API unificata creazione/verifica/cancellazione di abbonamenti, pagamenti singoli, download di fatture e gestione dei webhook.

Installazione e configurazione

Installa Cashier e crea le tabelle necessarie.
composer require laravel/cashier
php artisan vendor:publish --tag="cashier-migrations"
php artisan migrate
Aggiungi il trait Billable al modello fatturabile (es. App\Models\User).
<?php

namespace App\Models;

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

class User extends Authenticatable
{
    use Billable;
}
Imposta le chiavi Stripe in .env.
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret

Gestione dei customer

Se il Customer Stripe potrebbe non esistere, usa createOrGetStripeCustomer().
$stripeCustomer = $user->createOrGetStripeCustomer();
Per crearlo esplicitamente usa createAsStripeCustomer().
$stripeCustomer = $user->createAsStripeCustomer();

Subscription

Creazione

Con newSubscription() e create(). Passa a $paymentMethodId il Payment Method ID ottenuto con Stripe.js.
$user->newSubscription('default', 'price_monthly')
    ->create($paymentMethodId);
price_monthly è un esempio: usa il vero Price ID definito nella dashboard Stripe.

Verifica dello stato

if ($user->subscribed('default')) {
    // Abbonamento attivo...
}

Cancellazione e ripresa

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

if ($user->subscription('default')->onGracePeriod()) {
    // L'utente è nel grace period...
}

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

Pagamenti singoli (Charge)

Con charge() esegui un singolo addebito. L’importo è nell’unità minima della valuta (per EUR 100 = 1,00 €). Anche qui usi $paymentMethodId.
$payment = $user->charge(100, $paymentMethodId);
Se l’addebito fallisce, charge() lancia un’eccezione.

Payment Element

Con il Payment Element di Stripe puoi gestire più metodi (carta, Apple Pay, Google Pay, iDEAL) in modo uniforme.

Con Subscription

Crea un Setup Intent e passalo alla vista.
return view('subscribe', [
    'intent' => $user->createSetupIntent()
]);
Nella vista Blade monta il Payment Element passandogli il 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) {
            // Mostra l'errore all'utente...
        }
    });
</script>
Nel return_url viene appeso il parametro setup_intent. Usalo per ottenere il Payment Method ID e creare l’abbonamento.
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');

Con pagamento singolo

Per il pagamento singolo usa pay() per creare un Payment Intent. Il modello Order richiede colonne 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,
    ]);
});
Monta il Payment Element per confermare.
<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) {
            // Mostra l'errore all'utente...
        }
    });
</script>
Dopo il redirect, con payment_intent recuperi l’Order e verifichi che il Payment Intent sia dell’utente autenticato ed in stato succeeded, poi conferma l’ordine.
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']);

        // Conferma ordine...
    }

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

Fatture

Ottieni la lista delle fatture con invoices().
$invoices = $user->invoices();
Per scaricare il PDF installa dompdf/dompdf e usa downloadInvoice(). Passa a $invoiceId l’ID recuperato da invoices().
composer require dompdf/dompdf
return $user->downloadInvoice($invoiceId);

Configurazione dei webhook

Cashier registra automaticamente la route dei webhook Stripe e usa di default /stripe/webhook. Imposta questo URL nella dashboard Stripe. Puoi creare l’endpoint con cashier:webhook.
php artisan cashier:webhook
Escludi stripe/* dalla protezione CSRF.
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(except: [
        'stripe/*',
    ]);
})
Impostando STRIPE_WEBHOOK_SECRET in .env, il middleware di Cashier verifica la firma delle richieste webhook.
Ultima modifica il 13 luglio 2026