Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ajck's avatar
Level 1

How to integrate Stripe Checkout with Laravel (5.4) Cashier?

Hi, I'd like my site visitors to be able to sign up to one of three simple subscription plans, paying with a credit/debit card. I've set up Laravel Cashier on the back end, and the default Stripe Checkout on the frontend, and am now just trying to finish the back end Laravel code to tie the two together. I've been following an example Stripe 'recipe' and am looking at the bit where the server receives the Stripe token from the Stripe checkout popup on the front end, here: https://stripe.com/docs/recipes/subscription-signup#create-a-subscription-for-the-customer and trying to match that up with the bit in the Laravel docs about creating a subscription: https://laravel.com/docs/5.4/billing#creating-subscriptions

So I'm effectively trying to merge those two bits of code at those two links (amazed that I can't find anything online about it anywhere given it's using all the standard default Laravel and Stripe stuff!). I'm not sure exactly what code to write. Guessing it's something like the below?

\Stripe\Stripe::setApiKey("my_stripe_secret_key");
$user = User::find(1);
$user->newSubscription('main', 'premium')->create($stripeToken);

1.) What about the try...catch block in the Stripe example code? (at the aforementioned link) - if the payment fails, how does Laravel handle that, or how do I handle that in the Laravel code?

2.) Presumably I'm getting the $stripeToken from Laravel's Request::get('stripeToken') (using the field from the Stripe example code)

3.) The Stripe example code posts the customer's email from the Checkout form, back to Stripe to create the customer, but the Laravel example code doesn't supply email, so I'm not clear on whether this is really necessary or not (for Stripe, or for my database).

4.) What about Laravel's CSRF protection - is that likely to be an issue with receiving the POST from Stripe Checkout?

Basically, the end result I want is as advertised in the two docs - a new customer and subscription entered into the database on both my server, and in Stripe, and Stripe to bill the customer - i.e. all the default standard stuff :)

Thanks for any suggestions!

0 likes
4 replies
martinbean's avatar
Level 80

@ajck You generate the Stripe token using the JavaScript library and then post it to a controller action:

Route::post('subscriptions', 'SubscriptionController@store');
class SubscriptionController extends Controller
{
    public function store(Request $request)
    {
        $this->validate($request, [
            'stripe_token' => 'required',
        ]);

        $request->user()->newSubscription('main', 'plan-id-in-stripe')
                        ->create($request->input('stripe_token'));

        return redirect('/')->withSuccess('You are now subscribed.');
    }
}

You’ll have needed to have created a plan in your Stripe account, and created the database tables as specified in the Cashier docs.

A Stripe payment request can fail with a Stripe\Error\Card instance. This is usually when the card is declined or the user has no funds, so you can catch this exception in your application’s exception handler at app/Exceptions/Handler.php:

use Stripe\Error\Card as CardError;

class Handler extends ExceptionHandler
{
    // Snipped...

    public function render($request, Exception $exception)
    {
        if ($exception instanceof CardError) {
            if ($request->expectsJson()) {
                return response()->json([
                    'error' => $exception->getMessage(),
                ], 400);
            }

            return redirect()->back()
                             ->withInput()
                             ->withError($exception->getMessage());
        }

        //

        return parent::render($request, $exception);
    }
}

All this requires you have a User already in your application to assign a subscription too. You could create the user at the same time as the subscription to allow guests to sign up and subscribe in one go:

class SubscriptionController extends Controller
{
    public function store(Request $request)
    {
        $this->validate($request, [
            'first_name' => 'filled',
            'last_name' => 'filled',
            'email' => 'filled|email|max:255|unique:users,email',
            'password' => 'filled',
            'stripe_token' => 'required',
        ]);

        $user = $this->getUser($request);

        $user->newSubscription('main', 'plan-id-in-stripe')
             ->create($request->input('stripe_token'));

        return redirect('/')->withSuccess('You are now subscribed.');
    }

    protected function getUser(Request $request)
    {
        if ($user = $request->user()) {
            return $user;
        }

        $user = User::create([
            'first_name' => $request->input('first_name'),
            'last_name' => $request->input('last_name'),
            'email' => $request->input('email'),
            'password' => bcrypt($request->input('password')),
        ]);

        Auth::login($user);

        return $user;
    }
}
1 like
ajck's avatar
Level 1

@martinbean This has been extremely helpful, thanks very much, especially the last chunk of code. Appreciated!

ajck's avatar
Level 1

@martinbean Just wondering - any idea how to get the payment amount from the stripeToken that's returned from the payment form submitted by Stripe Checkout? Reason being that I have three different subscription options with three subscribe buttons and need a way to know which was submitted (so I know which plan to sign the user up to) without it being easily hackable. At the moment I've just got a hidden field with the plan name in each of the subscribe button forms. Any user could e.g. open developer options in their browser and change the hidden field plan name (thus e.g. paying the price of the basic subscription for the gold plan!). Thanks

martinbean's avatar

@ajck A token is exactly that: a tokenised version of the card details the customer provided. You get a token instead of card details (number, expiry, CVC etc). From there, it’s up to you how much you charge, so if I user POSTs the ID of a basic plan then that’s what you’d bill them for.

If you look at the Cashier docs, you’ll see that the charge() and invoiceFor() methods accept the amount to be charged.

When creating subscriptions with the newSubscription() builder, you would pass the name of a plan in your Stripe account, and then Stripe will bill the user the price of that plan as set in your account. So you would never find yourself in the situation of POSTing the ID of Plan A and getting it for the price of Plan B.

Please or to participate in this conversation.