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

packy's avatar
Level 7

Larvel Cashier not storing card version 10.1

I am creating a new app using Cashier 10.1. In the past I would send a token from Stripe to the subscription function when registering a user with a subscription. Now it says it takes a Payment Method (id). I am registering a payment method with Stripe and passing that to my controller but it returns the error "This customer has no attached payment source". I read the docs but it only gives an example of how to add a subscription to a current user by passing to the view $user->createSetupIntent(). Below is the code for when a user registers:

Component

       pay() {
            this.isLoading = true;

            if (this.form.payment_method == "cc") {
                let that = this;
                this.stripe
                    .createPaymentMethod({
                        type: "card",
                        card: that.card
                    })
                    .then(result => {
                        this.form.stripePayment = result.paymentMethod.id;
                        this.register();
                    })
                    .catch(e => {
                        console.log(e);
                    });
            } else {
                this.register();
            }
        },

        register() {
            this.form
                .post("/register")
                .then(data => {
                    this.isLoading = false;
                    if (data.type == "success") {
                        this.$swal({
                            type: "success",
                            title: "Great...",
                            text: data.message,
                            toast: true,
                            position: "top-end",
                            showConfirmButton: false,
                            timer: 2000
                        });

                        setTimeout(() => {
                            // window.location.replace(data.url);
                        }, 2000);
                    }
                })
                .catch(error => {
                    this.isLoading = false;
                });
        }

RegisterController

protected function create(request $request)
    {
        $request->validate([
            'name' => 'required',
            'email' => 'required|unique:users',
            'username' => 'required|alpha_dash|unique:users',
            'phone' => 'required',
            'city' => 'required',
            'state' => 'required',
            'password' => 'required|confirmed',
            'agree' => 'required',
        ]);

        $user = User::create([
            'username' => $request['username'],
            'name' => $request['name'],
            'email' => $request['email'],
            'phone' => $request['phone'],
            'city' => $request['city'],
            'state' => $request['state'],
            'password' => Hash::make($request['password']),
        ]);

        if ($request['subscription_type'] == 'premier' && $request['payment_method'] == 'cc') {

            $user->newSubscription('default',  env('STRIPE_PLAN_ID'))->create($request->input('stripePayment'), [
                'email' => $request['email'],
            ]);
        }



        if ($user) {
            $user->assignRole('subscriber');



            Auth::login($user);

            return response()->json([
                'type' => 'success',
                'message' => 'you are all set.',
                'url' => '/dashboard'
            ]);
        }

I posted this on Stackoverflow as well and it was mentioned that Cashier no longer can create a subscription when you create a user. You have to create a user first, return a new view with that users createSetupIntent and then take the payment information. This seems like it creates a lot of room for the user to exit out before they created their subscription which will lead to some confusion if they signed up for a subscription thats paid for or not. Even this site takes the CC when you register, I would assume he uses Cashier.

0 likes
4 replies
kensmithzzz's avatar

If I understand you correctly, you want to create the Laravel user and a subscription at the same time.

You should be able to do that with just one page if you want. Just call createSetupIntent() and include it in a view that asks for the user information and the payment information all at once.

The relevant docs are here: https://laravel.com/docs/6.x/billing#storing-payment-methods

1 like
packy's avatar
packy
OP
Best Answer
Level 7

Thanks @kensmithzzz . I found a good article explaining the new setup finally (https://www.seismicpixels.com/creating-a-laravel-saas-framework-part-6/). Basically when I show my registration view I now create a new User and pass the intent there. I kept thinking the user had to be saved already, not just created. So if anyone else wants to do it:

Show the view

Registration Controller

public function show()
    {
        $user = new User;

        return view('auth.register', [
            'intent' => $user->createSetupIntent()
        ]);
    }

Pass the intent to my Vue component

<register-form stripe-key="{{ env('STRIPE_KEY') }}" stripe-intent="{{ $intent->client_secret }}">
            </register-form>

Add stripe elements to a div:

 mounted() {
        // Create a Stripe client.
        this.stripe = Stripe(this.stripeKey);

        // Create an instance of Elements.
        var elements = this.stripe.elements();

        var style = {
            base: {
                color: "#32325d",
                fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
                fontSmoothing: "antialiased",
                fontSize: "16px",
                "::placeholder": {
                    color: "#aab7c4"
                }
            },
            invalid: {
                color: "#fa755a",
                iconColor: "#fa755a"
            }
        };

        // Create an instance of the card Element.
        this.card = elements.create("card", { style: style });

        // Add an instance of the card Element into the `card-element` <div>.
        this.card.mount("#card-element");
    },

process the data

pay() {
            this.isLoading = true;

            if (this.form.payment_method == "cc") {
                this.setupCard();
            } else {
                this.register();
            }
        },

        setupCard() {
            this.stripe
                .handleCardSetup(this.stripeIntent, this.card, {
                    payment_method_data: {
                        billing_details: { name: this.form.name }
                    }
                })
                .then(data => {
                    this.form.stripePayment = data.setupIntent.payment_method;
                    if (this.form.stripePayment) this.register();
                })
                .catch(error => {
                    this.isLoading = false;
                    console.log(error);
                });
        },

        register(setupIntent) {
            this.form
                .post("/register")
                .then(data => {
                    this.isLoading = false;
                    if (data.type == "success") {
                        this.$swal({
                            type: "success",
                            title: "Great...",
                            text: data.message,
                            toast: true,
                            position: "top-end",
                            showConfirmButton: false,
                            timer: 2000
                        });

                        setTimeout(() => {
                            window.location.replace(data.url);
                        }, 2000);
                    }
                })
                .catch(error => {
                    this.isLoading = false;
                });
        }

save the user

Register Controller

protected function create(request $request)
    {
        $request->validate([
            'name' => 'required',
            'email' => 'required|unique:users',
            'username' => 'required|alpha_dash|unique:users',
            'phone' => 'required',
            'city' => 'required',
            'state' => 'required',
            'password' => 'required|confirmed',
            'agree' => 'required',
        ]);

        $user = User::create([
            'username' => $request['username'],
            'name' => $request['name'],
            'email' => $request['email'],
            'phone' => $request['phone'],
            'city' => $request['city'],
            'state' => $request['state'],
            'password' => Hash::make($request['password']),
        ]);

        if ($request['subscription_type'] == 'premier' && $request['payment_method'] == 'cc') {

            $user->newSubscription('default',  env('STRIPE_PLAN_ID'))->create($request->input('stripePayment'), [
                'email' => $request['email'],
            ]);
        }



        if ($user) {
            $user->assignRole('subscriber');



            Auth::login($user);

            return response()->json([
                'type' => 'success',
                'message' => 'you are all set.',
                'url' => '/dashboard'
            ]);
        }
kensmithzzz's avatar

Actually I had forgotten that createSetupIntent was a method of User! Hopefully your idea works, but I too would have assumed the user needed to be saved before doing that.

packy's avatar
Level 7

@kensmithzzz tested and confirmed to work. I wish the docs better showed how to do it on user registration and not to just a already registered user, makes it confusing. Any pull to updated the docs @jeffreyway

Please or to participate in this conversation.