Back to all articles
Laravel Insights Oct 30, 2025 โˆ™ 1 min read

Mastering Laravel Cashier: Subscription Billing Guide

Mastering Laravel Cashier: Simplifying Subscription Billing with Stripe and Beyond

A secure payment terminal symbolizing Laravel Cashier's ability to simplify subscription billing with Stripe and other gateways.

Mastering Laravel Cashier: Simplifying Subscription Billing with Stripe and Beyond

A deep dive into Laravel Cashier's features, Stripe integration, and other payment gateways.

Implementing subscription billing can be a complex undertaking for any development team. You need to manage pricing plans, handle recurring payments, generate invoices, and process webhooks for events like failed charges or cancellations. Building this functionality from scratch is a resource-intensive process that can divert focus from your core product and slow down your project delivery timeline.

This is where Laravel Cashier provides an innovative solution. As an official Laravel package, Cashier offers an expressive, fluent interface to manage subscription billing services. It elegantly handles the boilerplate code required for billing, allowing your team to leverage their existing Laravel expertise to build sophisticated subscription logic quickly. While Cashier is most famous for its seamless integration with Stripe, its architecture also opens the door to working with other payment providers.

This comprehensive guide will explore Laravel Cashier's core capabilities, walk through practical examples of its integration with Stripe, and discuss how to approach other payment gateways. By mastering Cashier, you can optimize your development process and build reliable, scalable billing systems for your SaaS or subscription-based applications.

Why Your Business Needs a Tool Like Laravel Cashier

For companies employing Laravel developers, efficiency and code quality are paramount. Manually integrating with a payment provider's API for subscription billing introduces several challenges:

  • Increased Development Time: Your team will spend weeks writing and debugging code to handle customer creation, plan synchronization, payment processing, and invoice management.
  • Maintenance Overhead: Payment provider APIs evolve. Maintaining a custom integration requires constant updates to stay compliant and secure.
  • Complexity and Risk: Billing logic is critical. Errors can lead to lost revenue, incorrect charges, and a poor customer experience.

Laravel Cashier is a proven solution that abstracts away this complexity. It provides a simple, well-documented set of methods to manage the entire subscription lifecycle, allowing your team to focus on building features that generate revenue, not on reinventing the billing wheel.

Getting Started: Setting Up Cashier with Stripe

Cashier's tight integration with Stripe makes it the most common and straightforward implementation. Let's walk through the setup process.

1. Installation and Configuration

First, install the Cashier package via Composer:

composer require laravel/cashier

Next, run the installation command. This will publish the migration files, create the configuration file, and add necessary environment variables.

php artisan cashier:install

After running the command, your .env file will have placeholders for your Stripe keys. You'll need to add your secret keys from the Stripe dashboard.

STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret

Finally, run the migrations to add the necessary subscription-related columns to your users table and create new tables for subscriptions and subscription items.

php artisan migrate

2. Preparing Your User Model

To enable Cashier's functionality, you must add the Billable trait to your User model.

use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;
    // ...
}

This single trait equips your User model with dozens of powerful billing methods, such as createAsStripeCustomer, newSubscription, and invoice.

Managing the Subscription Lifecycle

With the setup complete, you can now manage the entire customer journey with Cashier's expressive syntax.

Creating a New Subscription

The most common task is subscribing a user to a plan. Cashier makes this incredibly simple. Assuming you have a form where a user submits a payment method token (generated by Stripe.js), you can create a new subscription with just one method chain.

use App\Models\User;
use Illuminate\Http\Request;

public function store(Request $request)
{
    $user = User::find(1);
    $paymentMethod = $request->payment_method;
    $planId = 'price_xxxxxxxxxxxxxx'; // The price ID from your Stripe dashboard

    // Create the customer on Stripe if they don't exist
    $user->createOrGetStripeCustomer();

    // Attach the payment method to the customer
    $user->updateDefaultPaymentMethod($paymentMethod);

    // Create the subscription
    $user->newSubscription('default', $planId)
         ->create($paymentMethod, [
             'email' => $user->email,
         ]);

    return redirect('dashboard')->with('status', 'Subscription successful!');
}

In this single, fluent chain, Cashier handles creating the customer in Stripe, attaching their payment method, and initiating the recurring subscription. This is a proven way to enhance code quality by replacing dozens of lines of manual API calls with a clean, readable method.

