> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Cashier (Stripe)

> Erläutert die grundlegenden Abläufe zur Umsetzung von Abonnement-Abrechnungen, Einmalzahlungen, Rechnungen und Webhooks mit Laravel Cashier (Stripe).

## Ü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.

```shell theme={null}
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 theme={null}
<?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`.

```ini theme={null}
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()`.

```php theme={null}
$stripeCustomer = $user->createOrGetStripeCustomer();
```

Für eine explizite Erstellung nutzen Sie `createAsStripeCustomer()`.

```php theme={null}
$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.

```php theme={null}
$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.

```php theme={null}
if ($user->subscribed('default')) {
    // Active subscription...
}
```

### Kündigen und fortsetzen

```php theme={null}
$user->subscription('default')->cancel();

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

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

```mermaid theme={null}
stateDiagram-v2
    [*] --> Active
    Active --> GracePeriod: cancel()
    GracePeriod --> Active: resume()
    GracePeriod --> Canceled: grace period ends
    Active --> Canceled: cancelNow()
```

## 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.

```php theme={null}
$payment = $user->charge(100, $paymentMethodId);
```

Schlägt die Abbuchung fehl, wirft `charge()` eine Ausnahme.

## Payment Element

Mit dem [Payment Element](https://stripe.com/docs/payments/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.

```php theme={null}
return view('subscribe', [
    'intent' => $user->createSetupIntent()
]);
```

In der Blade-View mounten Sie das Payment Element und übergeben das `client_secret` des Setup Intents.

```html theme={null}
<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.

```php theme={null}
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`.

```php theme={null}
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.

```html theme={null}
<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.

```php theme={null}
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');
```

```mermaid theme={null}
sequenceDiagram
    participant User as Nutzer
    participant App as Laravel-<br>App
    participant Stripe

    User->>App: POST /pay
    App->>Stripe: PaymentIntent mit pay() erzeugen
    Stripe-->>App: client_secret
    App-->>User: checkout-View anzeigen
    User->>Stripe: confirmPayment()
    Stripe-->>User: Redirect an return_url
    User->>App: GET /payment/complete
    App->>Stripe: PaymentIntent abrufen und prüfen
    App->>App: order.status = paid
    App-->>User: Redirect ins Dashboard
```

## Rechnungen

Die Rechnungsliste erhalten Sie über `invoices()`.

```php theme={null}
$invoices = $user->invoices();
```

Für PDF-Downloads installieren Sie `dompdf/dompdf` und verwenden `downloadInvoice()`. In `$invoiceId` übergeben Sie die Rechnungs-ID aus `invoices()`.

```shell theme={null}
composer require dompdf/dompdf
```

```php theme={null}
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`.

```shell theme={null}
php artisan cashier:webhook
```

Nehmen Sie `stripe/*` von der CSRF-Prüfung aus.

```php theme={null}
->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.


## Related topics

- [Upgrade von Laravel 10 auf 11](/de/blog/upgrade-10-to-11.md)
- [Laravel-Updates Juni 2026](/de/blog/changelog/202606.md)
- [CSRF-Schutz](/de/csrf.md)
- [Anwendungsstruktur ab Laravel 11](/de/advanced/app-structure.md)
- [Service-Container](/de/service-container.md)
