#bk_paymentelement-googlepay

1 messages ยท Page 1 of 1 (latest)

topaz graniteBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1263179597625954395

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

jolly sparrowBOT
#

Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.

  • bk_code, 20 hours ago, 36 messages
lavish gazelle
#

bk_paymentelement-googlepay

#

Hello! I'm happy to try and help though I would like to focus on the exact error you get and which part of your code is causing that error

pure herald
#

Going to outline the steps for our implementation:

  • we setup the payment element + our additional form fields (name, address, payment cadence = subscription or one time payment)
  • on submit we 1) do the elements.submit call, 2) create a confirmation token 3) hits our API endpoint 4) then tries to use either the subscription or payment client secret to submit the payment
  • our api endpoint creates a customer, then if it is a one time payment, it sets up a paymentIntent and if it is a Subscription, it will create the subscription before returning the client secret to the frontend
#

Exact error I get is: "Failed to execute 'postMessage' on 'Window': Delegation is not allowed without transient user activation."

#

And this only happens when trying to use Google Pay

#

And it happens when we try to confirm the payment:

        elements,
        clientSecret,
        confirmParams: {
              return_url: 'https://seedcompanydev.wpengine.com/thank-you',
        },
      });```
lavish gazelle
#

Perfect. So GooglePay and ApplePay are strict as to when you can trigger the UI to appear. And that error usually happens when you try to show the UI/modal without an explicit click from the customer. Often it's because you call confirmPayment() in a callback/promise after a call to your server for example

pure herald
#

right. I think I read something like that, but I am not sure how you can use the payment element and also submit your business logic to your API and still utilize google/apple pay

lavish gazelle
#

There are many different ways to do this. It depends what you call "submit your business logic" but really that's the issue. You need to ensure that the way you build your flow calls confirmPayment() or createPaymentMethod() as a result of a customer action

pure herald
#

So does that include being as a result of other things happening? Right now, I have 1 submit event that does several things in succession:

    e.preventDefault();
    const {error: submitError} = await elements.submit();
    if (submitError) {
        console.error(submitError);
        return;
    }

    // Create the ConfirmationToken using the details collected by the Payment Element
    // and additional shipping information
    const {error, confirmationToken} = await stripe.createConfirmationToken({
        elements,
        params: {
            return_url: 'https://seedcompanydev.wpengine.com/thank-you'
        }
    });
    if (error) {
        // This point is only reached if there's an immediate error when
        // creating the ConfirmationToken. Show the error to your customer (for example, payment details incomplete)
        console.error(error);
        return;
    }
    const { body: data } = await processStripeFinalCall(confirmationToken.id);
    console.log('intent');
    console.log(data);
    console.log(data.data.donate.intent.clientSecret);
    const clientSecret = data.data.donate.intent.clientSecret;
    const { error: confirmError } = await stripe.confirmPayment({
        elements,
        clientSecret,
        confirmParams: {
              return_url: 'https://seedcompanydev.wpengine.com/thank-you',
        },
      });
}```
#

That processStripeFinalCall is where we hit our API which setups or gets the Stripe Customer, creates the payment intent or subscription and returns the client secret

lavish gazelle
#

Wait you're using createConfirmationToken()? So that is the function throwing the error or something else? I'm confused now

pure herald
#

I believe it is the confirmPayment because all my logs show before the error

lavish gazelle
#

yeah that doesn't make sense to me that it would be since createConfirmationToken() is what controls showing the Google Pay UI.
Like you agree that when you call that method you get the GooglePay UI right?

pure herald
#

Yea. On submit is when it pops up and you can choose your payment method and such.

#

And then it errors after you try to submit the payment

lavish gazelle
#

Can you share your code where you create the PaymentIntent?

pure herald
pure herald
lavish gazelle
#

sure can you share the exact code please?

pure herald
#
    customerId,
    confirmationToken,
    paymentMethodId,
    savePaymentMethod,
    amount,
    metadata,
    statementDescriptor,
  }: {
    customerId: string;
    paymentMethodId?: string;
    savePaymentMethod?: boolean;
  } & CamelCasedProperties<
    Pick<
      Stripe.PaymentIntentCreateParams,
      'confirmation_token' | 'amount' | 'metadata' | 'statement_descriptor'
    >
  >) {
    // Stripe makes 75 = $0.75 so multiplying the whole number by 100 gets us the whole $ amount
    const stripeAmount = amount * 100;
    return await this.stripe.paymentIntents.create({
      customer: customerId,
      payment_method: paymentMethodId,
      confirm: !confirmationToken,
      setup_future_usage: savePaymentMethod ? 'off_session' : undefined,
      // this setting allows for the payment methods in the dashboard to be used by default
      automatic_payment_methods: { enabled: true, allow_redirects: 'always' },
      amount: stripeAmount,
      currency: 'usd',
      metadata,
      statement_descriptor: statementDescriptor,
    });
  }
