ZackHossain
ZackHossain

Reputation: 201

Flutter Stripe throws StripeException when Presenting Payment Sheet

I am trying to implement a Stripe payment system in my flutter app using the stripe_payment package. In my code, I call Stripe.instance.initPaymentSheet(...), however when I try to call Stripe.instance.presentPaymentSheet(...) just a few lines later, I get this error:

flutter: StripeException(error: LocalizedErrorMessage(code: FailureCode.Failed, localizedMessage: No payment sheet has been initialized yet, message: No payment sheet has been initialized yet, stripeErrorCode: null, declineCode: null, type: null))

Here is my code:

Future<void> makePayment() async {
    final url = Uri.parse(
        '${firebaseFunction}');

    final response =
        await http.get(url, headers: {'Content-Type': 'application/json'});

    this.paymentIntentData = json.decode(response.body);

    await Stripe.instance.initPaymentSheet(
        paymentSheetParameters: SetupPaymentSheetParameters(
            paymentIntentClientSecret: paymentIntentData!['paymentIntent'],
            applePay: true,
            googlePay: true,
            style: ThemeMode.dark,
            merchantCountryCode: 'UK',
            merchantDisplayName: 'Test Payment Service'));
    setState(() {});

    print('initialised');
    try {
      await Stripe.instance.presentPaymentSheet();
      setState(() {
        paymentIntentData = null;
      });
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: Text('Payment Successful!'),
      ));
    } catch (e) {
      print(e);
    }
    // await displayPaymentSheet();
  }

And here is my node.js code (accessed through url):

const functions = require("firebase-functions");

const stripe = require('stripe')(functions.config().stripe.testkey);

exports.stripePayment = functions.https.onRequest(async (req, res) => {
    const paymentIntent = await stripe.paymentIntents.create({
        amount: 170,
        currency: 'usd'
    },
    function(err, paymentIntent) {
        if (err != null) {
            console.log(err);
        } else {
            res.json({
                paymentIntent: paymentIntent.client_secret
            })
        }
    })
})

Why doesn't the Payment Sheet initialize (or stay initialized) when I try to use the presentPaymentSheet method?

Upvotes: 16

Views: 19027

Answers (6)

user22904424
user22904424

Reputation:

Simply include this code within the catch statement :

      if (e is _$_StripeException && e.error.localizedMessage == 'The payment flow has been canceled') {
    // Handle canceled payment
    print('Payment canceled by the user');
    // You can show a message to the user or navigate back to the previous screen
  } else {
    // Handle other errors
    print('Error during payment: $e');
    // You might want to show a generic error message or log the error for debugging
  }

Upvotes: 0

Osama Buzdar
Osama Buzdar

Reputation: 1222

if you have checked out all the above but nothing worked: just set allowsDelayedPaymentMethods: true,

 await Stripe.instance.initPaymentSheet(
      paymentSheetParameters: SetupPaymentSheetParameters(
    merchantDisplayName: 'Prospects',
    customerId: data['customer'],
    allowsDelayedPaymentMethods: true, // set this to true
    paymentIntentClientSecret: data['client_secret'],
    customerEphemeralKeySecret: data['ephemeralKey'],
  ));

Upvotes: 1

Andy
Andy

Reputation: 81

I had the same problem as I was following the official documentation found here. What was causing this problem was the value of paymentIntentClientSecret.

Try changing:

paymentIntentClientSecret: data['paymentIntent']

To:

paymentIntentClientSecret: data['client_secret'],

Upvotes: 1

梁典典
梁典典

Reputation: 3

stripe version

flutter_stripe: ^7.0.0
await Stripe.instance.initPaymentSheet(
        paymentSheetParameters: SetupPaymentSheetParameters(
            merchantDisplayName: 'APP',
            paymentIntentClientSecret: model.clientSecret,
            customerEphemeralKeySecret: eph.secret,
            customerId: model.customer,
            style: ThemeMode.system,
            billingDetails: billingDetail,
            customFlow: true),
      );

Adding the attribute 'customFlow' solves my problem

customFlow: true

Upvotes: 0

Mahluleli Goodson
Mahluleli Goodson

Reputation: 31

In case someone ends up here in the future and you've tried everything including adding extra settings in your main file, try also changing your customerId field in the Stripe.instance.initPaymentSheet to null or some existing Id. What I found is for android it easily works but with iOS it needs a proper customerId or null.

Upvotes: 3

Daniel Kang
Daniel Kang

Reputation: 565

The Paymentsheet worked on android but did not work in iPhone for me. It took me hours to find this answer (was struggling as well). There needs to be an update in the stripe documentation but when initializing Stripe you will need to initialize Stripe.publishableKey but also initialize Stripe.merchantIdentifier

EXAMPLE

First you will need initialize Stripe in your main function. (Like shown below).

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Stripe.publishableKey = stripePublishableKey;
  Stripe.merchantIdentifier = 'any string works';
  await Stripe.instance.applySettings();
  runApp(const App());
}

Then the paymentsheet will appear without stating No payment sheet has been initialized yet

Upvotes: 38

Related Questions