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

wxcaptain's avatar

Cashier - handleCardSetup - invalid API key

I am working with Cashier, and having trouble with the Stripe integration.

The only thing that I am doing different, than in the documentation, is getting the Payment Intent client_secret from an Ajax request, since the form is loaded in a vue component.

I get the stripe sdk and card element to load properly, and once I click the button to handleCardSetup, I get the error: "Invalid API Key provided: stripe-p*****-key"

In my stripe dashboard, I can see that there are successful requests coming in. I suppose these are for handling the setup of the card element, but I don't know why I'm getting the API key error when trying to handle the card setup. I've added the test key and secret to the .env file like this: STRIPE_KEY=pk_test_*** STRIPE_SECRET=sk_test_***

Any suggestions on things to try here?

0 likes
3 replies
martinbean's avatar

@weathercaptain Well, the error’s pretty self-explanatory. You’re passing an invalid API key.

When you create the Stripe element, you should use the publishable key (the one beginning with pk_test_). But you should pass the client secret of the setup intent when calling handleCardSetup on the element.

Also, handleCardSetup as a method is deprecated: https://stripe.com/docs/js/deprecated/handle_card_setup

wxcaptain's avatar

Thanks for the response @martinbean. The error message is indeed self explanatory, but I believe I'm using the test API keys appropriately in the code. And, when receiving the paymentIntent, i'm seeing a successful request on the API dashboard. It is only the handleCardSetup method that errors out, when passing the clientSecret.

Here's the relevant part of the Vue component (I took out javascript methods that weren't relevant). You'll see on mount, I retrieve the clientSecret from the server, which is passed to the handleCardSetup(). Any other suggestions are appreciated:

<template>
    <aside class="header-subscription">
        <div v-show="showAddPayment">
            <label>Name
                <input id="card-holder-name" type="text" v-model="cardHolderName">
            </label>

            <!-- Stripe Elements Placeholder -->
            <label>Credit Card
                <div id="card-element"></div>
            </label>

            <button id="card-button" class="button" @click="handleCardSetup">
                {{ addPaymentText }}
            </button>
        </div>
    </aside>
</template>

<script>
    let stripe;
    export default {
        name: "main-subscription.vue",
        props: ['name','subscription'],
        data: function() {
            return {
                clientSecret: '',
                showAddPayment: false,
                cardElement:false,
                cardHolderName:''
            }
        },
        methods: {
            handleCardSetup: async function() {
                const { setupIntent, error } = await stripe.handleCardSetup(
                    this.clientSecret, this.cardElement, {
                        payment_method_data: {
                            billing_details: { name: this.cardHolderName }
                        }
                    }
                );

                if (error) {
                    console.log(error);
                } else {
                    // The card has been verified successfully...
                    this.updatePaymentMethod(setupIntent.paymentMethod);
                }
            },
            updatePaymentMethod(paymentMethod) {
                console.log('updating payment method');
            }   
        },
        mounted: function() {

            let self = this;
            this.showAddPayment = this.subscription.type === 'Basic';

            const loadStripeFields = function() {
                stripe = Stripe('stripe-public-key');

                const elements = stripe.elements();
                self.cardElement = elements.create('card');
                self.cardElement.mount('#card-element');
            };

            if (! document.getElementById('stripe-sdk')) {
                console.log('load stripe');
                const stripeScript = document.createElement('script');
                stripeScript.setAttribute('id', 'stripe-sdk');
                stripeScript.setAttribute('src', 'https://js.stripe.com/v3/');
                stripeScript.setAttribute('async', 'false');
                stripeScript.onreadystatechange = loadStripeFields;
                stripeScript.onload = loadStripeFields;
                document.head.appendChild(stripeScript);
            } else
                loadStripeFields();

            self = this;
            //get client secret from server
            axios.get('/subscription/stripe-intent')
                .then(function (response) {
                    self.clientSecret = response.data.client_secret;
                })
                .catch(function (error) {console.log(error);})
        }
    }
</script>
wxcaptain's avatar
wxcaptain
OP
Best Answer
Level 1

Well, sometimes, I'm just not on my game. When loading the stripe SDK, I didn't actually put in the pub key, I left it like this: stripe = Stripe('stripe-public-key');

So, silly... Posting the result here, in case someone else makes a silly mistake like this when following the Laravel documentation.

1 like

Please or to participate in this conversation.