#neil_error

1 messages · Page 1 of 1 (latest)

ionic owlBOT
#

👋 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/1332450018053066822

📝 Have more to share? Add more details, code, screenshots, videos, etc. below.

placid heath
#

does elements.submit() somehow override the paymentMethodTypes i've set based on the wallet and for google_pay its changing the paymentMethodTypes to be card, us_bank_account?

craggy egret
#

elements.submit won't override that. Can you show me your code for creating your elements instance on your client?

#

And do you have the ID of an intent that you got this error with?

placid heath
#

yup one minute

#

wait sorry, no intent ID, because this the create on server flow. The create intent call is what is failing

#

I can give you the confirmation token generated on the FE: ctoken_1QktJWFdviIHOKAn7DtSXUvM

craggy egret
#

Ah gotcha, can you provide the code for creating the intent as well? Looking through your logs but that may help me spot this quicker. Basically payment method types disagrees between what you sent on Stripe elements and what the intent is calculating for its payment method types

placid heath
#

right right, Im just trying to figure out why, because from our code im pretyt sure its now on our end

#
const elements = useElements();
  useEffect(() => {
    // Note: Stripe Elements throws a fit if amount and currency are not valid.
    // It is important that we check for these conditions before updating it.
    if (
      elements &&
      currency &&
      currency.length > 0 &&
      amount &&
      amount > 0 &&
      styles
    ) {
      const paymentMethodTypes = [];
      if (paymentOptions.allowPaymentViaACH) {
        paymentMethodTypes.push('us_bank_account');
      }
      if (paymentOptions.allowPaymentViaCC) {
        paymentMethodTypes.push('card');
      }

      elements.update({
        currency: currency.toLowerCase(),
        paymentMethodTypes,
        amount,
        ...styles,
        customerSessionClientSecret: customerSession,
        setupFutureUsage: showSubscribeAction ? 'off_session' : null,
      });

      setIsOptionsUpdated(true);
    }
  }, [
    elements,
    styles,
    paymentOptions,
    showSubscribeAction,
    invoiceId,
    currency,
    amount,
    customerSession,
  ]);
#

this is what we do on the client ^

#
params.OffSession = stripe.Bool(false)
            params.ConfirmationToken = stripe.String(input.ConfirmationToken.ID)

            params.PaymentMethodTypes = input.Invoice.GetAllowedStripePaymentMethodTypes()
            params.AutomaticPaymentMethods = &stripe.PaymentIntentAutomaticPaymentMethodsParams{
                Enabled: stripe.Bool(false),
            }

            if input.Invoice.IsAutoChargeSubscription() {
                params.SetupFutureUsage = stripe.String(string(stripe.PaymentIntentSetupFutureUsageOffSession))
            }

            if input.ConfirmationToken.PaymentMethodPreview.Type == stripe.ConfirmationTokenPaymentMethodPreviewTypeUSBankAccount {
                // us_bank_account_ach_payments capability is required to enable ACH debit capabilities
                // https://stripe.com/docs/payments/ach-debit#request-ach-debit-capabilities-for-your-connected-accounts
                _, err := l.StripeService.GetCapability(input.DestinationAccount.ID, stripe_cli.AchPaymentsCapability)
                if err != nil {
                    return output, err
                }
            }

            if input.ConfirmationToken.PaymentMethodPreview.Type == stripe.ConfirmationTokenPaymentMethodPreviewTypeCard {
                params.OnBehalfOf = stripe.String(input.DestinationAccount.ID)
                params.PaymentMethodTypes = []*string{stripe.String(string(stripe.PaymentMethodTypeCard))}
            }
            paymentIntent, err := l.StripeService.CreatePaymentIntent(params)
#

^ backend

#

just looking at the stripe dashboard im certain this code path is running

if input.ConfirmationToken.PaymentMethodPreview.Type == stripe.ConfirmationTokenPaymentMethodPreviewTypeCard {
                params.OnBehalfOf = stripe.String(input.DestinationAccount.ID)
                params.PaymentMethodTypes = []*string{stripe.String(string(stripe.PaymentMethodTypeCard))}
            }
#

and on the front-end you can see we are also setting the paymentMethodType on elements to card

#

^ im also confident about that because we know its working for apple_pay

craggy egret
#

Gotcha yeah so overall it looks like paymentOptions.allowPaymentViaACH is triggering and adding us_bank_account on the client side but then you are passing payment_method_types on the backend but are only passing 'card' there

placid heath
#

no no, when the pay action is clicked we pdate the element before confirming. Sorry I think that code snippet got mixed in my initial post in the "Repro steps"

const handleSubmit: MouseEventHandler<HTMLButtonElement> = async (event) => {
    event.preventDefault();

    if (!stripe || !elements) return;

    setIsPaying(true);

    if (
      selectedSource === 'card' ||
      selectedSource === 'apple_pay' ||
      selectedSource === 'google_pay'
    ) {
      elements.update({
        onBehalfOf,
        paymentMethodTypes: ['card'],
      });
    }

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

    const { error, confirmationToken } = await stripe.createConfirmationToken({
      elements,
    });

    if (error) {
      handleError(error);
      return;
    }

    handlePayInvoiceClicked(confirmationToken);
  };
