Accept a payment - ACH Direct Debit (US and Canada only)

Handling ACH direct debit payments#

ACH Direct Debit is a delayed notification payment method, which means that it takes some time before the funds are transfered (around 4 days). At the moment Stripe only supports bank accounts for the US and Canada.

1. Create#

First, you need a Stripe account. Register now.

Server-side#

This integration requires endpoints on your server that talk to the Stripe API. Use one official libraries for access to the Stripe API from your server. Follow the steps to create an ACH payment here.

Client-side#

The Flutter SDK is open source, fully documented.

To install the SDK, follow these steps:

  • Run the commmand flutter pub add flutter_stripe
  • This will add a line like this to your project's pubspec.yaml with the latest package version

For details on the latest SDK release and past versions, see the Releases page on GitHub. To receive notifications when a new release is published, watch releases for the repository.

When your app starts, configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API.

void main() async {
  Stripe.publishableKey = stripePublishableKey;
  runApp(const App());
}

Use your test mode keys while you test and develop, and your live mode keys when you publish your app.

Also make sure your account is registered in the US and you have enabled the ACH payment method in Stripe dashboard.

2. Add an endpoint [Server Side]#

First you need to create a PaymentIntent on your backend server. A paymentintent is an object that represents your intent to collect a payment from a customer and tracks the lifecycle of the payment process through each stage.

Checkout the example implementation for your server in the official stripe docs

Returns the Payment Intent’s client secret, to your app.

3. Collect the payment details [Client Side]#

Step 1: Confirm the payment.#

When you received the payment intents client secret you can use the FlutterStripe sdk to configm the payment. For this paymentmethod it is required to provide the name + email in the billingdetails.


 final billingDetails = BillingDetails(
        name: 'Flutter Stipe',
        email: 'email@stripe.com',
        phone: '+48888000888',
        address: Address(
          city: 'Houston',
          country: 'US',
          line1: '1459  Circle Drive',
          line2: '',
          state: 'Texas',
          postalCode: '77063',
        ),
      );

final confirmIntent = await Stripe.instance.confirmPayment(
          paymentIntentResult['clientSecret'],
          PaymentMethodParams.usBankAccount(
              accountNumber: _accountController.text,
              routingNumber: _routingNumberController.text,
              billingDetails: billingDetails,
              ),
);

Step 2: Verify bank with microdeposits.#

Not all customers can verify the bank instantly and in that cases Stripe sends a microdeposit to the bank account which takes 1-2 days to appear.

The deposit can come into 2 shapes:

  • Descriptor code: Stripe will send a microdeposit of 0.01 USD to the customer's account with a 6 digit descriptor code that starts with SM. The customer will use this string to verify their bank account.
  • Amount: Stripe will send two non-unique microdeposits to the customers bank account with a statement that looks like: AMTS: <amount1>,<amount2>. The customer needs to enter the 2 deposit amounts to verify their bank account.

In the Flutter Sdk use the action parameter of the intent that is retrieved from the confirmIntent method in step 1.


  confirmIntent.action?.maybeWhen(
      verifyWithMicroDeposits: (_, __, ___) {
        /// show some widget where user can enter the microdeposit info
      },

After that collect the microdeposits. You must provide either a descriptor code or the two amounts not both. The example below shows how to invoke the Stripe sdk with the descriptorcode.

 await Stripe.instance.verifyPaymentIntentWithMicrodeposits(
          isPaymentIntent: true,
          clientSecret: widget.clientSecret,
          params: VerifyMicroDepositsParams(
            descriptorCode: _descriptorController.text
          ));

4. Handle post-payment events#

Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.

Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes. Setting up your integration to listen for asynchronous events also makes it easier to accept more payment methods in the future. Check out our guide to payment methods to see the differences between all supported payment methods.

5. Test the integration#

If you are using your test Api key stripe will show a test page after confirming the intent. You can choose yourself whether or not to authorize or fail the payment. For more info about testing check the Stripe docs.