Financial Connections

Connect to your users' bank accounts (US bank accounts only)

Financial Connections allows you to connect to your users' bank accounts to access financial data for various use cases like account verification, balance checks, and transaction history.

To learn more about how it works read: Official Stripe Financial Connections docs.

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 Financial account session here.

Client-side

The Flutter SDK is open source, fully documented.

To install the SDK, follow these steps:

  • Run the command 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.

2. Create an account holder. [Server Side]

To attach data to an account holder you must first create one.
For detailed api instructions checkout the official docs.

3. Create a Financial connections session [Server Side]

Before you can retrieve data from a user's bank account through Stripe financial connections, your user must authenticate their account with the authentication flow.

Click here to learn more how to setup a session.

4. Collect Financial Accounts [Client Side]

On the client side you need to receive the session client secret in order to start the authorization flow on mobile.

Option A: Collect Financial Connections Accounts

Use collectFinancialConnectionsAccounts to connect to a user's bank account and retrieve account information:

Future<void> _collectAccount(BuildContext context) async {
  // 1. Retrieve the session client secret from your backend
  final data = await _fetchFinancialConnectionsSession();
  final clientSecret = data['clientSecret'];

  // 2. Use the client secret to start the financial connections flow
  try {
    final result = await Stripe.instance.collectFinancialConnectionsAccounts(
      clientSecret: clientSecret,
    );

    // Handle successful result
    setState(() {
      response = result.toString();
    });
  } on Exception catch (e) {
    if (e is StripeException) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Error from Stripe: ${e.error.localizedMessage}'),
        ),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Unforeseen error: $e'),
        ),
      );
    }
  }
}

The collectFinancialConnectionsAccounts method returns a FinancialConnectionSessionResult when the user completes the modal authentication flow, or throws a StripeException on failure or cancellation.

Option B: Collect Bank Account Token

Use collectBankAccountToken to collect a bank account token that can be used for payments:

Future<void> _collectBankToken(BuildContext context) async {
  // 1. Retrieve the session client secret from your backend
  final data = await _fetchFinancialConnectionsSession();
  final clientSecret = data['clientSecret'];

  // 2. Use the client secret to collect a bank token
  try {
    final result = await Stripe.instance.collectBankAccountToken(
      clientSecret: clientSecret,
    );

    // Handle successful result
    setState(() {
      response = result.toString();
    });
  } on Exception catch (e) {
    if (e is StripeException) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Error from Stripe: ${e.error.localizedMessage}'),
        ),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Unforeseen error: $e'),
        ),
      );
    }
  }
}

The collectBankAccountToken method returns a FinancialConnectionTokenResult containing a bank account token.

5. Complete Example [Client Side]

Here's a complete example showing both methods:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:http/http.dart' as http;

class FinancialConnectionsScreen extends StatefulWidget {
  const FinancialConnectionsScreen({super.key});

  @override
  State<FinancialConnectionsScreen> createState() =>
      _FinancialConnectionsScreenState();
}

class _FinancialConnectionsScreenState
    extends State<FinancialConnectionsScreen> {
  String response = '';

  Future<Map<String, dynamic>> _fetchFinancialConnectionsSession() async {
    final url = Uri.parse('$kApiUrl/financial-connections-sheet');
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
    );
    return json.decode(response.body);
  }

  Future<void> _collectAccount(BuildContext context) async {
    final data = await _fetchFinancialConnectionsSession();
    final clientSecret = data['clientSecret'];

    try {
      final result = await Stripe.instance.collectFinancialConnectionsAccounts(
        clientSecret: clientSecret,
      );

      if (!mounted) return;
      setState(() {
        response = result.toString();
      });
    } on StripeException catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error: ${e.error.localizedMessage}')),
      );
    }
  }

  Future<void> _collectBankToken(BuildContext context) async {
    final data = await _fetchFinancialConnectionsSession();
    final clientSecret = data['clientSecret'];

    try {
      final result = await Stripe.instance.collectBankAccountToken(
        clientSecret: clientSecret,
      );

      if (!mounted) return;
      setState(() {
        response = result.toString();
      });
    } on StripeException catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error: ${e.error.localizedMessage}')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Financial Connections')),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () => _collectAccount(context),
              child: Text('Collect Financial Account'),
            ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: () => _collectBankToken(context),
              child: Text('Collect Bank Token'),
            ),
            SizedBox(height: 20),
            Text(response),
          ],
        ),
      ),
    );
  }
}