Zum Hauptinhalt springen

Überblick

Laravel Cashier (Stripe) ist das offizielle Paket zur Nutzung der Abrechnungsfunktionen von Stripe aus Laravel. Damit können Sie Abonnements anlegen, deren Status prüfen und kündigen, Einmalzahlungen abwickeln, Rechnungen herunterladen und Webhooks verarbeiten – alles über eine einheitliche API.

Installation und Konfiguration

Installieren Sie zunächst Cashier und legen Sie die erforderlichen Tabellen an.
composer require laravel/cashier
php artisan vendor:publish --tag="cashier-migrations"
php artisan migrate
Fügen Sie anschließend das Trait Billable zum Modell hinzu, das Zahlungen empfängt – üblicherweise App\Models\User.
<?php

namespace App\Models;

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

class User extends Authenticatable
{
    use Billable;
}
Hinterlegen Sie die Stripe-Schlüssel in Ihrer .env.
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret

Kundenverwaltung

Wenn möglicherweise noch kein Stripe-Kunde angelegt wurde, verwenden Sie createOrGetStripeCustomer().
$stripeCustomer = $user->createOrGetStripeCustomer();
Für eine explizite Erstellung nutzen Sie createAsStripeCustomer().
$stripeCustomer = $user->createAsStripeCustomer();

Abonnements

Neu anlegen

Ein Abonnement wird mit newSubscription() und create() gestartet. An $paymentMethodId übergeben Sie die Payment-Method-ID, die Sie etwa über Stripe.js ermittelt haben.
$user->newSubscription('default', 'price_monthly')
    ->create($paymentMethodId);
price_monthly dient nur als Beispiel. Bei der Umsetzung verwenden Sie die tatsächliche Price-ID aus Ihrem Stripe-Dashboard.

Status prüfen

Mit subscribed() prüfen Sie, ob ein gültiges Abonnement besteht.
if ($user->subscribed('default')) {
    // Active subscription...
}

Kündigen und fortsetzen

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

if ($user->subscription('default')->onGracePeriod()) {
    // The user is on the grace period...
}

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

Einmalzahlung (Charge)

Mit charge() können Sie einen einmaligen Betrag abbuchen. Der Betrag wird in der kleinsten Währungseinheit angegeben (bei USD entspricht 100 zum Beispiel $1.00). Auch hier ist $paymentMethodId die in Stripe erzeugte Payment-Method-ID.
$payment = $user->charge(100, $paymentMethodId);
Schlägt die Abbuchung fehl, wirft charge() eine Ausnahme.

Payment Element

Mit dem Payment Element von Stripe können Sie mehrere Zahlungsarten wie Kreditkarte, Apple Pay, Google Pay oder iDEAL einheitlich verarbeiten.

Nutzung mit Abonnements

Erzeugen Sie ein Setup Intent und übergeben Sie es an die View.
return view('subscribe', [
    'intent' => $user->createSetupIntent()
]);
In der Blade-View mounten Sie das Payment Element und übergeben das client_secret des Setup Intents.
<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) {
            // Fehlermeldung an den Nutzer anzeigen ...
        }
    });
</script>
An die von Stripe verwendete Redirect-URL wird der Parameter setup_intent angehängt. Damit ermitteln Sie die Payment-Method-ID und erstellen das 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');

Nutzung für Einmalzahlungen

Bei Einmalzahlungen erzeugen Sie mit pay() ein Payment Intent. Das Modell Order benötigt die Spalten user_id, amount, status und 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,
    ]);
});
Mounten Sie das Payment Element und bestätigen Sie die Zahlung.
<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) {
            // Fehlermeldung an den Nutzer anzeigen ...
        }
    });
</script>
Nach dem Redirect suchen Sie die Bestellung anhand des Parameters payment_intent. Stellen Sie sicher, dass das Payment Intent zur authentifizierten Person gehört und den Status succeeded hat, bevor Sie die Bestellung finalisieren.
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']);

        // Bestellung finalisieren ...
    }

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

Rechnungen

Die Rechnungsliste erhalten Sie über invoices().
$invoices = $user->invoices();
Für PDF-Downloads installieren Sie dompdf/dompdf und verwenden downloadInvoice(). In $invoiceId übergeben Sie die Rechnungs-ID aus invoices().
composer require dompdf/dompdf
return $user->downloadInvoice($invoiceId);

Webhooks einrichten

Cashier registriert automatisch eine Route für Stripe-Webhooks; standardmäßig wird /stripe/webhook verwendet. Tragen Sie diese URL im Stripe-Dashboard ein. Einen Webhook erstellen Sie mit cashier:webhook.
php artisan cashier:webhook
Nehmen Sie stripe/* von der CSRF-Prüfung aus.
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(except: [
        'stripe/*',
    ]);
})
Wenn Sie STRIPE_WEBHOOK_SECRET in der .env setzen, kann die Signaturprüfungs-Middleware von Cashier eingehende Webhook-Anfragen verifizieren.
Zuletzt geändert am 13. Juli 2026