#PERF - Confirm Pamyent Intent

1 messages · Page 1 of 1 (latest)

honest tartan
#

HI 👋 I'll take a look

storm arrow
#

This confirm call is coming from the react-native sdk as well

honest tartan
#

Okay but I'm seeing that you are passing an empty string for setup_future_usage

#

Why is that?

#

But I agree the error message is confusing, since you are using the Publishable key

storm arrow
#

I payload for the request was automatically created via the stripe react-native SDK

const res = await confirmPaymentSheetPayment();
if (!res.error) {
  // We good
} else {
  // Error
}
honest tartan
#

Hmmmm.... Okay let me take a look and see if there are any open issues with the RN SDK

#

I'm not seeing anything on the GH Issues page so I'm reaching out to the team that manages the SDK

storm arrow
#

alright, for context. It has worked in the past. So it might be a setup issue. (just thinking out loud)

honest tartan
#

The exact code, no changes?

storm arrow
#

wym?

honest tartan
#

You said "it has worked in the past". I"m asking, during those successful calls, was the Payment Intent created the same? Was the RN code the same?

storm arrow
#

not exactly the same, but the same gist. Code was moved around during development. Not really sure the exact tracing. We were just able to created, confirm and capture a payment intent previously

#

Little more context, when saving the cards via the setup intent flow. I am getting the original error.

However when creating and saving a card via the payment intent sheet I am able to successfully submit and confirm a payment.

#

pi_3LQwDVFdV4bT3T5F0TIVULDN - worked
pi_3LQwCeFdV4bT3T5F0jbYw1xK - failed

#

Using the same card that was created via the sheet still fails. pi_3LQwGKFdV4bT3T5F1ZqOTXid for the same reason

honest tartan
#

"The sheet"? There is only the PaymentSheet regardless of what type of intent you are using.

#

But I'm looking into these

storm arrow
#

yea sorry i know. It is the same call just different keys

#
const res = await initPaymentSheet({
    merchantDisplayName: MERCHANT_DISPLAY_NAME,
    customFlow: true,
    applePay: {
        merchantCountryCode: MERCHANT_COUNTRY_CODE,
        paymentSummaryItems: [],
    },
    googlePay: {
        merchantCountryCode: MERCHANT_COUNTRY_CODE,
        testEnv: config.ENV !== 'production',
        currencyCode: MERCHANT_CURRENCY_CODE,
    },
    returnURL: MERCHANT_RETURN_URL,
    customerId: stripeCustomerId,
    paymentIntentClientSecret: paymentIntentClientSecret,
    customerEphemeralKeySecret: ephemeralKey,
});
#
"@stripe/stripe-react-native": "^0.15.0",
honest tartan
#

When you say different keys, are you talking about API keys, ephemeral keys, ?

storm arrow
#
export declare type ClientSecretParams = {
    paymentIntentClientSecret: string;
    setupIntentClientSecret?: undefined;
} | {
    setupIntentClientSecret: string;
    paymentIntentClientSecret?: undefined;
};

these two types

#

when using either a payment intent or setup intent

honest tartan
#

Okay, client secrets, not keys. And yes that is how you let the PaymentSheet know what record to update.

storm arrow
#

i believe the issue comes from the original statement you asked the beginning though. Why is setup_future_usage empty.

{
  "payment_method": "pm_1LQwCYFdV4bT3T5FSoPFJfWN",
  "return_url": "thentwrktest://noop",
  "payment_method_options": {
    "card": {
      "setup_future_usage": ""
    }
  },
  "use_stripe_sdk": "true",
  "client_secret": "************************************************************",
  "expand": {
    "0": "payment_method"
  }
}
honest tartan
#

Right. Which you pointed out was not explicitly passed from your RN code.

storm arrow
#

that is correct

honest tartan
#

Because the successful /confirm calls included setup_future_usage: "off_session"

#

So I'n trying to understand if the Payment Sheet might have been initialized in a different way that resulted in that weird payload to the /confirm API call

#

If that makes sense

storm arrow
#

yes it does. We are using golang in our servers to create the payment intent

