Professional Documents
Culture Documents
Introduction
Upgrading Cashier
Installation
Configuration
Billable Model
API Keys
Currency Configuration
Logging
Customers
Retrieving Customers
Creating Customers
Updating Customers
Payment Methods
Creating Subscriptions
Checking Subscription Status
Changing Plans
Subscription Quantity
Multiplan Subscriptions
Subscription Taxes
Subscription Anchor Date
Cancelling Subscriptions
Resuming Subscriptions
Subscription Trials
With Payment Method Up Front
Without Payment Method Up Front
Extending Trials
Handling Stripe Webhooks
Simple Charge
Charge With Invoice
Refunding Charges
Invoices
Testing
Introduction
Laravel Cashier provides an expressive, fluent interface to Stripe's
subscription billing services. It handles almost all of the boilerplate
subscription billing code you are dreading writing. In addition to basic
subscription management, Cashier can handle coupons, swapping
subscription, subscription "quantities", cancellation grace periods, and
even generate invoice PDFs.
Upgrading Cashier
When upgrading to a new version of Cashier, it's important that you
carefully review the upgrade guide.
{note} To prevent breaking changes, Cashier uses a fixed Stripe
API version. Cashier 11 utilizes Stripe API version 2020-03-02 . The
Stripe API version will be updated on minor releases in order to
make use of new Stripe features and improvements.
Installation
First, require the Cashier package for Stripe with Composer:
Database Migrations
The Cashier service provider registers its own database migration
directory, so remember to migrate your database after installing the
package. The Cashier migrations will add several columns to your
users table as well as create a new subscriptions table to hold all
of your customer's subscriptions:
If you need to overwrite the migrations that ship with the Cashier
package, you can publish them using the vendor:publish Artisan
command:
1 use Laravel\Cashier\Cashier;
2
3 Cashier::ignoreMigrations();
{note} Stripe recommends that any column used for storing Stripe
identifiers should be case-sensitive. Therefore, you should ensure
the column collation for the stripe_id column is set to, for
example, utf8_bin in MySQL. More info can be found in the
Stripe documentation.
Configuration
Billable Model
Before using Cashier, add the Billable trait to your model definition.
This trait provides various methods to allow you to perform common
billing tasks, such as creating subscriptions, applying coupons, and
updating payment method information:
1 use Laravel\Cashier\Billable;
2
3 class User extends Authenticatable
4 {
5 use Billable;
6 }
Cashier assumes your Billable model will be the App\User class that
ships with Laravel. If you wish to change this you can specify a
different model in your .env file:
1 CASHIER_MODEL=App\User
API Keys
Next, you should configure your Stripe key in your .env file. You can
retrieve your Stripe API keys from the Stripe control panel.
1 STRIPE_KEY=your-stripe-key
2 STRIPE_SECRET=your-stripe-secret
Currency Configuration
The default Cashier currency is United States Dollars (USD). You can
change the default currency by setting the CASHIER_CURRENCY
environment variable:
1 CASHIER_CURRENCY=eur
1 CASHIER_CURRENCY_LOCALE=nl_BE
Logging
Cashier allows you to specify the log channel to be used when logging
all Stripe related exceptions. You may specify the log channel using
the CASHIER_LOGGER environment variable:
1 CASHIER_LOGGER=stack
Customers
Retrieving Customers
You can retrieve a customer by their Stripe ID using the
Cashier::findBillable method. This will return an instance of the
Billable model:
1 use Laravel\Cashier\Cashier;
2
3 $user = Cashier::findBillable($stripeId);
Creating Customers
Occasionally, you may wish to create a Stripe customer without
beginning a subscription. You may accomplish this using the
createAsStripeCustomer method:
1 $stripeCustomer = $user->createAsStripeCustomer();
Once the customer has been created in Stripe, you may begin a
subscription at a later date. You can also use an optional $options
array to pass in any additional parameters which are supported by the
Stripe API:
1 $stripeCustomer = $user-
>createAsStripeCustomer($options);
1 $stripeCustomer = $user->createOrGetStripeCustomer();
Updating Customers
Occasionally, you may wish to update the Stripe customer directly
with additional information. You may accomplish this using the
updateStripeCustomer method:
1 $stripeCustomer = $user-
>updateStripeCustomer($options);
Payment Methods
1 return view('update-payment-method', [
2 'intent' => $user->createSetupIntent()
3 ]);
After you have created the Setup Intent and passed it to the view, you
should attach its secret to the element that will gather the payment
method. For example, consider this "update payment method" form:
{tip} If you would like more information about Setup Intents and
gathering customer payment details please review this overview
provided by Stripe.
1 $paymentMethods = $user->paymentMethods();
1 $paymentMethod = $user->defaultPaymentMethod();
You can also retrieve a specific payment method that is owned by the
Billable model using the findPaymentMethod method:
1 $paymentMethod = $user-
>findPaymentMethod($paymentMethodId);
1 if ($user->hasDefaultPaymentMethod()) {
2 //
3 }
1 if ($user->hasPaymentMethod()) {
2 //
3 }
1 $user->updateDefaultPaymentMethod($paymentMethod);
1 $user->updateDefaultPaymentMethodFromStripe();
1 $user->addPaymentMethod($paymentMethod);
1 $paymentMethod->delete();
1 $user->deletePaymentMethods();
{note} If a user has an active subscription, you should prevent
them from deleting their default payment method.
Subscriptions
Creating Subscriptions
To create a subscription, first retrieve an instance of your billable
model, which typically will be an instance of App\User . Once you have
retrieved the model instance, you may use the newSubscription
method to create the model's subscription:
1 $user = User::find(1);
2
3 $user->newSubscription('default', 'premium')-
>create($paymentMethod);
Additional Details
Coupons
1 $user->newSubscription('default', 'monthly')
2 ->withCoupon('code')
3 ->create($paymentMethod);
Adding Subscriptions
1 $user = User::find(1);
2
3 $user->newSubscription('default', 'premium')->add();
If you would like to determine if a user is still within their trial period,
you may use the onTrial method. This method can be useful for
displaying a warning to the user that they are still on their trial period:
1 if ($user->subscription('default')->onTrial()) {
2 //
3 }
1 if ($user->subscribedToPlan('monthly', 'default')) {
2 //
3 }
1 if ($user->subscription('default')->recurring()) {
2 //
3 }
1 if ($user->subscription('default')->cancelled()) {
2 //
3 }
You may also determine if a user has cancelled their subscription, but
are still on their "grace period" until the subscription fully expires. For
example, if a user cancels a subscription on March 5th that was
originally scheduled to expire on March 10th, the user is on their
"grace period" until March 10th. Note that the subscribed method
still returns true during this time:
1 if ($user->subscription('default')->onGracePeriod()) {
2 //
3 }
1 if ($user->subscription('default')->ended()) {
2 //
3 }
1 if ($user->hasIncompletePayment('default')) {
2 //
3 }
4
5 if ($user->subscription('default')-
>hasIncompletePayment()) {
6 //
7 }
If you would like the subscription to still be considered active when it's
in a past_due state, you may use the
keepPastDueSubscriptionsActive method provided by Cashier.
Typically, this method should be called in the register method of
your AppServiceProvider :
1 use Laravel\Cashier\Cashier;
2
3 /**
4 * Register any application services.
5 *
6 * @return void
7 */
8 public function register()
9 {
10 Cashier::keepPastDueSubscriptionsActive();
11 }
Changing Plans
After a user is subscribed to your application, they may occasionally
want to change to a new subscription plan. To swap a user to a new
subscription, pass the plan's identifier to the swap method:
1 $user = App\User::find(1);
2
3 $user->subscription('default')->swap('provider-plan-
id');
If you would like to swap plans and cancel any trial period the user is
currently on, you may use the skipTrial method:
1 $user->subscription('default')
2 ->skipTrial()
3 ->swap('provider-plan-id');
If you would like to swap plans and immediately invoice the user
instead of waiting for their next billing cycle, you may use the
swapAndInvoice method:
1 $user = App\User::find(1);
2
3 $user->subscription('default')-
>swapAndInvoice('provider-plan-id');
Prorations
By default, Stripe prorates charges when swapping between plans.
The noProrate method may be used to update the subscription's
without prorating the charges:
1 $user->subscription('default')->noProrate()-
>swap('provider-plan-id');
Subscription Quantity
Sometimes subscriptions are affected by "quantity". For example, your
application might charge $10 per month per user on an account. To
easily increment or decrement your subscription quantity, use the
incrementQuantity and decrementQuantity methods:
1 $user = User::find(1);
2
3 $user->subscription('default')->incrementQuantity();
4
5 // Add five to the subscription's current quantity...
6 $user->subscription('default')->incrementQuantity(5);
7
8 $user->subscription('default')->decrementQuantity();
9
10 // Subtract five to the subscription's current
quantity...
11 $user->subscription('default')->decrementQuantity(5);
1 $user->subscription('default')->updateQuantity(10);
1 $user->subscription('default')->noProrate()-
>updateQuantity(10);
Multiplan Subscriptions
Multiplan subscriptionss allow you to assign multiple billing plans to a
single subscription. For example, imagine you are building a customer
service "helpdesk" application that has a base subscription of $10 per
month, but offers a live chat add-on plan for an additional $15 per
month:
1 $user = User::find(1);
2
3 $user->subscription('default')->addPlan('chat-plan');
Now the customer will have two plans on their default subscription.
The example above will add the new plan and the customer will be
billed for it on their next billing cycle. If you would like to bill the
customer immediately you may use the addPlanAndInvoice method:
1 $user->subscription('default')-
>addPlanAndInvoice('chat-plan');
1 $user->subscription('default')->removePlan('chat-
plan');
Proration
1 $user->subscription('default')->noProrate()-
>removePlan('chat-plan');
Quantities
If you would like to update quantities on individual subscription plans,
you may do so using the existing quantity methods and passing the
name of hte plan as an additional argument to the method:
1 $user = User::find(1);
2
3 $user->subscription('default')->incrementQuantity(5,
'chat-plan');
4
5 $user->subscription('default')->decrementQuantity(3,
'chat-plan');
6
7 $user->subscription('default')->updateQuantity(10,
'chat-plan');
Subscription Items
When a subscription has multiple plans, it will have multiple
subscription "items" stored in your database's subscription_items
table. You may access these via the items relationship on the
subscription:
1 $user = User::find(1);
2
3 $subscriptionItem = $user->subscription('default')-
>items->first();
4
5 // Retrieve the Stripe plan and quantity for a specific
item...
6 $stripePlan = $subscriptionItem->stripe_plan;
7 $quantity = $subscriptionItem->quantity;
1 $user = User::find(1);
2
3 $subscriptionItem = $user->subscription('default')-
>findItemOrFail('chat-plan');
Subscription Taxes
To specify the tax rates a user pays on a subscription, implement the
taxRates method on your billable model, and return an array with
the Tax Rate IDs. You can define these tax rates in your Stripe
dashboard:
1 $user->subscription('default')->syncTaxRates();
This will also sync any subscription item tax rates so make sure you
also properly change the planTaxRates method.
Tax Exemption
1 $user = User::find(1);
2
3 $user->isTaxExempt();
4 $user->isNotTaxExempt();
5 $user->reverseChargeApplies();
1 use App\User;
2 use Carbon\Carbon;
3
4 $user = User::find(1);
5
6 $anchor = Carbon::parse('first day of next month');
7
8 $user->newSubscription('default', 'premium')
9 ->anchorBillingCycleOn($anchor-
>startOfDay())
10 ->create($paymentMethod);
For more information on managing subscription billing cycles, consult
the Stripe billing cycle documentation
Cancelling Subscriptions
To cancel a subscription, call the cancel method on the user's
subscription:
1 $user->subscription('default')->cancel();
You may determine if a user has cancelled their subscription but are
still on their "grace period" using the onGracePeriod method:
1 if ($user->subscription('default')->onGracePeriod()) {
2 //
3 }
1 $user->subscription('default')->cancelNow();
Resuming Subscriptions
If a user has cancelled their subscription and you wish to resume it,
use the resume method. The user must still be on their grace period
in order to resume a subscription:
1 $user->subscription('default')->resume();
If the user cancels a subscription and then resumes that subscription
before the subscription has fully expired, they will not be billed
immediately. Instead, their subscription will be re-activated, and they
will be billed on the original billing cycle.
Subscription Trials
{note} Cashier manages trial dates for subscriptions and does not
derive them from the Stripe plan. Therefore, you should configure
your plan in Stripe to have a trial period of zero days so that
Cashier can manage the trials instead.
1 $user = User::find(1);
2
3 $user->newSubscription('default', 'monthly')
4 ->trialDays(10)
5 ->create($paymentMethod);
This method will set the trial period ending date on the subscription
record within the database, as well as instruct Stripe to not begin
billing the customer until after this date. When using the trialDays
method, Cashier will overwrite any default trial period configured for
the plan in Stripe.
You may determine if the user is within their trial period using either
the onTrial method of the user instance, or the onTrial method of
the subscription instance. The two examples below are identical:
1 if ($user->onTrial('default')) {
2 //
3 }
4
5 if ($user->subscription('default')->onTrial()) {
6 //
7 }
1 $user = User::create([
2 // Populate other user properties...
3 'trial_ends_at' => now()->addDays(10),
4 ]);
You may also use the onGenericTrial method if you wish to know
specifically that the user is within their "generic" trial period and has
not created an actual subscription yet:
1 if ($user->onGenericTrial()) {
2 // User is within their "generic" trial period...
3 }
Once you are ready to create an actual subscription for the user, you
may use the newSubscription method as usual:
1 $user = User::find(1);
2
3 $user->newSubscription('default', 'monthly')-
>create($paymentMethod);
Extending Trials
The extendTrial method allows you to extend the trial period of a
subscription after it's been created:
If the trial has already expired and the customer is already being billed
for the subscription, you can still offer them an extended trial. The
time spent within the trial period will be deducted from the
customer's next invoice.
Handling Stripe Webhooks
{tip} You may use the Stripe CLI to help test webhooks during
local development.
customer.subscription.updated
customer.subscription.deleted
customer.updated
customer.deleted
invoice.payment_action_required
1 protected $except = [
2 'stripe/*',
3 ];
Defining Webhook Event Handlers
Cashier automatically handles subscription cancellation on failed
charges, but if you have additional webhook events you would like to
handle, extend the Webhook controller. Your method names should
correspond to Cashier's expected convention, specifically, methods
should be prefixed with handle and the "camel case" name of the
webhook you wish to handle. For example, if you wish to handle the
invoice.payment_succeeded webhook, you should add a
handleInvoicePaymentSucceeded method to the controller:
1 <?php
2
3 namespace App\Http\Controllers;
4
5 use Laravel\Cashier\Http\Controllers\WebhookController
as CashierController;
6
7 class WebhookController extends CashierController
8 {
9 /**
10 * Handle invoice payment succeeded.
11 *
12 * @param array $payload
13 * @return
\Symfony\Component\HttpFoundation\Response
14 */
15 public function
handleInvoicePaymentSucceeded($payload)
16 {
17 // Handle The Event
18 }
19 }
Failed Subscriptions
What if a customer's credit card expires? No worries - Cashier's
Webhook controller will cancel the customer's subscription for you.
Failed payments will automatically be captured and handled by the
controller. The controller will cancel the customer's subscription when
Stripe determines the subscription has failed (normally after three
failed payment attempts).
Single Charges
Simple Charge
{note} The charge method accepts the amount you would like to
charge in the lowest denominator of the currency used by
your application.
1 $user->charge(100, $paymentMethod, [
2 'custom_option' => $value,
3 ]);
1 use App\User;
2
3 $stripeCharge = (new User)->charge(100,
$paymentMethod);
The charge method will throw an exception if the charge fails. If the
charge is successful, an instance of Laravel\Cashier\Payment will be
returned from the method:
1 try {
2 $payment = $user->charge(100, $paymentMethod);
3 } catch (Exception $e) {
4 //
5 }
1 $user->invoiceFor('Stickers', 500, [
2 'quantity' => 50,
3 ], [
4 'default_tax_rates' => ['tax-rate-id'],
5 ]);
Refunding Charges
If you need to refund a Stripe charge, you may use the refund
method. This method accepts the Stripe Payment Intent ID as its first
argument:
Invoices
You may easily retrieve an array of a billable model's invoices using
the invoices method:
1 $invoices = $user->invoices();
2
3 // Include pending invoices in the results...
4 $invoices = $user->invoicesIncludingPending();
When listing the invoices for the customer, you may use the invoice's
helper methods to display the relevant invoice information. For
example, you may wish to list every invoice in a table, allowing the
user to easily download any of them:
1 <table>
2 @foreach ($invoices as $invoice)
3 <tr>
4 <td>{{ $invoice->date()-
>toFormattedDateString() }}</td>
5 <td>{{ $invoice->total() }}</td>
6 <td><a href="/user/invoice/{{ $invoice->id
}}">Download</a></td>
7 </tr>
8 @endforeach
9 </table>
1 return $request->user()->downloadInvoice($invoiceId, [
2 'vendor' => 'Your Company',
3 'product' => 'Your Product',
4 ], 'my-invoice');
1 CASHIER_PAYMENT_NOTIFICATION=Laravel\Cashier\Notificati
ons\ConfirmPayment
Stripe SDK
Many of Cashier's objects are wrappers around Stripe SDK objects. If
you would like to interact with the Stripe objects directly, you may
conveniently retrieve them using the asStripe method:
1 $stripeSubscription = $subscription-
>asStripeSubscription();
2
3 $stripeSubscription->update(['application_fee_percent'
=> 5]);
Testing
When testing an application that uses Cashier, you may mock the
actual HTTP requests to the Stripe API; however, this requires you to
partially re-implement Cashier's own behavior. Therefore, we
recommend allowing your tests to hit the actual Stripe API. While this
is slower, it provides more confidence that your application is working
as expected and any slow tests may be placed within their own
PHPUnit testing group.
When testing, remember that that Cashier itself already has a great
test suite, so you should only focus on testing the subscription and
payment flow of your own application and not every underlying
Cashier behavior.
To get started, add the testing version of your Stripe secret to your
phpunit.xml file:
Now, whenever you interact with Cashier while testing, it will send
actual API requests to your Stripe testing environment. For
convenience, you should pre-fill your Stripe testing account with
subscriptions / plans that you may then use during testing.