lavish gazelle
#

payment_method: paymentMethodId, what is this? That doesn't exist at all in this specific flow right?
You also have confirm: !confirmationToken, which seems... abnormal to me so I don't get it. This smells like the result of many different rewrites

pure herald
#

paymentMethodId essentially only gets used if there is a saved payment (which, my team lead wanted to keep in the code even though we don't use saved payments anywhere)

lavish gazelle
#

it would help to temporarily start fresh while you're debugging things so that you're not bogged down by months of rewrites/other features. It's hard to debug the issue with so much unrelated code

pure herald
#

and I think there is some logic where if there is a confirmationToken passed, we confirm so it auto confirms.

lavish gazelle
#

I'm still really confused why confirmPayment() would show the GooglePay UI again it doesn't make sense to me

pure herald
#

I don't think it shows it again, but I see all the console logs that happen before that point and then an error

lavish gazelle
#

I mean it doens't show because of the error

#

it would otherwise

pure herald
#

I actually don't have a good handle on where the error actually is.

lavish gazelle
#

try this: comment out the code to your server and hardcode a client_secret

#

๐Ÿ˜…

pure herald
lavish gazelle
#

yeah that picture doesn't really tell me anything

pure herald
#

yea. That's all I have to go off of currently.

lavish gazelle
#

I mean you can add clear logs before and after every part of the code to pinpoint which exact method throws that error

#

and try what I said above: comment out the code to your server and hardcode a client_secret

pure herald
#

Like just any string or is there somewhere I can grab a client secret outside of this flow?

#

Oh I got one from the UI. Nevermind. Let me try it

#

ok. EVen with the client secret hard codes and my server call out of there I still get the same error

lavish gazelle
#

Okay can you share an exact URL with this and exact logs before and after every call so I can have a look?

pure herald
#
    e.preventDefault();
    const {error: submitError} = await elements.submit();
    if (submitError) {
        console.error(submitError);
        return;
    }

    // Create the ConfirmationToken using the details collected by the Payment Element
    // and additional shipping information
    const {error, confirmationToken} = await stripe.createConfirmationToken({
        elements,
        params: {
            return_url: 'https://seedcompanydev.wpengine.com/thank-you'
        }
    });
    if (error) {
        // This point is only reached if there's an immediate error when
        // creating the ConfirmationToken. Show the error to your customer (for example, payment details incomplete)
        console.error(error);
        return;
    }
//     const { body: data } = await processStripeFinalCall(confirmationToken.id);
//     console.log('intent');
//     console.log(data);
//     console.log(data.data.donate.intent.clientSecret);
    const clientSecret = 'pi_3PdaeODXchwDHdiC1d0jzCFK_secret_KgXG4GrQv7oX2FCAD8Z7TyvJT';
    const { error: confirmError } = await stripe.confirmPayment({
        elements,
        clientSecret,
        confirmParams: {
              return_url: 'https://seedcompanydev.wpengine.com/thank-you',
        },
      });
}```
#

That's what runs on submit right now after removing the API call and setting up the client secret as static

lavish gazelle
#

ah yeah I'm dumb I can't test it since it's GooglePay and that will give you my real address

#

Unfortunately you didn't seem to add any of the logs I mentioned. Can you please cleanly add the logs before and after every call?

pure herald
#
    e.preventDefault();
    console.log('before element submit')
    const {error: submitError} = await elements.submit();
    if (submitError) {
        console.error(submitError);
        return;
    }
console.log('after element submit')
    // Create the ConfirmationToken using the details collected by the Payment Element
    // and additional shipping information
    console.log('before confirmation token creation')
    const {error, confirmationToken} = await stripe.createConfirmationToken({
        elements,
        params: {
            return_url: 'https://seedcompanydev.wpengine.com/thank-you'
        }
    });
    if (error) {
        // This point is only reached if there's an immediate error when
        // creating the ConfirmationToken. Show the error to your customer (for example, payment details incomplete)
        console.error(error);
        return;
    }
        console.log('after confirmation token creation')

//     const { body: data } = await processStripeFinalCall(confirmationToken.id);
//     console.log('intent');
//     console.log(data);
//     console.log(data.data.donate.intent.clientSecret);
    const clientSecret = 'pi_3PdaeODXchwDHdiC1d0jzCFK_secret_KgXG4GrQv7oX2FCAD8Z7TyvJT';
        console.log('before confirm payment')

    const { error: confirmError } = await stripe.confirmPayment({
        elements,
        clientSecret,
        confirmParams: {
              return_url: 'https://seedcompanydev.wpengine.com/thank-you',
        },
      });
            console.log('after confirm payment')

}```
lavish gazelle
#

