Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cashier Laravel Package

laravel/cashier

Laravel Cashier offers a fluent Laravel interface for Stripe subscription billing. Manage subscriptions, coupons, plan swaps, quantities, and cancellation grace periods, with support for generating invoice PDFs—all while handling the boilerplate billing code.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require laravel/cashier

Publish the migration and config:

php artisan vendor:publish --provider="Laravel\Cashier\CashierServiceProvider"
php artisan migrate
  1. Configure Stripe: Add your Stripe secret key to .env:

    STRIPE_KEY=your_stripe_secret_key
    
  2. User Model Setup: Use the HasApiTokens and HasBillingInfo traits in your User model:

    use Laravel\Cashier\HasBillingInfo;
    use Laravel\Sanctum\HasApiTokens;
    
    class User extends Authenticatable
    {
        use HasApiTokens, HasBillingInfo;
    }
    
  3. First Use Case: Create a subscription for a user:

    $user = User::find(1);
    $user->newSubscription('monthly', 'price_123')->create($paymentMethodId);
    

Key Documentation Links


Implementation Patterns

Core Workflows

1. Subscription Management

  • Create a Subscription:
    $user->newSubscription('premium', 'price_123')
         ->withQuantity(2)
         ->create($paymentMethodId);
    
  • Swap Plans:
    $user->subscription('premium')->swap('price_456');
    
  • Cancel Subscription:
    $user->subscription('premium')->cancel();
    // With grace period
    $user->subscription('premium')->cancelNow();
    

2. Payment Handling

  • Charge a Customer:
    $user->charge(1000); // $10.00
    
  • Update Payment Method:
    $user->updateDefaultPaymentMethod($newPaymentMethodId);
    

3. Checkout Sessions

  • Create a Checkout Session:
    $session = $user->createCheckoutSession([
        'success_url' => route('checkout.success'),
        'cancel_url' => route('checkout.cancel'),
        'line_items' => [
            [
                'price' => 'price_123',
                'quantity' => 1,
            ],
        ],
    ]);
    
  • Handle Webhooks:
    use Laravel\Cashier\Http\Controllers\WebhookController;
    
    Route::post('/stripe/webhook', [WebhookController::class, 'handleWebhook']);
    

4. Invoices and PDFs

  • Generate Invoice PDF:
    $invoice = $user->invoices()->latest()->first();
    $pdf = $invoice->download();
    
  • List Invoices:
    $user->invoices()->get();
    

5. Coupons and Trials

  • Apply a Coupon:
    $user->newSubscription('premium', 'price_123')
         ->withCoupon('SUMMER20')
         ->create($paymentMethodId);
    
  • Set Trial Period:
    $user->newSubscription('premium', 'price_123')
         ->trialDays(7)
         ->create($paymentMethodId);
    

Integration Tips

Model Observers

Use observers to log subscription events:

class UserObserver
{
    public function created(User $user)
    {
        if ($user->subscribed('premium')) {
            // Send welcome email
        }
    }
}

Middleware for Subscription Checks

Protect routes based on subscription status:

public function handle(Request $request, Closure $next)
{
    if (!$request->user()->subscribed('premium')) {
        abort(403);
    }
    return $next($request);
}

Testing Subscriptions

Use Cashier facade for testing:

$stripe = new \Laravel\Cashier\Stripe\StripeService();
$stripe->stub()->subscription()->create();

Customizing Webhooks

Extend the WebhookController for custom logic:

class CustomWebhookController extends WebhookController
{
    public function handleWebhook(Request $request)
    {
        if ($request->type === 'invoice.paid') {
            // Custom logic
        }
        parent::handleWebhook($request);
    }
}

Gotchas and Tips

Common Pitfalls

1. Webhook Signatures

  • Issue: Webhook verification fails due to incorrect STRIPE_WEBHOOK_SECRET.
  • Fix: Ensure the secret matches your Stripe dashboard settings and is set in .env:
    STRIPE_WEBHOOK_SECRET=whsec_...
    

2. Subscription State Mismatches

  • Issue: subscribed() returns false even though Stripe shows an active subscription.
  • Fix: Sync the subscription state manually:
    $user->subscription('premium')->refresh();
    
    Or use sync() to force a refresh:
    $user->sync();
    

3. Payment Method Failures

  • Issue: charge() or create() fails silently.
  • Fix: Check for exceptions and log Stripe errors:
    try {
        $user->charge(1000);
    } catch (\Exception $e) {
        \Log::error('Stripe charge failed: ' . $e->getMessage());
    }
    

4. Quantity Updates

  • Issue: Updating subscription quantities fails for single-price subscriptions.
  • Fix: Use updateQuantity() with caution:
    $user->subscription('premium')->updateQuantity(3);
    
    Ensure the plan supports quantity adjustments in Stripe.

5. Invoice Generation

  • Issue: download() fails with "Invoice not found."
  • Fix: Verify the invoice exists and is finalized:
    $invoice = $user->invoices()->where('status', 'paid')->latest()->first();
    if ($invoice) {
        $pdf = $invoice->download();
    }
    

Debugging Tips

Logging Stripe Events

Enable Stripe logging in config/cashier.php:

'logging' => [
    'enabled' => true,
    'log_level' => 'debug',
],

Inspecting Stripe Objects

Use dd() to inspect Stripe objects:

dd($user->subscription('premium')->asStripeSubscription());

Testing Webhooks Locally

Use stripe-cli to test webhooks:

stripe listen --forward-to localhost:8000/stripe/webhook

Configuration Quirks

Customizing Invoice Settings

Override default invoice settings in config/cashier.php:

'invoice_settings' => [
    'custom_fields' => [
        [
            'name' => 'Order ID',
            'value' => 'ORD123',
        ],
    ],
],

Handling Taxes

Ensure tax settings are configured in Stripe and Cashier:

$user->newSubscription('premium', 'price_123')
     ->withTaxRate('txr_123')
     ->create($paymentMethodId);

Flexible Billing

For usage-based billing, configure billing_cycle_anchor:

$user->newSubscription('flexible', 'price_123')
     ->withBillingCycleAnchor(now())
     ->create($paymentMethodId);

Extension Points

Customizing Subscription Creation

Extend the create() method for custom logic:

$subscription = $user->newSubscription('premium', 'price_123');
$subscription->create($paymentMethodId, [
    'metadata' => ['custom_key' => 'custom_value'],
]);

Adding Custom Fields to Invoices

Use invoiceCustomFields in config/cashier.php:

'invoice_custom_fields' => [
    'Order ID' => 'order_id',
],

Overriding Webhook Handling

Extend the WebhookController for custom logic:

class CustomWebhookController extends WebhookController
{
    public function handleCustomerSubscriptionCreated(Request $request)
    {
        // Custom logic
        parent::handleCustomerSubscriptionCreated($request);
    }
}

Using Stripe Sources

For custom payment methods (e.g., SEPA, iDEAL):

$source = $user->createAsStripeCustomer([
    'source' => $sourceToken,
]);

Performance Considerations

Avoid Frequent Syncs

  • Syncing subscriptions too often can slow down your application. Use refresh() sparingly.

Batch Invoice Processing

  • Process invoices in batches to avoid timeouts:
    $user->invoices()->chunk(1
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport