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

vincent15000's avatar

Cashier with Stripe and session checkout => no subscription created in the database

Hello,

I have setup Cashier and Stripe to sell subscriptions with monthly payment. It was quite easy to do.

public function subscribe(Request $request, Plan $plan)
{
    return auth()->user()
        ->newSubscription($plan->slug, $plan->stripe_price_id)
        ->quantity($request->number_of_users)
        ->checkout([
            // 'success_url' => route('your-success-route'),
            // 'cancel_url' => route('your-cancel-route'),
        ]);
}

But I don't have any subscription saved in the database.

Should this happen automatically, or do I need to create the subscription manually ?

What do you suggest me ?

Thanks for your help.

V

0 likes
8 replies
martinbean's avatar

@vincent15000 Then you need some way to allow Stripe webhooks to reach your server, in be handled by Cashier’s webhook controller, and perform actions such as creating/updating subscriptions.

I personally use the Stripe CLI which allows you to create a tunnel:

stripe listen --forward-to 'http://localhost/stripe/webhook'

This tunnel needs to be running whenever you’re testing/expecting events to reach your application.

1 like
vincent15000's avatar

@martinbean @jlrdw Perhaps it comes from the CSRF token ? But I don't have created any additional route to listen for the stripe events and I supposed that Cashier already has the needed routes and handlers for a normal functioning.

The document says to bypass the CSRF protection.

https://laravel.com/docs/10.x/billing#webhooks-csrf-protection

protected $except = [
    'stripe/*',
];

UPDATED I have added this in the app.php file in the bootstrap folder, but I get the same errors.

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(CleanParametersMiddleware::class);
        $middleware->validateCsrfTokens(except: [
            'stripe/*',
            'http://127.0.0.1:8000/stripe/*',
        ]);    
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

But how can I customize the VerifyCsrfToken middleware, it's not published anymore (Laravel v11).

Here are the events listened by the local stripe event listener.

2025-02-26 08:38:43   --> customer.updated [evt_1QwfCZJd6VREmFDKYBNySKlh]
2025-02-26 08:38:43   --> payment_method.attached [evt_1QwfCZJd6VREmFDKZaJYSeGF]
2025-02-26 08:38:43   --> charge.succeeded [evt_3QwfCVJd6VREmFDK1diOpxrH]
2025-02-26 08:38:43   --> customer.updated [evt_1QwfCZJd6VREmFDKnHKpAnHD]
2025-02-26 08:38:43   --> checkout.session.completed [evt_1QwfCZJd6VREmFDK0g0wh16M]
2025-02-26 08:38:43   --> customer.subscription.created [evt_1QwfCZJd6VREmFDKPkZZgcSO]
2025-02-26 08:38:43   --> customer.subscription.updated [evt_1QwfCZJd6VREmFDKbaPovPkD]
2025-02-26 08:38:44   --> payment_intent.succeeded [evt_3QwfCVJd6VREmFDK1xKeLJuE]
2025-02-26 08:38:44   --> payment_intent.created [evt_3QwfCVJd6VREmFDK1uBPsldl]
2025-02-26 08:38:44   --> invoice.created [evt_1QwfCZJd6VREmFDKSjxSdMab]
2025-02-26 08:38:44   --> invoice.finalized [evt_1QwfCZJd6VREmFDK7CVKh49R]
2025-02-26 08:38:44   --> invoice.updated [evt_1QwfCZJd6VREmFDKGl0uAGC0]
2025-02-26 08:38:44   --> invoice.paid [evt_1QwfCZJd6VREmFDKKvOCj0yE]
2025-02-26 08:38:44  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKYBNySKlh]
2025-02-26 08:38:44  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKZaJYSeGF]
2025-02-26 08:38:44  <--  [200] POST http://localhost:8000/stripe/webhook [evt_3QwfCVJd6VREmFDK1diOpxrH]
2025-02-26 08:38:44   --> invoice.payment_succeeded [evt_1QwfCaJd6VREmFDKomit4E0K]
2025-02-26 08:38:44  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKnHKpAnHD]
2025-02-26 08:38:44  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDK0g0wh16M]
2025-02-26 08:38:45  <--  [500] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKPkZZgcSO]
2025-02-26 08:38:45  <--  [500] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKbaPovPkD]
2025-02-26 08:38:45  <--  [200] POST http://localhost:8000/stripe/webhook [evt_3QwfCVJd6VREmFDK1xKeLJuE]
2025-02-26 08:38:45  <--  [200] POST http://localhost:8000/stripe/webhook [evt_3QwfCVJd6VREmFDK1uBPsldl]
2025-02-26 08:38:45  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKSjxSdMab]
2025-02-26 08:38:45  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDK7CVKh49R]
2025-02-26 08:38:45  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKGl0uAGC0]
2025-02-26 08:38:45  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKKvOCj0yE]
2025-02-26 08:38:45  <--  [200] POST http://localhost:8000/stripeoth/webhook [evt_1QwfCaJd6VREmFDKomit4E0K]

Two events failed.

2025-02-26 08:38:45  <--  [500] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKPkZZgcSO]
2025-02-26 08:38:45  <--  [500] POST http://localhost:8000/stripe/webhook [evt_1QwfCZJd6VREmFDKbaPovPkD]
vincent15000's avatar

And I get this log in stripe.

invalid_request_error - url
Invalid URL: URL must be publicly accessible. Consider using a tool like the Stripe CLI to test webhooks locally: https://github.com/stripe/stripe-cli

But I use the stripe CLI.

./stripe listen --forward-to localhost:8000/stripe/webhook
vincent15000's avatar
vincent15000
OP
Best Answer
Level 63

I just found the problem (not solved for now, but found) : I'm using ULID for primary keys in all tables, but Cashier doesn't use ULID and it generates an error while creating the subscription with an ULID foreign key for user_id.

I have modified the foreign ids to foreign ulid in the cashier migrations and it works fine.

Please or to participate in this conversation.