Snippet

Stripe Checkout with Laravel Cashier

php
use Stripe\Checkout\Session as CheckoutSession;

public function checkout(User $user)
{
    return with($request->user(), function ($user) use ($request) {
        return with(CheckoutSession::create(array_merge($user->stripe_id ? ['customer' => $user->stripe_id] : ['customer_email' => $user->email], [
            'payment_method_types'        => ['card'],
            'subscription_data' => [
                'items'             => [['plan' => 'PLAN_ID_HERE']],
                'trial_period_days' => 7,
            ],
            'allow_promotion_codes' => true,
            'mode'                  => 'subscription',
            'client_reference_id'   => $user->id,
            'success_url'           => url('/home'),
            'cancel_url'            => URL::previous(url('/register')),
        ])), fn ($session) => $session->id);
    });
}
app/Http/StripeWebhookController.php
use Illuminate\Support\Facades\DB;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;

class StripeWebhookController extends CashierController
{
    public function handleCheckoutSessionCompleted(array $payload)
    {
        $session = $payload['data']['object'];
        $user = User::findOrFail($session['client_reference_id']);

        DB::transaction(function () use ($session, $user) {
            $user->update(['stripe_id' => $session['customer']]);

            $user->subscriptions()->create([
                'name'          => 'default',
                'stripe_id'     => $session['subscription'],
                'stripe_status' => 'trialing' // Or use "active" if you don't provide a trial
                'stripe_plan'   => 'PLAN_ID_HERE',
                'quantity'      => 1,
                'trial_ends_at' => now()->addDays(7),
                'ends_at'       => null,
            ]);
        });

        return $this->successMethod();
    }
}

Context

While Laravel Cashier uses Stripe Elements by default, Stripe can now handle the checkout flow themselves. The following snippet allows you to implement this new flow into your Laravel application, while keeping the rest of Cashier working.

Usage

For this to work you'll need to create a route pointing to your StripeWebhookController and point your Stripe webhooks to that route instead of the default one provided by Cashier. You'll also need to add the checkout.session_completed event to your webhook from the Stripe Dashboard.

Enjoyed the article? Consider sharing it on Twitter so others can enjoy it too :)

Share on Twitter

Receive project updates, article drafts & thoughts on your inbox every saturday.

Subscribe →