#

The only thing between the elements.update and createConfirmationToken code is await elements.submit();

Hence my suspision that code is doing something with google pay specifically to payment methods

craggy egret
#

And you have double checked that paymentMethodTypes only includes card when you initialize the elements instance on your actual page?

placid heath
#

can you clarify what you mean by "when you initialize the elements instance ". Happy to share the code snippet for that to confirm

#

but im pretty sure we are because apple_pay is working fine.

placid heath
#

oh yea, using the elements component for tht. No payment method types are set there. Use the elements.update to modify them

craggy egret
#

Basically, the issue is that that one way or another payment_method_types is getting set as ['card', 'us_bank_account'] on your frontend which disagrees with it just being ['card'] on the backend. The two places that that can be set are when initializing elements or when updating the elements.update call

placid heath
#
<Elements
      stripe={stripe}
      options={{
        fonts: [
          {
            cssSrc: 'https://fonts.googleapis.com/css?family=Inter',
          },
        ],
        // set the default configuration for stripe elements.
        // this is the only way to setup verification method for ACH payment.
        // but if you provide that you need to also provide other options
        // like mode, amount, currency
        mode: 'payment',
        amount: 100, // must be greater than 0, otherwise stripe will throw an error
        currency: 'usd',
        paymentMethodOptions: {
          us_bank_account: {
            verification_method: 'instant',
          },
        },
      }}
    >
craggy egret
#

Ah, if you don't pass paymentMethodTypes we use the configuration for automatic payment method types that i on your account. So maybe ACH is turned on there

placid heath
#

Yea, Pompey, im totally on the same page with you. But im telling you its not our code that is doing that :p

#

Otherwise apple_pay would also not work

#

for that matter no cards would work

#

i know I've said this before but it has to be elements.submit() that is the only thing before confirmation that could be interrupting the paymentMethodsTypes set already

placid heath
craggy egret
#

I am not seeing other reports of this at the moment and am not seeing any code in elements.submit that tries to manipulate the settings. If you cut out the code that dynamically sets payment method types, does this behavior stop or at least become more consistent?

placid heath
#

oh yea, none of the our cards work without that code. Everytime we get the paymentMethodTypes mismatch error because the backend only has card but hte client sets card and bank

#

I have an idea of what to do to fix things. In the server flow i can use the confirmationToken data to access the ConfirmationTokenPaymentMethodPreviewCard and see if it has ConfirmationTokenPaymentMethodPreviewCardWallet with google pay. If so, i'll update the payment method types on the backend.

But this would me blindly applying a solution

craggy egret
#

Oh, I think elements.update has asynchronous effects, I think I've seen this with other elements updates that users have tried. so you may be running into a race condition here.

#

Okay sorry I was confused by a couple things. Taking a step back, do you know why your page tries to make this update call before making the submit call here? As long as card is present in the payment method types, the card payment can succeed when you create the intent, setting PMT to just card won't have a benefit that I am aware of

placid heath
#

hmmm... maybe but tbh it wouldn't explain why Apple pay works consistently! liek zerro issues

craggy egret
#

It is unlikely for race conditions to have consistent issues like this but I have seen it before

placid heath
#

yes we make the update call because we have to remove on behalf of dynamically based on card or us bank account. We use desitnation charges

craggy egret
#

Ah and the connected account is in a country that doesn't support ACH?

placid heath
#

yea eactly or missing capabilities

craggy egret
placid heath
#

okay that might be something

#

but elements.submit() opens the dialog for wallet right?

#

so shoulnd't that be super slow?

#

meaning that element.update has plenty of time to finish before we get to the confirmation

craggy egret
#

One way or another, we don't reccommend calling update immediately before calling submit. I am not as familiar with the internal implementation details but that is in unsupported/unexpected behavior territory. Though we do need to call this out better in our docs.

placid heath
#

okay got it

craggy egret
#

Of course, and I will raise that with our docs team

placid heath
#

LOL, there is on event with the the React hook?

craggy egret
#

Good question, I am not as familiar with Stripe.js + React, looking into this and will get back to you

placid heath
#

so here's a hack for you

#

I tried calling update again! after the submit

#

and before the confirm

#

and it worked!

#

so yea...

#

definitely there is something sus about update/submit

craggy egret
#

Huh, that is surprising. Unfortunately I am not seeing a hook for the update-end event. I will file something with the team that makes that library, that is definitely something we should have added when we added that event. I'm also not sure if we have an official suggestion of how to make this work consistently without that event. I can create a ticket, ask my colleagues, and get back to you on that if that works for you

placid heath
#

thank you that will work

#

also believe me, I know my solution above is super hacky

#

but atleast it works right :p

ionic owlBOT
#

Hello @placid heath, we have sent you a direct message, please check it at https://discord.com/channels/@me/1326640130097942609

  • 🔗The message has instructions on how to open a direct support case with our Developer Support team, in order to help you more effectively.
craggy egret
#

Sounds good, can you fill out the thing from above and let me know when you've finished? I can pick it up from there