params := &stripev72.PaymentIntentParams{ 
    Params: stripev72.Params{ 
        Context:        ctx,
        IdempotencyKey: stripev72.String(orderID),
    },
    CaptureMethod: stripev72.String(string(stripev72.PaymentIntentCaptureMethodManual)),
    Amount:        stripev72.Int64(amount),
    Currency:      stripev72.String(string(stripev72.CurrencyUSD)),
    Customer:      stripev72.String(stripeCustomerID),
    Description:   stripev72.String(description),
    PaymentMethodTypes: []*string{
        stripev72.String(string(stripev72.PaymentMethodTypeCard)),
    },
    PaymentMethodOptions: &stripev72.PaymentIntentPaymentMethodOptionsParams{ 
        Card: &stripev72.PaymentIntentPaymentMethodOptionsCardParams{ 
            SetupFutureUsage: stripev72.String("off_session"), 
        },
    },
    StatementDescriptor: stripev72.String(descriptionShort),
    TransferGroup:       stripev72.String(orderID),
}

if klarnaMinimumAmountInCents <= amount && amount <= klarnaMaximumAmountInCents {
    params.PaymentMethodTypes = append(params.PaymentMethodTypes, stripev72.String(string(stripev72.PaymentMethodTypeKlarna)))
}

which is then fed into

paymentIntent, err := s.stripePaymentIntents.New(params)
honest tartan
#

Okay so you are always creating a Payment Method that can be used again in the future for off-session payments.

storm arrow
#

yea all the payment methods attached to the customer i am using are all saved as off_session

honest tartan
#

That makes sense.

storm arrow
#

strange how this one doesn't have the label though

#

the last line

#

since the second was created via setup intent not during the payment intent sheet

honest tartan
storm arrow
#

yea the one that succeed was a new card

#

created during payment intent

honest tartan
#

So it fails when you use a saved payment method only?

storm arrow
#

yea it appears that way

#

is the addition of

"payment_method_options": {
    "card": {
      "setup_future_usage": "off_session"
    }
  },

needed for existing?

#

I would think that should only be added if it was a new card

honest tartan
#

That is what I would think too. Essentially I would expect the PaymentSheet to not pass and payment_method_options at all when using a saved card.

storm arrow
#

yea

#

we did update from version 0.13.0 to 0.15.0 at some point

#

in the package

honest tartan
#

At some point but both the successful and failed requests occurred on the same day

storm arrow
#

oh yea

#

when i said before, that it succeeded before. I think that was on version 0.13.0

#

i think

honest tartan
storm arrow
#

default with custom style sheet

#

aka changing colors and what not

honest tartan
#

Okay I've reached out to a colleague to dig further into this. Thanks for the confirmation

storm arrow
#

thank you @honest tartan I am going to reinstall package version 0.13.0 to see if it succeeds in that version like it was before

honest tartan
#

I would clone the project first, or create a separate git branch, so you can apply any fix to v0.15.0 that we might find.

storm arrow
#

all these changes are in a experimental branch anyways 😉

storm arrow
#

The error still happens during version 0.13.0

somber spire
#

Hello! I'm taking over and catching up...

storm arrow
#

🆒

somber spire
#

The mobile SDKs want to have control over setup_future_usage, but they can't override it if you've set it explicitly server-side with your secret key, which leads to the error you're seeing.

storm arrow
#

so we should omit

 PaymentMethodOptions: &stripev72.PaymentIntentPaymentMethodOptionsParams{ 
        Card: &stripev72.PaymentIntentPaymentMethodOptionsCardParams{ 
            SetupFutureUsage: stripev72.String("off_session"), 
        },
    },

from our server code?

somber spire
#

That would prevent this issue from happening, yes.

#

This might be a bug in the mobile SDKs, we're investigating further now, but in the meantime omitting setup_future_usage when creating the Payment Intent is a viable workaround.

#

Out of curiosity, why are you setting that specifically for cards instead of at the top-level of the Payment Intent?

storm arrow
#

I believe the original reason was because klarna was failing when that was set but i dont remember to be honest

somber spire
#

Ah, interesting.

storm arrow
#

but since the default is off_session can this whole property be omitted?

somber spire
#

You should be able to omit it server-side and let the mobile SDK set it to the correct value, especially if you're able to set it at the top-level of the Payment Intent server-side.

storm arrow
#

