stripe / stripe-react-native

React Native library for Stripe.
https://stripe.dev/stripe-react-native
MIT License
1.26k stars 263 forks source link

Issue with manual payment intents on ReactNative #1737

Open skoolaidl opened 1 week ago

skoolaidl commented 1 week ago

I am attempting to collect user payment using the Stripe SDK in react native, but having some issues with the current flow I am attempting.

Essentially, it goes like this:

  1. Collect payment information from the user using the PaymentSheet. Following the docs line for line here. Everything is working as expected. Payment sheet is shown, can select payment, etc.
  2. Submission on the confirmHandler calls the backend which generates a payment intent that must be confirmed manually. The reason behind this is the basic functionality of the app -- a user submits a request for a service and the service provider must confirm the details before the process is completed. When the service provider completes this step, then the payment intent is set to confirmed (also via my service).
  3. When my backend returns the client secret, I get this error message on the payment sheet:
PNG image

Here is how I am initializing the sheet:

const openPaymentSheet = async () => {
        if (user) {
            await fetchPaymentSheetParams(user)
                .then((response: any) => {
                    return initPaymentSheet({
                        merchantDisplayName: "MyApp",
                        customerId: response.id,
                        customerEphemeralKeySecret: response.secret,
                        intentConfiguration: {
                            //sample amount, will be set dynamically
                            mode: {
                                amount: 1409,
                                currencyCode: 'USD', 
                            },
                            confirmHandler: confirmHandler,
                        },
                        returnURL: 'MyAppRedirect',
                        allowsDelayedPaymentMethods: false,
                        applePay: {
                            merchantCountryCode: 'US',
                        },
                        // customFlow: true,
                    });
                })
                .then(() => {
                    return presentPaymentSheet();
                })
                .catch((error) => {
                    // log error
                });
        };
    };

And here is the handler:

const confirmHandler = async (paymentMethod: any, shouldSavePaymentMethod: any, intentCreationCallback: any) => {
        if (user) {
            await requestService(user)
                .then((response) => {
                    intentCreationCallback({clientSecret: response.clientSecret});
                })
                .catch(error => {
                    intentCreationCallback({error: error});
                })
        }
    }

The client_secret is processed and applied to the intentCreationCallback. I need a way to just close the sheet, even if the intent is manual. I shouldn't NEED to confirm it on the mobile app? There is little to no documentation on PaymentSheet.FlowController, so I am at a loss there as well.

I see a lot of people suggesting setting "customFlow" to true, which does not accomplish what I need. If I use Apple Pay as the payment method, it still seems to require an payment intent with automatic validation.

Thoughts?

seanzhang-stripe commented 1 week ago

Hi @skoolaidl the manual confirmation in Stripe context (e.g., confirmation_method="manual") refers to a confirming a PaymentIntent with a secret key from your server. Based on the use case that your described, I believe you should use the auth-and-capture flow by setting capture_method="manual". So that you can still confirm the PaymentIntent with PaymentSheet, and later capture the funds when your service provider completes the details.

Feel free to let me know if you have any other questions.