# Laravel Cashier Stripe: subscription billing inside an Eloquent model

> Cashier wraps Stripe's subscription API in a Laravel billable trait. It is a good fit when your users, plans and invoices all live in the same database as the rest of your app, and a poor fit when you need a payment gateway other than Stripe.

**laravel/cashier-stripe** — Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

- Repository: https://github.com/laravel/cashier-stripe
- Website: https://laravel.com/docs/billing
- Stars: 2,548 · Forks: 744
- Language: PHP
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/laravel-cashier-stripe

## The billing boilerplate Cashier removes from a Laravel app

Every subscription product needs the same handful of operations: start a plan, change a plan mid-cycle, apply a coupon, cancel at period end, resume, and produce an invoice. Written directly against the Stripe API in PHP, each of those is a request, a response shape to parse, a local record to keep in sync, and a webhook handler for the cases where Stripe changes state on its own. Cashier exists to collapse that into model methods. The README describes it as an expressive, fluent interface to Stripe's subscription billing services that handles almost all of the boilerplate subscription billing code you are dreading writing. The intended audience is a Laravel developer who already has a users table and does not want a second source of truth for who is subscribed to what. Cashier also covers coupons, swapping subscriptions, subscription quantities, cancellation grace periods, and invoice PDF generation, which are the parts teams usually get wrong the first time. If your application is not Laravel, nothing here applies: the package is built on Eloquent models, service providers and Artisan commands.

## How Cashier maps Stripe objects onto Eloquent models

The repository layout tells you most of the architecture. src/ holds the package code, database/ holds migrations, config/ holds the published configuration file, and routes/ holds the webhook route the package registers. The central idea is a billable model: your User, or any model you choose, gains a trait that turns Stripe customer and subscription identifiers into columns on your own table, so calls like subscribing to a plan, checking whether the model is subscribed, or reading the current subscription state resolve through Eloquent rather than through a separate billing database. Stripe remains the authority on money and on subscription lifecycle; your database keeps the identifiers and enough state to answer questions without a network round trip. Webhooks are how Stripe pushes changes back: a subscription that fails payment, a trial that converts, or a cancellation initiated in the Stripe dashboard all arrive as events, and Cashier's job is to translate them into updates on the billable model. That design is the package's strength and its boundary. Anything you need that Stripe does not model, such as usage records for a bespoke metering scheme, is your code, not Cashier's.

## Installing Laravel Cashier Stripe and taking a first subscription

The README does not print installation steps. It names the package on Packagist as laravel/cashier and sends you to the Laravel website for documentation, at https://laravel.com/docs/billing. That page is where the install commands, the trait name and the environment variables live, and they change between major versions, so take them from there rather than from a blog post. What the repository itself tells you is structural: composer.json declares the package and its Laravel version constraint, database/ holds the migrations that add the Stripe columns to your billable table, config/ holds the configuration file the package expects you to publish, and routes/ holds the webhook route it registers. Read composer.json first and confirm the Laravel constraint matches the framework version you are running, because a mismatch is the failure that wastes the most time. Then read the migrations in database/ against your existing schema before running them anywhere near production, since a column that already exists will abort the migration. The trait goes on whichever model represents your paying user. Once it is applied and the Stripe keys are configured, a subscription is a method call on an instance of that model, and the first successful call writes a Stripe customer identifier onto that model's row, which is the concrete signal that the wiring works. The README does not document rollback, so plan the migration order accordingly.

## Webhooks are not optional, and the route file proves it

The presence of a routes/ directory in the package is the clearest statement of how Cashier expects to stay in sync: it registers an HTTP endpoint that Stripe calls. If that endpoint is not reachable from the public internet, or if the signing secret does not match the one configured in the Stripe dashboard, subscriptions will drift. A customer cancels in Stripe, your database still says active, and your application keeps granting access. This is the most common failure mode for the package and it is an operational one, not a code one. It also means local development needs a tunnel or a Stripe CLI forwarder, because Stripe cannot call localhost. Cashier's webhook handling is deliberately narrow: it maps Stripe events onto billable model state. If you need to react to an event Cashier does not handle, you register your own listener, and at that point you are maintaining two paths into the same subscription state. Teams that already run a central billing service will find this split awkward, because the webhook endpoint belongs to whichever application holds the billable model.

## Where Cashier is the wrong tool: Paddle, PayPal and non-Laravel stacks

