Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERROR An error occurred in PaymentSheet.There is a mismatch between the payment method ID on your Intent: pm_XXX and the payment method passed into the confirmHandler: pm_YYY #4195

Open
Ariandr opened this issue Oct 28, 2024 · 6 comments
Labels
fixed in master Fixed in master, awaiting next update kind:bug triaged Issue has been reviewed by Stripe and is being tracked internally

Comments

@Ariandr
Copy link

Ariandr commented Oct 28, 2024

Summary

We are migrating from Basic Integration to new Payment Sheet, using iOS and backend with payment intents. We use Stripe connect where we save the payment methods on the main platform account and then share these payment methods to make the Direct payments to Connected accounts.

With the Basic Integration (and with the PaymentSheet August version of SDK) it worked perfectly for us, but with the new Payment Sheet releases (after #3972) there is an issue that we cannot confirm it on the iOS side later due to a problem that the initial payment method doesn't match the one inside the payment intent.

https://docs.stripe.com/connect/direct-charges-multiple-accounts

iOS version

iOS 18, but not related to iOS version

Installation method

Cocoapods

SDK version

23.32

Other information

Essentially, our flow it this:

  1. Use the PaymentSheet.FlowController to select a payment method
  2. Send the request to the backend with the selected paymentMethod.stripeId
  3. Backend shares this payment method to a connected account and puts the shared one inside the payment intent. Then, the backend tries to confirm the payment intent.
  4. Then backend sends the payment intent secret back to iOS
  5. On iOS, we are tying to call intentCreationCallback?(.success(clientSecret))
  6. If the intent requires next action (e.g. 3DSecure), we get this ERROR An error occurred in PaymentSheet.There is a mismatch between the payment method ID on your Intent: pm_XXX and the payment method passed into the confirmHandler: pm_YYY

With Basic Integration and older PaymentSheet versions this action is handled without issues and we confirm the payment with 3DSecure.
But with the new PaymentSheet releases this got broken.

I saw you added this check in this pull request, but it breaks our use case unfortunately.
#3972

It works with the older (August) version of SDK, e.g. 23.29.2. Can we add a way (maybe additional configuration option) to omit this check, so our use case is not broken?

@yuki-stripe
Copy link
Collaborator

Hello @Ariandr, sorry you're running into this. How are you "sharing" the payment method? In the integration you linked (https://docs.stripe.com/connect/direct-charges-multiple-accounts), cloning happens after the confirmation succeeds and you shouldn't run into this issue.

@Ariandr
Copy link
Author

Ariandr commented Oct 28, 2024

@yuki-stripe
To make it simpler, probably the steps will be easier:

  1. We choose a payment method using PaymentSheet.FlowController using the Main account stripeId on iOS/Android and pay.
  2. We send payment method id to the server to finalize the payment.
  3. On backend (NodeJS)
// 1. Create a shared payment method for the connected account
let sharedStripePaymentMethod = await stripe.paymentMethods.create(
      {
        customer: stripeCustomerId,
        payment_method: paymentMethodId,
      },
      {
        stripeAccount: clubStripeAccountId,
      },
    );
    
    ......
    
// 2. Use it to create and confirm a payment intent
let intentOptions = {
      payment_method: sharedStripePaymentMethod.id,
      customer: sharedStripeCustomer.id,

      amount: updatedAmount,
      currency: currency,

      return_url: return_url,
      confirmation_method: 'manual',
      use_stripe_sdk: true,
      save_payment_method: false,
      confirm: true,

      ....
    };
  1. Send the intent client secret back to the iOS/Android
  2. If it requires action (e.g. 3DSecure), we set a connected stripe account id (both in Basic and new Payment element integrations), then call intentCreationCallback(.success(clientSecret)). In the last version it gives the error (before showing 3DSecure authentication).
  3. After the next action is handled, we send a new request to the backend with the payment intent id to let it fully confirm the payment and assign the purchased service product to the user.

As you see, we finalize the payment manually on the backend side.

Using August SDK version it works.

In the docs, it also uses a cloned payment method (with a new unique id) to create and confirm the payment intent, so if the next action is required on iOS/Android, the app will have to go through 3DSecure after intentCreationCallback(.success(clientSecret)), since we are using manual confirmation and it cannot be confirmed before.
image

@Ariandr
Copy link
Author

Ariandr commented Oct 28, 2024

Side note.
It would be great if the PaymentSheetResult provided the completed intent. For manual server-side confirmation it's pretty inconvenient to keep track of the intent to send it back to the server after the required client action has been performed on iOS.

PaymentSheetResult {
    case completed(intent: Intent)
    ....
}

Wherever makePaymentSheetResult is called in SDK there is access to the intent and this change won't break anything I believe.

I use this workaround instead:

var clientSecret: Sting? // Last received from the server

func confirmPayment() {
      self.paymentSheetFlowController?.confirm(from: self, completion: { paymentResult in
            switch paymentResult {
            case .completed:
                if let clientSecret = clientSecret {
                        STPAPIClient.shared.retrievePaymentIntent(withClientSecret: clientSecret) { paymentIntent, error in
                                guard let paymentIntent = paymentIntent else {
                                    return
                                }
                                
                                if paymentIntent.status == .requiresConfirmation {
                                     let paymentIntentId = paymentIntent.stripeId
                                     // Send paymentIntentId back to the server to finalize the payment
                                }
                            }
                            
                            ....
                            ....
}

Just a suggestion from me, it's not directly related to the issue, just that you can understand the use case🙂

@Ariandr Ariandr closed this as completed Oct 28, 2024
@Ariandr Ariandr reopened this Oct 28, 2024
@Ariandr
Copy link
Author

Ariandr commented Oct 30, 2024

Hi @yuki-stripe
Do you know any workarounds to skip this validation for our case?
ERROR An error occurred in PaymentSheet.There is a mismatch between the payment method ID on your Intent

Because otherwise new versions of SDK become unusable for us :(

@yuki-stripe
Copy link
Collaborator

Hey @Ariandr, I believe we'll indeed need to update the validation logic in #3972 to accommodate your use case. Sorry for the delay here and sorry for missing this scenario when we added the check! We should be able to get the fix into the next SDK release this coming Monday.

@yuki-stripe yuki-stripe added the triaged Issue has been reviewed by Stripe and is being tracked internally label Oct 30, 2024
@Ariandr
Copy link
Author

Ariandr commented Oct 30, 2024

@yuki-stripe
Great, thank you for the response and action. Appreciate it!

joyceqin-stripe added a commit that referenced this issue Nov 1, 2024
## Summary
<!-- Simple summary of what was changed. -->
Added fingerprint checking logic in deferred validation for card and
us_bank_account if PM ids don't match

## Motivation
<!-- Why are you making this change? If it's for fixing a bug, if
possible, please include a code snippet or example project that
demonstrates the issue. -->
#4195
https://jira.corp.stripe.com/browse/RUN_MOBILESDK-3670

## Testing
<!-- How was the code tested? Be as specific as possible. -->
Unit tests with different pm ids but matching or mismatching fingerprints for card and bank account

## Changelog
<!-- Is this a notable change that affects users? If so, add a line to
`CHANGELOG.md` and prefix the line with one of the following:
    - [Added] for new features.
    - [Changed] for changes in existing functionality.
    - [Deprecated] for soon-to-be removed features.
    - [Removed] for now removed features.
    - [Fixed] for any bug fixes.
    - [Security] in case of vulnerabilities.
-->
@yuki-stripe yuki-stripe added the fixed in master Fixed in master, awaiting next update label Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed in master Fixed in master, awaiting next update kind:bug triaged Issue has been reviewed by Stripe and is being tracked internally
Projects
None yet
Development

No branches or pull requests

2 participants