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

You cannot confirm this Paymentlntent because it's missing a payment method #1980

Open
itsamit108 opened this issue Oct 29, 2024 · 14 comments
Open
Labels
bug Something isn't working

Comments

@itsamit108
Copy link

Describe the Bug
I am implementing Stripe ACH with instant verification in a Flutter app but encounter an error during payment confirmation. I followed the official Flutter Stripe documentation: Flutter Stripe Financial Connections.

Issue Details
After collecting and verifying the bank account through Stripe ACH with instant verification (as per the documentation), I receive this error when attempting to confirm the payment:

"You cannot confirm this PaymentIntent because it's missing a payment method. You can either update the PaymentIntent with a payment method and then confirm it again, or confirm it again directly with a payment method or ConfirmationToken."

image

Key Question

How should the payment method be provided or linked in the following code?

final paymentIntent = await Stripe.instance.confirmPayment(
  paymentIntentClientSecret: paymentIntentData['paymentIntent'],
);

This is a business-critical requirement.

For reference, I also reviewed the related issue: GitHub Issue #1348.

Critical Code Snippets

Payment Handling Code

Future<void> handlePayment() async {
  if (_amountController.text.isEmpty) {
    setState(() { _errorMessage = 'Please enter an amount'; });
    return;
  }

  setState(() => _errorMessage = null);
  ref.read(paymentLoadingProvider.notifier).state = true;

  // Step 1: Create Financial Connection Session
  final sessionData = await PaymentService.createFinancialConnectionSession();

  // Step 2: Collect Financial Connection Account
  final result = await Stripe.instance.collectFinancialConnectionsAccounts(
    clientSecret: sessionData['clientSecret'],
  );

  _selectedAccountId = result.session.accounts.first.id;

  // Step 3: Create Payment Intent
  final paymentIntentData = await PaymentService.createPaymentIntent(
    amount: double.parse(_amountController.text),
  );

  // Step 4: Confirm Payment
  final paymentIntent = await Stripe.instance.confirmPayment(
    paymentIntentClientSecret: paymentIntentData['paymentIntent'],
  );

  if (mounted) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Payment processed successfully!'),
        backgroundColor: Colors.green,
      ),
    );
    setState(() {
      _amountController.clear();
      _selectedAccountId = null;
    });
  }

  ref.read(paymentLoadingProvider.notifier).state = false;
}

Payment Service Class

class PaymentService {
  static Future<Map<String, dynamic>> createPaymentIntent({
    required double amount,
    String staffingFirmId = '',
  }) async {
    final amountInCents = (amount * 100).round();
    final response = await http.post(
      Uri.parse("${dotenv.get("baseurl")}/api/payment/create-payment-intent"),
      headers: {
        'Content-Type': 'application/json',
        'Authorization': "Bearer ${IdSharedPreferences.getJWTHead()}",
      },
      body: json.encode({
        'amount': amountInCents,
        'currency': 'usd',
        'description': 'Payment of \$$amount',
        'staffingFirmId': staffingFirmId,
      }),
    ).timeout(const Duration(seconds: 10), onTimeout: () {
      throw 'Connection timeout. Please check if the server is running.';
    });

    if (response.statusCode == 200) {
      final responseData = json.decode(response.body);
      return { 'paymentIntent': responseData['client_secret'] };
    } else {
      throw 'Server returned status code: ${response.statusCode}\nResponse: ${response.body}';
    }
  }

  static Future<Map<String, dynamic>> createFinancialConnectionSession() async {
    final response = await http.post(
      Uri.parse("${dotenv.get("baseurl")}/api/payment/create-financial-connection-session"),
    ).timeout(const Duration(seconds: 10), onTimeout: () {
      throw 'Connection timeout. Please check if the server is running.';
    });

    if (response.statusCode == 200) {
      final responseData = json.decode(response.body);
      return { 'clientSecret': responseData['clientSecret'] };
    } else {
      throw 'Server returned status code: ${response.statusCode}\nResponse: ${response.body}';
    }
  }
}

Stripe Integration - Payment Intent Creation

async createPaymentIntent(amount, currency = 'usd', description = '') {
  const paymentIntent = await paymentIntents.create({
    amount,
    currency,
    description,
    automatic_payment_methods: { enabled: true },
    payment_method_options: {
      us_bank_account: {
        verification_method: 'automatic',
        financial_connections: { permissions: ['payment_method', 'balances'] },
      }
    },
  });

  Log_INFO(`PaymentIntent created with ID: ${paymentIntent.id}`);
  return paymentIntent;
}