Checking Subscription Status

Once a user is subscribed, you'll need to check their status to control access to features. The Billable trait provides several convenient helper methods.

// Check if the user has an active subscription of any kind
if ($user->subscribed('default')) {
    // User is on an active plan
}

// Check if the user is on a specific plan
if ($user->subscribedToPrice('price_xxxxxxxxxxxxxx', 'default')) {
    // User is on the specific "Pro" plan
}

// Check for cancelled but still active subscriptions (on grace period)
if ($user->subscription('default')->onGracePeriod()) {
    // User has cancelled but can still access features until the billing period ends
}

Handling Invoices

Cashier simplifies invoice management. You can easily retrieve a collection of a user's invoices and allow them to download PDF copies.

// In a controller
public function listInvoices(Request $request)
{
    $user = $request->user();
    $invoices = $user->invoices();

    return view('invoices.index', ['invoices' => $invoices]);
}

// In your Blade view
@foreach ($invoices as $invoice)
    <tr>
        <td>{{ $invoice->date()->toFormattedDateString() }}</td>
        <td>{{ $invoice->total() }}</td>
        <td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>
    </tr>
@endforeach

To provide the download functionality, you just need a simple route and controller method:

// In routes/web.php
Route::get('/user/invoice/{invoice}', [InvoiceController::class, 'download']);

// In InvoiceController.php
public function download(Request $request, $invoiceId)
{
    return $request->user()->downloadInvoice($invoiceId, [
        'vendor' => 'Your Company',
        'product' => 'Your Product',
    ]);
}

Processing Webhooks for Reliability

A reliable billing system must respond to events that happen outside your application, such as a recurring payment succeeding or failing. Stripe notifies your application of these events via webhooks.

Cashier includes a dedicated webhook controller to process incoming events. To enable it, you just need to point a route to it in your routes/web.php file.

// In routes/web.php
use Laravel\Cashier\Http\Controllers\WebhookController;

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

You must also configure the webhook endpoint URL in your Stripe dashboard and tell Stripe which events to send (e.g., invoice.payment_succeeded, invoice.payment_failed). Cashier automatically handles events like updating your database when a subscription fails or is cancelled. You can easily extend the webhook controller to handle custom events your application cares about.

Beyond Stripe: Cashier and Other Gateways

While Laravel Cashier is built for Stripe, its underlying architecture is adaptable. Several community-driven packages have emerged to bring Cashier's elegant syntax to other payment providers.

  • Cashier for Mollie: Maintained by the Mollie team, this package provides a seamless integration for European markets.
  • Cashier for Paddle: A popular choice for businesses that need a merchant of record to handle tax compliance.
  • Cashier for Braintree: For teams looking for a PayPal-backed alternative to Stripe.

The existence of these packages demonstrates the power and flexibility of Cashier's design. If your business needs to leverage a different payment gateway, it's worth investigating if a Cashier adapter already exists. This can significantly accelerate project delivery compared to building a custom integration from the ground up.

Potential Limitations

The primary limitation of Cashier is its opinionated nature. It is designed specifically for subscription billing with a per-seat or flat-rate model. For more complex billing scenarios, like usage-based billing or metered pricing, you might need to extend Cashier or use a lower-level integration. However, for the vast majority of SaaS applications, Cashier's feature set is more than sufficient.

Conclusion: A Powerful Tool to Optimize Your Billing Workflow

Laravel Cashier is an essential, reliable tool for any company building subscription-based applications with Laravel. It provides a comprehensive, fluent, and elegant API that drastically simplifies the complexities of recurring billing. By handling the heavy lifting of interacting with payment providers, Cashier empowers your development team to:

  • Accelerate project delivery by focusing on core features instead of billing boilerplate.
  • Enhance code quality with a proven, well-tested, and expressive API.
  • Reduce development friction by abstracting away the complexities of payment provider integrations.

By mastering Laravel Cashier, you can build a scalable, reliable, and maintainable billing system that supports your business's growth. It's a perfect example of Laravel's commitment to developer experience, providing a powerful solution that allows your team to build better products, faster.


Related articles

Continue exploring Laravel insights and practical delivery strategies.

Laravel consulting

Need senior Laravel help for this topic?

Let's adapt these practices to your product and deliver the next milestone.