So you're building a web application where users can signup to your website and access your web application but then, you realized that your web application can bring you hundreds if not, thousands of revenue. However, you don't really know exactly where to start. In this tutorial, we will learn how to create monthly subscription plans using Laravel 7 and Cashier to get payments from users through Stripe (or their credit cards) What is Laravel Cashier Laravel cashier is a package from Laravel that provides an expressive and fluent interface to Stripe's subscription billing services. With Laravel Cashier, you can create coupons, subscription plans, and even generate invoice PDFs.It's safe to say that almost everything you need to create a flawless subscription system is in Laravel cashier. How to install Laravel Cashier To install Cashier in Laravel, all you need to do is to use the following command in your terminal: composer require laravel/cashier It's important to note that we will be using a pre-setup project for this tutorial. If you don't know how to create a project in Laravel, you may check out our guide here. Creating a new Laravel project After installation, you will then have to use the following command to create the database for the cashier: php migrate artisan The command should give you the following in the terminal. After the migration, you can see in your database that there are two new tables which are for subscriptions and other items. Cashier will also add 4 columns inside the users table. These columns are for the card details and for when the trial will end (if any). Stripe API Before we begin using Laravel Cashier, we need to create an account from Stripe to get API keys and secret keys for Cashier.If you already have an account, you may skip this step. Otherwise, you may register using the button below: Sign up to Stripe After the registration and email verification for your account.Go to Developers tab and select the API keys page. Since our account is not activated, we can only use the standard keys.Under the standard keys section, you can copy the following keys. The publishable key is your API key and the secret key is your secret key.Now let's apply these keys to our application.Open your .env file and copy the following code: STRIPE_KEY=pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxx STRIPE_SECRET=sk_test_xxxxxxxxxxxxxxxxxxxxxxxxx Make sure to replace the value with your API key and secret key.Don't forget to save the .env file. User's Billable For us to be able to perform common billing tasks such as subscriptions, we will have to add the Billable trait to our User model. Let's open User.php Go to your project folder > app > User.php Then, just underneath the line of use Illuminate\Notifications\Notifiable;, apply the following code: use Laravel\Cashier\Billable; Then, just beside the Notifiable, you can just add Billable.The updated code should have the following: Save the script. And there we have it, we have finally installed and setup Cashier to our Laravel application. Creating a subscription Now that we have installed Cashier in our Laravel application, we can now start creating subscription plans for our users. Create products with Stripe Luckily, we can all do this with our Stripe account so login to our Stripe dashboard and navigate to the products page and click the Add Product button. A form should pop up as soon as you press the add product button.Fill up the form. NameThis will be the name of the subscription plan. Note that this is visible to customers at checkout and in their receipts or invoices.Description *To describe what the plan can do for users. Note that this is also visible to users at checkout. Image *You may upload an image to describe the subscription plan. Totally optionalStatement descriptor *Statement descriptor is what will be shown to your customer's bank statement.Unit label *This is used to describe how you sell your product. For example, if you sell a product by its weight, then you can enter either kg or any unit.Since we're creating a plan, you can just leave this empty.Metadata *If you want to store additional data, you can create it here.Pricing modelChoose standard pricing if your selling subscription plans or one time payment items.Change to package pricing if you are selling products by units.Select graduated pricing if you use pricing tiers that changes the price for some units in an order.Select volume pricing if you want to charge your customers based on the quantity or units.PriceEnter the amount that you want to charge your customers.You can also select if you want to charge your customers monthly or one time only.Billing periodHere you can select if you want to charge your customers daily, weekly, monthly or yearly (and so on).Add free trial *If you want to give your customers a trial, you can set how many days before they will be charged.Usage is metered *Metered billing lets you charge your customers based on their usage.Price description *Something you can use to describe the price.Items with * are optional Once you're done filling up the form, you can save by clicking the Save button at the top-right of the page.After saving, you will be redirected to the product's page. In the image above, we have created only two pricing. If you want to add more, feel free to do so.So what we really need here is the API ID beside each of the pricing. We're going store them in our database so it will be much easier to access them rather than going back to stripe. Creating the model Open your terminal and run the following code: php artisan make:model Plans -m This will create a migration file for us which we'll then edit for our subscription plans.So open the file which is located inside the migrations folder of the database folder. Once you have accessed the file, copy the following code: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreatePlansTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('plans', function (Blueprint $table) { $table->id(); $table->string('title'); $table->string('identifier')->unique; $table->string('stripe_id')->unique; $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('plans'); } } Save the file and open your terminal once again and run the following command php artisan migrate This will create the table in your database. Now click the plans table.We will have to insert two rows in this table or depending on how many plans you have created in your Stripe account.So we'll just go over the SQL page and use the following SQL query to insert our first row. INSERT INTO plans(`title`,`identifier`,`stripe_id`,`created_at`,`updated_at`) VALUES ('Premium Plan','premium','ENTER YOUR API ID HERE',NOW(),NOW()) Make sure you enter your API ID which you can find beside the pricing of your Stripe product. Then, another SQL query: INSERT INTO plans(`title`,`identifier`,`stripe_id`,`created_at`,`updated_at`) VALUES ('Basic Plan','basic','ENTER YOUR API ID HERE',NOW(),NOW()) Your table should look like this: Creating the subscription controller The next thing that we need to create is the controller for our subscription plans. So open your terminal again and run the following command: php artisan make:controller Subscriptions\SubscriptionController This will create Subscriptions folder and a new file named SubscriptionController.phpYou can access them under app > Http > Controllers Open SubscriptionController.php and update its code to the following: <?php namespace App\Http\Controllers\Subscriptions; use App\Plans; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class SubscriptionController extends Controller { public function index() { $plans = Plans::get(); return view('subscriptions.plans', compact('plans')); } } Creating the subscription plans view Navigate to your views folder which is located inside the resources folder.Then, create a new folder and name it subscriptions.Then, inside the subscriptions folder, create a new file and name it plans.blade.php. Open the plans.blade.php and copy the following code: @extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">{{ __('Subscription Plans') }}</div> <div class="card-body"> @foreach($plans as $plan) <div> <a href="{{ route('payments', ['plan' => $plan->identifier]) }}">{{$plan->title}}</a> </div> @endforeach </div> </div> </div> </div> </div> @endsection Adding routes Open web.php which located inside the routes folder and update its code to the following: <?php use Illuminate\Support\Facades\Route; /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::group(['namespace' => 'Subscriptions'], function() { Route::get('plans', 'SubscriptionController@index')->name('plans'); }); Route::get('/', function () { return view('welcome'); }); Auth::routes(); Route::get('/home', 'HomeController@index')->name('home'); This should allow you to access the plans page like below Creating payment controller Open your terminal once again and use the following command to create the PaymentController. php artisan make:controller Subscriptions\PaymentController After that, navigate to your project folder > app > Http > Controllers > Subscription and open PaymentController.php and copy the following code: <?php namespace App\Http\Controllers\Subscriptions; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class PaymentController extends Controller { public function index() { $data = [ 'intent' => auth()->user()->createSetupIntent() ]; return view('subscriptions.payment')->with($data); } public function store(Request $request) { } } So, what we're doing here is we're just passing to our payment view the intent value from the createSetupIntent() function.Since we still don't have the said view, let's go and create that file. Creating the payment view Go to your resources folder and open the views folder and inside the subscriptions, create a new file and name it payment.blade.php. Then copy the following code: @extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">{{ __('Checkout page') }}</div> <div class="card-body"> <form id="payment-form" action="{{ route('payments.store') }}" method="POST"> @csrf <input type="hidden" name="plan" id="plan" value="{{ request('plan') }}"> <div class="form-group"> <label for="">Name</label> <input type="text" name="name" id="card-holder-name" class="form-control" value="" placeholder="Name on the card"> </div> <div class="form-group"> <label for="">Card details</label> <div id="card-element"></div> </div> <button type="submit" class="btn btn-primary w-100" id="card-button" data-secret="{{ $intent->client_secret }}">Pay</button> </form> </div> </div> </div> </div> </div> <script> const stripe = Stripe('{{ config('cashier.key') }}') const elements = stripe.elements() const cardElement = elements.create('card') cardElement.mount('#card-element') const form = document.getElementById('payment-form') const cardBtn = document.getElementById('card-button') const cardHolderName = document.getElementById('card-holder-name') form.addEventListener('submit', async (e) => { e.preventDefault() cardBtn.disabled = true const { setupIntent, error } = await stripe.confirmCardSetup( cardBtn.dataset.secret, { payment_method: { card: cardElement, billing_details: { name: cardHolderName.value } } } ) if(error) { cardBtn.disable = false } else { let token = document.createElement('input') token.setAttribute('type', 'hidden') token.setAttribute('name', 'token') token.setAttribute('value', setupIntent.payment_method) form.appendChild(token) form.submit(); } }) </script> @endsection Next, go to your routes folder again and open the web.php file and update its code to the following: <?php use Illuminate\Support\Facades\Route; /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::group(['namespace' => 'Subscriptions'], function() { Route::get('plans', 'SubscriptionController@index')->name('plans'); Route::get('/payments', 'PaymentController@index')->name('payments'); Route::post('/payments', 'PaymentController@store')->name('payments.store'); }); Route::get('/', function () { return view('welcome'); }); Auth::routes(); Route::get('/home', 'HomeController@index')->name('home'); Now the next thing that we need to do is to make sure that we're referencing the JavaScript file of Stripe so go and open the app.blade.php and add the following script tag inside the head tags. <script src="https://js.stripe.com/v3/"></script> After adding the script tag, you should then be able to run your app like below. Awesome! Creating the subscription Now the last thing that we need to do is to create the subscription and store the result into our database. Let's go and open the PaymentController.php for the very last time and update its code to the following: <?php namespace App\Http\Controllers\Subscriptions; use App\Plans; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class PaymentController extends Controller { public function index() { $data = [ 'intent' => auth()->user()->createSetupIntent() ]; return view('subscriptions.payment')->with($data); } public function store(Request $request) { $this->validate($request, [ 'token' => 'required' ]); $plan = Plans::where('identifier', $request->plan) ->orWhere('identifier', 'basic') ->first(); $request->user()->newSubscription('default', $plan->stripe_id)->create($request->token); return back(); } } Save the script and enter your test credit card details like below. It should redirect you back to the payment page and if you check your database, you should see that a new row was created for the table subscriptions and subscriptions_items. And if you check your Stripe dashboard, you should see that you've got the payment. Conclusion Adding subscription plans to your web applications can be intimidating but with Laravel cashier and Stripe, creating subscription plans will never be hard anymore.We're hoping that this guide helped you to create subscriptions in Laravel. If you have encountered any issues, you may let us know in the comments below and we'll do our best to help you out.