wouldn't it default to that since its the only value?

somber spire
#

No, what I'm saying is, when you create the Payment Intent, set setup_future_usage to off_session at the top-level of the Payment Intent: https://stripe.com/docs/api/payment_intents/create#create_payment_intent-off_session

Then, to work around the issue of Klarna not liking that setting (if that's an issue) you can override the top-level setup_future_usage to none only for Klarna by setting it here: https://stripe.com/docs/api/payment_intents/create#create_payment_intent-payment_method_options-klarna-setup_future_usage

#

It boils down to telling the API, "For this Payment Intent I want to set up the payment method for future off-session use, unless it's Klarna."

storm arrow
#

yea gotcha

#

sweet so omitting it from the params completely makes it all work 😉

#

with klarna as well

#
params := &stripev72.PaymentIntentParams{ 
        Params: stripev72.Params{ 
            Context:        ctx,
            IdempotencyKey: stripev72.String(orderID),
        },
        CaptureMethod: stripev72.String(string(stripev72.PaymentIntentCaptureMethodManual)),
        Amount:        stripev72.Int64(amount),
        Currency:      stripev72.String(string(stripev72.CurrencyUSD)),
        Customer:      stripev72.String(stripeCustomerID),
        Description:   stripev72.String(description),
        PaymentMethodTypes: []*string{
            stripev72.String(string(stripev72.PaymentMethodTypeCard)),
        },
        StatementDescriptor: stripev72.String(descriptionShort),
        TransferGroup:       stripev72.String(orderID),
    }
somber spire
#

You should test to make sure cards and whatever else you want to be set up for future use are indeed set up for future use the way you want with this configuration.

storm arrow
#

yea, we just wanted all cards saved as off_session so i think we are ok but will do

somber spire
#

If that's the case you should do what I advised above, set setup_future_usage at the top level and disable it for Klarna specifically.

storm arrow
#

ok

#
params := &stripev72.PaymentIntentParams{
        Params: stripev72.Params{
            Context:        ctx,
            IdempotencyKey: stripev72.String(orderID),
        },
        CaptureMethod: stripev72.String(string(stripev72.PaymentIntentCaptureMethodManual)),
        Amount:        stripev72.Int64(amount),
        Currency:      stripev72.String(string(stripev72.CurrencyUSD)),
        Customer:      stripev72.String(stripeCustomerID),
        Description:   stripev72.String(description),
        PaymentMethodTypes: []*string{
            stripev72.String(string(stripev72.PaymentMethodTypeCard)),
        },
        PaymentMethodOptions: &stripev72.PaymentIntentPaymentMethodOptionsParams{
            Klarna: &stripev72.PaymentIntentPaymentMethodOptionsKlarnaParams{
                SetupFutureUsage: stripev72.String(string(stripev72.PaymentIntentPaymentMethodOptionsKlarnaSetupFutureUsageNone)),
            },
        },
        StatementDescriptor: stripev72.String(descriptionShort),
        TransferGroup:       stripev72.String(orderID),
        SetupFutureUsage:    stripev72.String(string(stripev72.PaymentIntentSetupFutureUsageOffSession)),
    }
somber spire
#

Is that approach working as expected?

storm arrow
#

yes

#

thank you so much!

#

and the long winded thread

somber spire
#

Happy to help!

storm arrow
#

❤️

#

Random question, but are the people helping in this discord just stripe employees that just chill in here? lol

#

or do you guys rotate using the same accounts?

somber spire
#

The people with the Stripe Staff role are people who work at Stripe. Some of us, like me, are engineers who staff this channel and help developers with questions like yours. We don't share accounts; I'm always Rubeus, for example.

storm arrow
#

ah kinda cool and random lol

somber spire
#

🙂

storm arrow
#

Cheers @somber spire !

lethal isleBOT
#

This thread has been archived. If you need help with anything else please ask in #dev-help or contact Stripe Support: https://support.stripe.com/contact

somber spire
#

Hi @storm arrow! Are you around by chance? I have an update about this issue.

#

First, I wanted to let you know that we've determined this is a bug in our mobile SDKs and we're going to work on getting it fixed. Can't give you a timeframe for a fix, but wanted to let you know we're working on it.