A FIELD GUIDE TO LARAVEL · VOLUME II · THE ECOSYSTEM
ENTRY II.7 · BILLING
Cashier
Laravel\Cashier · Package · first recorded 4 March 2014, v1.0.0 on Packagist
Stripe subscription billing as a trait on your user model. Billable gives subscriptions, trials, swaps and invoices; Stripe's webhooks keep a local subscriptions table in step, so subscribed() is a database read.
Specification
Kind Package: a trait, migrations, a webhook route, a payment page
Interface The Billable trait; Stripe Checkout, Payment Element, or a payment method ID
Client stripe-php 17 to 21; the Stripe API version is the installed SDK's
Installed by composer require laravel/cashier · vendor:publish · migrate
Voice cashier:webhook (creates the endpoint in Stripe)
Scales by Rows in subscriptions and subscription_items; Stripe holds the rest
Range Cloud: yes. /stripe/webhook must be reachable from Stripe
Forge, VPS: yes, the same route and secret
Vapor: yes. Webhooks are plain HTTP; nothing resident
Neighbours
Cashier Paddle is the sibling package: Paddle is merchant of record, so sales tax is Paddle's, and checkout is an overlay. Spark builds a customer billing portal on top of Cashier. The distinction: Cashier is the billing code in your app, Spark the screens your customers use.
Field marks
STRIPE_KEY · STRIPE_WEBHOOK_SECRET
config/cashier.php
use Laravel\Cashier\Billable
subscriptions, subscription_items
Fig. II.7.1 · One subscription, kept in step
Parts
1 Billable. use Billable on User. Adds stripe_id, trial_ends_at and the payment-method columns by migration.
2 Checkout. newSubscription('default', 'price_monthly')->checkout() sends the customer to Stripe's hosted page.
3 Stripe, holds the customer, the subscription and the card. Cashier wraps its objects; asStripeSubscription() unwraps.
4 Webhook. /stripe/webhook, registered by Cashier, verified with STRIPE_WEBHOOK_SECRET; you exempt stripe/* from CSRF.
5 subscriptions table. One row per subscription, stripe_status kept current by the webhook, so subscribed() never calls Stripe.
6 Payment page. The cashier.payment route: where you send the customer after an IncompletePayment, to confirm for SCA.
Hidden joinery
stripe_id wants a utf8_bin collation on MySQL because Stripe ids are case-sensitive. A Checkout subscription needs the customer.subscription.created webhook on, or no local row appears. A Checkout trial is 48 hours minimum, Stripe's floor. CASHIER_PAYMENT_NOTIFICATION turns on off-session SCA mail, off by default.
Checked line by line against laravel.com/docs/13.x/billing, the 16.x source and Packagist on 2026-10-08.
TITLE
Cashier · kept in step
SOURCES
laravel.com/docs/13.x/billing · github.com/laravel/cashier-stripe/tree/16.x · github.com/laravel/cashier-stripe/blob/16.x/src/Cashier.php · github.com/laravel/cashier-stripe/blob/16.x/composer.json · github.com/stripe/stripe-php/blob/v17.4.0/lib/Util/ApiVersion.php · packagist.org/packages/laravel/cashier · laravel.com/docs/13.x/cashier-paddle · spark.laravel.com/docs · www.paddle.com · Monitor 576
STATUS
Verified · 2026-10-08
SHEET
II.7 of 48
REV
A · 2026-10-08
DRAWN
BS
FINISH
All faces, including the back