Laravel Cashier
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.
To prevent breaking changes, Cashier uses a fixed Stripe API version. Cashier 10.1 utilizes Stripe API version 2019-08-14
. 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:
composer require laravel/cashier
To ensure Cashier properly handles all Stripe events, remember to set up Cashier's webhook handling.
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:
php artisan migrate
If you need to overwrite the migrations that ship with the Cashier package, you can publish them using the vendor:publish
Artisan command:
php artisan vendor:publish --tag="cashier-migrations"
If you would like to prevent Cashier's migrations from running entirely, you may use the ignoreMigrations
provided by Cashier. Typically, this method should be called in the register
method of your AppServiceProvider
:
use Laravel\Cashier\Cashier;
Cashier::ignoreMigrations();
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:
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}
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:
CASHIER_MODEL=App\User
If you're using a model other than Laravel's supplied App\User
model, you'll need to publish and alter the migrations provided to match your alternative model's table name.
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.
STRIPE_KEY=your-stripe-key
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:
CASHIER_CURRENCY=eur
In addition to configuring Cashier's currency, you may also specify a locale to be used when formatting money values for display on invoices. Internally, Cashier utilizes PHP's NumberFormatter
class to set the currency locale:
CASHIER_CURRENCY_LOCALE=nl_BE
In order to use locales other than en
, ensure the ext-intl
PHP extension is installed and configured on your server.
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:
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:
use Laravel\Cashier\Cashier;
$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:
$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:
$stripeCustomer = $user->createAsStripeCustomer($options);
You may also use the createOrGetStripeCustomer
method if you want to return the customer object if the billable entity is already a customer within Stripe.
$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:
$stripeCustomer = $user->updateStripeCustomer($options);
Custom Email Addresses
By default, Cashier will use the email
attribute on your Billable model to create customers within Stripe. You can override this using the stripeEmail
method:
/**
* Get the email address used to create the customer in Stripe.
*
* @return string|null
*/
public function stripeEmail()
{
return $this->email;
}
You can also choose to return null
since an email address isn't required for creating a customer within Stripe. If you do not provide an email address, features within Stripe like dunning emails, failed payment reminders, and other email related features will not be available.
Payment Methods
Storing Payment Methods
In order to create subscriptions or perform "one off" charges with Stripe, you will need to store a payment method and retrieve its identifier from Stripe. The approach used to accomplish differs based on whether you plan to use the payment method for subscriptions or single charges, so we will examine both below.
Payment Methods For Subscriptions
When storing credit cards to a customer for future use, the Stripe Setup Intents API must be used to securely gather the customer's payment method details. A "Setup Intent" indicates to Stripe the intention to charge a customer's payment method. Cashier's Billable
trait includes the createSetupIntent
to easily create a new Setup Intent. You should call this method from the route or controller that will render the form which gathers your customer's payment method details:
return view('update-payment-method', [
'intent' => $user->createSetupIntent()
]);
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:
<input id="card-holder-name" type="text">
<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>
<button id="card-button" data-secret="{{ $intent->client_secret }}">
Update Payment Method
</button>
Next, the Stripe.js library may be used to attach a Stripe Element to the form and securely gather the customer's payment details:
<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('stripe-public-key');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
</script>
Next, the card can be verified and a secure "payment method identifier" can be retrieved from Stripe using Stripe's confirmCardSetup
method:
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;
cardButton.addEventListener('click', async (e) => {
const { setupIntent, error } = await stripe.confirmCardSetup(
clientSecret, {
payment_method: {
card: cardElement,
billing_details: { name: cardHolderName.value }
}
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});
After the card has been verified by Stripe, you may pass the resulting setupIntent.payment_method
identifier to your Laravel application, where it can be attached to the customer. The payment method can either be added as a new payment method or used to update the default payment method. You can also immediately use the payment method identifier to create a new subscription.
If you would like more information about Setup Intents and gathering customer payment details please review this overview provided by Stripe.
Payment Methods For Single Charges
Of course, when making a single charge against a customer's payment method we'll only need to use a payment method identifier a single time. Due to Stripe limitations, you may not use the stored default payment method of a customer for single charges. You must allow the customer to enter their payment method details using the Stripe.js library. For example, consider the following form:
<input id="card-holder-name" type="text">
<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>
<button id="card-button">
Process Payment
</button>
Next, the Stripe.js library may be used to attach a Stripe Element to the form and securely gather the customer's payment details:
<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('stripe-public-key');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
</script>
Next, the card can be verified and a secure "payment method identifier" can be retrieved from Stripe using Stripe's createPaymentMethod
method:
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
cardButton.addEventListener('click', async (e) => {
const { paymentMethod, error } = await stripe.createPaymentMethod(
'card', cardElement, {
billing_details: { name: cardHolderName.value }
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});
If the card is verified successfully, you may pass the paymentMethod.id
to your Laravel application and process a single charge.
Retrieving Payment Methods
The paymentMethods
method on the Billable model instance returns a collection of Laravel\Cashier\PaymentMethod
instances:
$paymentMethods = $user->paymentMethods();
To retrieve the default payment method, the defaultPaymentMethod
method may be used:
$paymentMethod = $user->defaultPaymentMethod();
You can also retrieve a specific payment method that is owned by the Billable model using the findPaymentMethod
method:
$paymentMethod = $user->findPaymentMethod($paymentMethodId);
Determining If A User Has A Payment Method
To determine if a Billable model has a payment method attached to their account, use the hasPaymentMethod
method:
if ($user->hasPaymentMethod()) {
//
}