Cashier is Stripe-specific. The related searches for this package include Laravel Cashier Paddle and Laravel Cashier PayPal, which suggests people arrive expecting one package to cover several gateways. It does not. Laravel ships a separate Cashier for Paddle, and that is a different package with a different API surface, not a driver you switch inside this one. There is no PayPal equivalent in this repository. If your business requires PayPal, or if you want Paddle because it acts as merchant of record and handles tax for you, this package cannot help and you should not try to wrap it. The same applies to the search phrase Laravel Stripe Connect: Connect is Stripe's marketplace product for paying out to third parties, and while you can call the Stripe PHP SDK directly for it, Cashier's subscription model is aimed at a business billing its own customers, not at a platform splitting charges between sellers. The other hard boundary is the framework. Cashier's value comes from Eloquent and Laravel's service container; in a Symfony or plain PHP application you would be paying the dependency cost of Laravel for a trait you cannot use.

## Alternatives: the Stripe PHP SDK, and a separate billing service

The most direct alternative is the official Stripe PHP library used on its own. The difference is where state lives. With the SDK you write the customer creation, the subscription call, the local persistence and the webhook handler yourself, which means you also decide exactly which fields you store and how you reconcile them. That is more code, but it is also the right choice when your billing rules are unusual, when you want to keep the payment integration in one small module rather than spread across models, or when the application is not Laravel at all. Cashier trades that control for convention: it decides the columns, the trait methods and the webhook mapping, and you accept them. The second alternative is architectural rather than a library. A separate billing service that owns the Stripe account and exposes its own API keeps subscription state out of the web application entirely, which suits organisations with several products sharing one Stripe customer. Cashier assumes the opposite: one Laravel application, one billable model, one Stripe account. Choose between them by asking whether subscription state belongs in your application database or outside it.

## Versioning, licence and the cost of staying current

The default branch is 16.x and the most recent release listed is v16.8.0 from 2026-09-01, with v16.7.0 and v16.6.0 before it. The last push to the repository was on 2026-09-01, so this is a package that moves in small, frequent increments rather than in large rewrites, and the major version tracks the Laravel release it supports. That is the upgrade cost you should plan for: a Laravel major upgrade generally means a Cashier major upgrade, and the repository ships an UPGRADE.md file precisely because those transitions need reading. The CHANGELOG.md is the place to check what changed between minor versions before bumping. Cashier is MIT licensed, which permits commercial use and modification; the practical implication is that you can fork it if you need a change upstream will not take, but you then own the merge burden on every future release. Cashier is not archived and its last push is recent, so the maintenance question is not whether it is alive but whether its release cadence lines up with your Laravel upgrade schedule.

## Conclusion

Adopt Laravel Cashier Stripe if your application is Laravel, your gateway is Stripe, and you want subscriptions expressed as methods on your User model rather than as raw API calls. Do not adopt it if you need Paddle or PayPal, or if your billing lives in a separate service that Laravel does not own. Before writing code, verify three things: that the package version matches your Laravel release according to composer.json, that the migrations in database/ have been reviewed against your existing schema, and that the webhook route from routes/ is reachable at the URL you register in the Stripe dashboard. Cashier is a thin layer over Stripe, so anything Stripe does not support is not something Cashier can add.

## FAQ

### Can Laravel Cashier Stripe work with Paddle or PayPal instead of Stripe?

No. This package is built for Stripe. Laravel publishes a separate Cashier for Paddle, and the repository has no PayPal equivalent.

### What does Laravel Cashier Stripe actually handle for me?

According to the README it provides a fluent interface to Stripe's subscription billing services and covers basic subscription management, coupons, swapping subscriptions, subscription quantities, cancellation grace periods and invoice PDF generation.

### How do I install Laravel Cashier Stripe?

The README does not print install steps; it names the package on Packagist as laravel/cashier and points to the Laravel website for documentation. The repository ships migrations, a config directory and a webhook route.

### Why does my subscription state drift from what Stripe shows?

The package registers a webhook route from its routes/ directory, and Stripe pushes lifecycle changes to that endpoint. If the URL is not reachable or the signing secret does not match, your local state will not follow Stripe.

## Sources

- [laravel/cashier-stripe on GitHub](https://github.com/laravel/cashier-stripe)
- [License: MIT](https://github.com/laravel/cashier-stripe/blob/16.x/LICENSE)
- [Project website](https://laravel.com/docs/billing)
- [README](https://github.com/laravel/cashier-stripe/blob/16.x/README.md)
- [Releases](https://github.com/laravel/cashier-stripe/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/laravel-cashier-stripe