okay so what happened between the ConfirmationToken related logs. Did you see GooglePay?

pure herald
#

Yes. I have seen and submitted google pay from the beginning.

#

then when I hit pay it errors

#

And even with my API call in the code, it still has shown this part.

lavish gazelle
#

(sorry Discord is busy so catching up on other threads)

#

Yes. I have seen and submitted google pay from the beginning.
what does that sentence mean? I'm sorry I'm not sitting next to you watching you. I need to understand exactly which bit of your code shows that GooglePay UI

pure herald
#

The 2nd screenshot above has been showing whether or not I have had my API call or not and then once I hit "pay" it will error

lavish gazelle
#

I don't get what that sentence means ๐Ÿ˜…

#

you're saying elements.submit() is what shows the GooglePay UI?

pure herald
#

No. I have the one submit functions that I have shared that runs on submit. If Google Pay is the selected option, then it will show the Google Pay UI where I can hit "pay"

lavish gazelle
#

๐Ÿ˜… I'm asking what shows that UI. Can you please tell me which exact line of your current code shows the GooglePay modal?

pure herald
#

I have no idea which part actually spins up the Google Pay piece

lavish gazelle
#

Can you try and debug please? That would really help as I'm worried we're talking a bit past each other right now

#

Comment all the code but the elements.submit() and its logs and confirm you get the modal to appear

pure herald
#

Yea. Looks like it is the elements.submit that makes the google pay ui pop up

lavish gazelle
#

perfect, so now uncommon the ConfirmationToken part, but keep the rest commented. Can you confirm you properly get the ConfirmationToken created?

pure herald
#

Yup. Seems like it all worked just fine

lavish gazelle
#

Okay, so it really looks like the confirmPayment() part is the issue here I just don't get why. I'm trying to reproduce but will take me some time as I'm helping 5 other people in parallel

#

Okay I think I got it. My code is completely different from yours. And if I pick your approach I get a similar error ๐Ÿคฆโ€โ™€๏ธ

#

What I do is

  1. Confirm server-side by passing the ConfirmationToken id
  2. Client-side, if anything extra is needed such as 3DS (won't happen for GooglePay I think) I use stripe.handleNextAction() instead
#

Now let me try to tweak your code to make it work instead

pure herald
#

I think this will require me to update my API code a bit. I had it architected this way at one point and my team lead didn't like us having to check for next actions on the frontend vs having the server submit whatever it could and return the next actions

lavish gazelle
#

Okay I got it

#

it's so obvious now but I realize I had never integrated that way so I didn't notice your "bug"

#

when you call confirmPayment() with elements in your code, we don't "remember" that a ConfirmationToken was created, so to us it looks like you want to just confirm again

pure herald
#

Yea. I think he and I made an assumption that if we did it this way, the next actions would just handle themselves.

lavish gazelle
#

What you are supposed to do is explicitly give us the ConfirmationToken id and not pass elements

#
  clientSecret: serverResult.client_secret,
  confirmParams: {
    return_url: 'https://google.com',
    confirmation_token: confirmationToken.id,
  },
  redirect: 'if_required',
});```
#

this is what my code looks like. So for you you need to do this const { error: confirmError } = await stripe.confirmPayment({ clientSecret, confirmParams: { return_url: 'https://seedcompanydev.wpengine.com/thank-you', confirmation_token: confirmationToken.id, }, });

topaz graniteBOT
pure herald
#

So wait... I will or will not need to return the next_actions piece from my API call?

gusty wind
#

๐Ÿ‘‹ stepping in as koopajah needs to step away

#

You are attempting to confirm server-side with a Confirmation Token and then figuring out how to handle 3DS if required, correct?

lavish gazelle
#

Sorry I made this quite messy so it's not that at all no

pure herald
#

Our desired flow was that we would return an unconfirmed payment intent to the client and confirm on the client.

#

That's how we built the entire solution anyway.

lavish gazelle
#

Client-side they create a ConfirmationToken. Then they go to their server and do stuff. After that they create a PaymentIntent and they do not confirm it at all.
Then they come back client-side and they were calling confirmPayment() incorrectly. They were passing the elements when they were supposed to pass the ConfirmationToken id.
The only fix needed is what I showed above in the code example

pure herald
#

Cool. let me update and check that out

#

YAY! That got me taken care of. Thanks @lavish gazelle !!!

lavish gazelle
#

I'm so sorry I should have caught it at the beginning. all my examples confirm server-side and I kept going to the wrong doc that did this instead of finding that last one, that's my bad