laravel-cashier

Auto-invoked skill

Subscription billing with Stripe or Paddle

Trigger Keywords

This skill automatically activates when Claude detects these keywords:

cashier stripe subscription billing payment paddle

Overview

The laravel-cashier skill provides expertise for implementing subscription billing in Laravel using Cashier with Stripe or Paddle, including subscriptions, trials, invoices, and webhooks.

What This Skill Provides

  • Subscription Management - Create, update, cancel subscriptions
  • Payment Methods - Add, update, remove payment methods
  • Invoicing - Generate and email invoices
  • Webhooks - Handle Stripe/Paddle webhooks
  • Checkout - Stripe Checkout integration
  • Metered Billing - Usage-based pricing

Quick Start

# Install Cashier for Stripe
composer require laravel/cashier

# Publish migrations
php artisan vendor:publish --tag="cashier-migrations"
php artisan migrate

# Add to .env
STRIPE_KEY=pk_test_xxx
STRIPE_SECRET=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx

Model Setup

<?php

namespace App\Models;

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

final class User extends Authenticatable
{
    use Billable;
}

Creating Subscriptions

// Create subscription
$user->newSubscription('default', 'price_monthly')
    ->create($paymentMethod);

// With trial
$user->newSubscription('default', 'price_monthly')
    ->trialDays(14)
    ->create($paymentMethod);

// With coupon
$user->newSubscription('default', 'price_monthly')
    ->withCoupon('SAVE20')
    ->create($paymentMethod);

// Multiple plans
$user->newSubscription('default', ['price_monthly', 'price_addon'])
    ->create($paymentMethod);

Managing Subscriptions

// Check subscription status
if ($user->subscribed('default')) {
    // User has active subscription
}

if ($user->subscription('default')?->onTrial()) {
    // User is on trial
}

if ($user->subscription('default')?->canceled()) {
    // Subscription was canceled
}

// Swap plans
$user->subscription('default')->swap('price_yearly');

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

// Cancel immediately
$user->subscription('default')->cancelNow();

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

Checkout Integration

// Controller
public function checkout(Request $request)
{
    return $request->user()
        ->newSubscription('default', 'price_monthly')
        ->checkout([
            'success_url' => route('dashboard'),
            'cancel_url' => route('pricing'),
        ]);
}

// Blade
<form action="" method="POST">
    @csrf
    <button type="submit">Subscribe</button>
</form>

Webhooks

// routes/web.php
Route::post('/stripe/webhook', [WebhookController::class, 'handleWebhook']);

// Custom webhook handler
namespace App\Http\Controllers;

use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;

class WebhookController extends CashierController
{
    protected function handleCustomerSubscriptionCreated(array $payload)
    {
        // Handle new subscription
        parent::handleCustomerSubscriptionCreated($payload);
    }

    protected function handleInvoicePaymentFailed(array $payload)
    {
        // Notify user of failed payment
    }
}

Common Pitfalls

  • Missing webhook endpoint - Configure in Stripe Dashboard
  • Not validating webhook signatures - Set STRIPE_WEBHOOK_SECRET
  • Forgetting CSRF exception - Exclude webhook route from CSRF
  • Not handling failed payments - Implement retry logic
  • Testing with live keys - Always use test keys in development

Best Practices

  • Use Stripe Checkout for PCI compliance
  • Handle all relevant webhook events
  • Implement grace periods for failed payments
  • Test with Stripe CLI locally
  • Use price IDs, not hardcoded amounts
  • Queue webhook processing for reliability

Related Skills