Financial Connections Session Creation

export async function createFinancialConnectionsSession(req, res, next) {
  const account = await stripe.accounts.create({
    country: 'US',
    type: 'custom',
    capabilities: {
      card_payments: { requested: true },
      transfers: { requested: true },
    },
  });

  const session = await stripe.financialConnections.sessions.create({
    account_holder: { type: 'account', account: account.id },
    filters: { countries: ['US'] },
    permissions: ['ownership', 'payment_method'],
  });

  return res.send({ clientSecret: session.client_secret });
}

To Reproduce
Steps to reproduce the issue:

  1. Enter 123-456-789 in the card field.
  2. Tap the confirm button.
  3. Observe the error message.

Expected Behavior
A clear and successful confirmation of the payment intent.

Smartphone / Tablet Details

  • Device: e.g., iPhone X
  • OS: e.g., iOS 13, Android 10
  • Package Version: e.g., 1.0.0
  • Flutter Version: e.g., 2.0.0

Additional Context
Any additional insights or workarounds are welcome.

@itsamit108 itsamit108 added the needs triage Needs triage label Oct 29, 2024
@remonh87
Copy link
Member

remonh87 commented Nov 3, 2024

you need to use confirmPayment with the us bankaccount payment like done in this example:

final intent = await Stripe.instance.confirmPayment(

@remonh87 remonh87 added Awaiting response Awaiting response from the issuer and removed needs triage Needs triage labels Nov 3, 2024
@itsamit108
Copy link
Author

you need to use confirmPayment with the us bankaccount payment like done in this example:

final intent = await Stripe.instance.confirmPayment(

Thanks for the suggestion! However, this example applies to Stripe ACH with microdeposit payments, while I'm implementing Stripe ACH with instant verification using financial connections.

The error I'm facing occurs after collecting and verifying the bank account through instant verification, as per the documentation. When I attempt to confirm the payment, I get this error:

"You cannot confirm this PaymentIntent because it's missing a payment method. You can either update the PaymentIntent with a payment method and then confirm it again, or confirm it again directly with a payment method or ConfirmationToken."

Please refer to the code snippets provided above for reference, or feel free to ask any follow-up questions for further clarity.

@remonh87 remonh87 added bug Something isn't working and removed Awaiting response Awaiting response from the issuer labels Nov 13, 2024
@remonh87
Copy link
Member

I will try to look at it next week at the moment I am abroad for work

@ogoldberg
Copy link

I always get this error when I accidentally use a test payment method in a prod environment or vice versa. You might want to double check that you are using the right key for the environment you are in.

@itsamit108
Copy link
Author

I will try to look at it next week at the moment I am abroad for work

Any fix for this issue?

@mariandumitrascu
Copy link

Hi All, I'm trying to replicate this issue, using the demo application in ./example. It looks like the issue correspond to the code in './example/lib/screens/regional_payment_methods/us_bank_account.dart' However the example app does not encounter the same error message when I try it. (That is: is not showing the message "You cannot confirm ...") Am I missing something in order to replicate the exact issue?

@remonh87
Copy link
Member

remonh87 commented Dec 9, 2024

sorry I had very little time the last weeks due to unforseen circumstances will look into the issue tomorrow. I think we need to implement the ach direct verification

@LMolochniy-cs
Copy link

Could you confirm if this issue has been resolved? I’m encountering the same problem when attempting instant verification in Flutter, but it works fine on the web.

@mariandumitrascu
Copy link

@remonh87 thank you for your message. Yes, We would Greatly appreciate. The example app does not contain the exact case scenario that we encounter, but is close. The example closest case is in 'us_bank_account.dart', but that one is using ACH microdeposits confirmation. We are looking to use "instant verification". So far, we can make it work only on web, but majority of our users will use flutter dart version.

@remonh87
Copy link
Member

I asked @jonasbark to take a look at it. I have an example ready but I ran into some weird serialization issues with readablemap in the native code.

@remonh87
Copy link
Member

there is a fix for it: #2014

@itsamit108
Copy link
Author

there is a fix for it: #2014

Thanks 🙏, is it ready to be used? Is it live in the current package version?

@itsamit108
Copy link
Author

there is a fix for it: #2014

Still getting this error while trying that fix:

Image

@itsamit108
Copy link
Author

This is what we want to implement in Flutter - ACH Direct Debit with Instant Verifications. Here is a short video explaining that (it's a web demo btw): https://youtu.be/Q9Muz8OEZYk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants