# Manage payout accounts for connected accounts Learn how to manage external bank accounts and debit cards for connected accounts. *Payout* (A payout is the transfer of funds to an external account, usually a bank account, in the form of a deposit) accounts can be bank accounts or debit cards. Stripe recommends collecting external account details with the Connect Onboarding web form, which helps you: - Save design and development time. - Eliminate the need to store sensitive data such as account and routing numbers on your server. - Eliminate the need to build form validations when connected accounts enter account details. In the US, we also recommend using [Stripe Financial Connections](https://docs.stripe.com/financial-connections.md), which lets your connected accounts securely link their financial accounts to your business. It helps you: - Increase onboarding conversion by preventing your accounts from having to interrupt the process to locate their account and routing numbers. - Reduce first payout failure rates by eliminating errors that result from manual entry of account and routing numbers. - Eliminate the need to store sensitive data such as account and routing numbers on your server. - Eliminate the need to build form validations when accounts enter account details in custom onboarding forms. - (Accounts v1 only) Enable your accounts to authenticate in fewer steps by reusing bank account details they’ve saved to [Link](https://support.stripe.com/questions/link-for-financial-connections-support-for-businesses). Accounts that save their account information at any of the Stripe businesses using Link can share their account details with your platform the next time they use Financial Connections. - Access additional information on an account’s external bank account, such as [balances](https://docs.stripe.com/financial-connections/balances.md), [ownership details](https://docs.stripe.com/financial-connections/ownership.md), and [transactions](https://docs.stripe.com/financial-connections/transactions.md). You can mitigate fraud during onboarding by verifying that information, such as the name and address of the external bank account holder. When [Link is enabled](https://dashboard.stripe.com/settings/connect/payouts/external_accounts), Stripe-hosted and embedded onboarding don’t charge for Financial Connections verifications. Otherwise, [standard Financial Connections verification pricing](https://stripe.com/financial-connections#pricing) applies. If you use API onboarding for your connected accounts, you can collect payout account details with a custom form in your account onboarding flow. ### Opting out of external account collection For accounts where the platform is responsible for collecting requirements, such as Custom accounts, you may opt not to collect external account information in onboarding. You may do this if, for instance, you build your own onboarding flow where you want to collect external account information. In embedded onboarding, you can [disable external account collection](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md?#external-account-collection) by setting the `external_account_collection` feature on the Account Session to false. Alternatively, in hosted onboarding you can go to your [Connect external accounts settings](https://dashboard.stripe.com/settings/connect/payouts/external_accounts) and then under **Accounts where the platform is responsible for collecting requirements** enable or disable collecting external account information. Note that this is off by default. ## Collecting external accounts #### Stripe-hosted or embedded onboarding [Stripe-hosted and embedded onboarding](https://docs.stripe.com/connect/onboarding.md) use themeable web forms to collect the information required to onboard connected accounts. They can collect both bank accounts and debit cards. You can use Financial Connections to collect bank account details, but not to collect debit card details. For connected accounts where your platform is responsible for negative balances, you can customize the collection flow of external accounts in your [External account](https://dashboard.stripe.com/settings/connect/payouts/external_accounts) settings. In your **External account** settings, you can: - Enable or disable the collection of debit cards, by making a selection under **Allow debit cards?**. - Require that connected accounts must add at least one bank account before being able to add any other type of external account, such as a debit card. You can access this setting under **Require at least one bank account?**. This is useful for ensuring [auto debit](https://docs.stripe.com/connect/account-balances.md#automatically-debit-connected-accounts) support. - Control whether or not connected accounts to add more than one external account in a given currency. There is a limit of five external accounts per currency. You can access this setting under **Collect multiple external accounts per currency**. #### Use Stripe Financial Connections ### Available in - US Stripe platforms in the US can enable [Stripe Financial Connections](https://docs.stripe.com/financial-connections.md) within the Stripe-hosted or embedded onboarding form by following these steps: 1. Navigate to your [External Account settings](https://dashboard.stripe.com/settings/connect/payouts/external_accounts), where you manage optional Connect onboarding features. 1. For connected accounts where your platform collects account information when requirements change, you must allow Stripe-hosted and embedded onboarding to collect external account details. Under **Stripe-hosted onboarding for Custom accounts**, allow Stripe to collect external account information by turning on the toggle. 1. Under **How will bank account details be collected?**, select **Financial Connections**. 1. (Optional) Request permission to access additional data on the accounts instantly verified with Financial Connections, such as balances, ownership details, and transactions. If you request this additional access, you’re prompted to sign up for Stripe Financial Connections. When external account detail collection is enabled, the onboarding flow prompts all connected accounts to authenticate their bank account. ![Image showing a Connect onboarding flow using Stripe Financial Connections to collect a payout account.](https://b.stripecdn.com/docs-statics-srv/assets/connect-custom-onboarding-financial-connections-onboarding.8937a023f6682c90bab8c0b39873909a.png) A Connect onboarding flow using Stripe Financial Connections to collect a payout account. If a connected account can’t instantly verify their bank account using Financial Connections, the verification process automatically falls back to manual entry: ![Image showing a Connect onboarding flow using the Stripe Financial Connections dialog to collect a payout account using manual entry.](https://b.stripecdn.com/docs-statics-srv/assets/connect-custom-onboarding-financial-connections-manual-entry.930da1e01c9026b9014008d75958bc8c.png) A Connect onboarding flow using the Stripe Financial Connections dialog to collect a payout account using manual entry. After onboarding, the specified bank account automatically attaches to the connected account. ## Retrieve data on a Financial Connections account (Server-side) You can determine whether a connected account linked a Financial Connections account by using their `Account` ID to retrieve any linked Financial Connections accounts. Specify their `Account` ID as the `account_holder.account` and in the `Stripe-Account` header. ```curl curl -G https://api.stripe.com/v1/financial_connections/accounts \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d "account_holder[account]"="{{CONNECTEDACCOUNT_ID}}" ``` This returns an API response similar to the following: ```json { "object": "list", "data": [ { "id": "fca_zbyrdjTrwcYZJZc6WBs6GPid", "object": "financial_connections.account", "account_holder": { "account": "{{CONNECTED_ACCOUNT_ID}}", "type": "account" }, ... "supported_payment_method_types": [ "us_bank_account" ] } ... ] } ``` If any Financial Connections accounts are listed, it indicates that the connected account linked them during the onboarding process. You can use the `id` value to access or refresh the data you specified in your [External Account settings](https://dashboard.stripe.com/settings/connect/payouts/external_accounts). To protect the privacy of your connected account’s data, you can only access the data you specified. To start retrieving account data, follow the guides for [balances](https://docs.stripe.com/financial-connections/balances.md), [ownership](https://docs.stripe.com/financial-connections/ownership.md), and [transactions](https://docs.stripe.com/financial-connections/transactions.md). On all subsequent account retrieval and refresh requests, be sure to include the `Stripe-Account` header with the connected account ID: ```curl curl https://api.stripe.com/v1/financial_connections/accounts/fca_zbyrdjTrwcYZJZc6WBs6GPid/refresh \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d "features[]"=balance ``` #### Enable manual entry of bank account details To allow Stripe to manually collect bank account details from connected accounts within the onboarding form, follow these steps: 1. Open your Connect settings and go to Payouts > External Accounts, where you can manage Connect onboarding options. 1. Under **How will bank account details be collected?**, select the option to manually collect bank account information. 1. For connected accounts where your platform collects account information when requirements change, you must allow Stripe-hosted and embedded onboarding to collect external account details. Under **Accounts where the platform is responsible for collecting requirements**, allow Stripe to collect external account information by turning on the toggle. ![Image showing a Connect onboarding flow using a form to collect a payout account using manual entry.](https://b.stripecdn.com/docs-statics-srv/assets/connect-custom-onboarding-payout-manual-entry-form.6764993258659b2ad6517e0825181e49.png) Connect onboarding flow using a form to collect a payout account using manual entry. Every country has a slightly different format for bank account details, and the form automatically displays the fields appropriate for your country of operation. #### Direct API calls from a custom form For connected accounts where your platform collects account information when requirements change, you can collect external account information by making direct API calls from a custom form. #### Enable Stripe Financial Connections ### Available in - US Stripe platforms in the US can enable [Stripe Financial Connections](https://stripe.com/financial-connections) within their custom onboarding form. After you enable Stripe Financial Connections within your form, connected accounts instantly authenticate their bank account within the [authentication flow](https://docs.stripe.com/financial-connections/fundamentals.md#authentication-flow). [Register for Financial Connections](https://dashboard.stripe.com/financial-connections/application) to be approved for live-mode access. ### Create a SetupIntent (Server-side) Insert a button or link on your onboarding form that calls a server-side endpoint to create a [SetupIntent](https://docs.stripe.com/api/setup_intents.md). The SetupIntent represents your intent to collect a connected account’s bank account information. For example, your button might say **Link your bank account**. We recommend you create a *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) with an email address to correspond to each connected account. Attaching a Customer object allows you to [list previously linked external accounts](https://docs.stripe.com/api/financial_connections/accounts/list.md) later. Provide an email address when creating your customer to allow them to authenticate into their accounts in fewer steps by saving and reusing their bank details with [Link](https://support.stripe.com/questions/link-for-financial-connections-support-for-businesses) across Stripe businesses using the [Financial Connections authentication flow](https://docs.stripe.com/financial-connections/fundamentals.md#authentication-flow). When creating a SetupIntent to collect bank account details for a connected account, set the following parameters: 1. Set the `customer` type to the [Customer’s id](https://docs.stripe.com/api/customers/object.md#customer_object-id) 1. Set `payment_method_types` to `["us_bank_account"]` 1. Set `flow_directions` to `["outbound"]` 1. (Optional) Consider additional data required to fulfill your use case, and request permission to access it. For example, set `payment_method_options[us_bank_account][financial_connections][permissions]` to `["payment_method", "ownership"]` to request access to the ownership data for the Financial Connections Account after your user links their bank account using Financial Connections. Here’s an example of the minimal requirements for creating a SetupIntent to collect bank account details: ```curl curl https://api.stripe.com/v1/setup_intents \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "flow_directions[]"=outbound \ -d "payment_method_types[]"=us_bank_account ``` The SetupIntent in the response includes a `client_secret`, which allows you to launch the Stripe.js on-page modal UI that handles the collection and verification of bank account details. Handle the `client_secret` carefully because it provides access to the SetupIntent with only a publishable key. Don’t log it, embed it in URLs, or expose it to anyone but your connected accounts. #### Web ## Collect payment method details (Client-side) Include the Stripe.js script on your bank account collection page by adding it to the head of your HTML file. ```html Payout ``` Create an instance of Stripe.js with the following JavaScript on your bank account collection page. ```javascript // Set your publishable key. Remember to change this to your live publishable key in production! // See your keys here: https://dashboard.stripe.com/apikeys var stripe = Stripe('<>', { apiVersion: "{{DATE_VERSION}}" }); ``` Pass the `SetupIntent`’s `client_secret` and your connected account user’s full name to `stripe.collectBankAccountForSetup` to collect the Payment Method. ```javascript // Assume you have a form to collect payout accounts var form = document.getElementById('payout-form'); form.addEventListener('submit', (event) => { event.preventDefault(); // clientSecret is the SetupIntent's client_secret property stripe.collectBankAccountForSetup({ clientSecret, params: { payment_method_type: 'us_bank_account', payment_method_data: { billing_details: { // name is required name: 'Jenny Rosen', email: 'jenny@example.com' }, }, }, // Optional, helpful for client-side logic expand: ['payment_method'] }).then(({setupIntent, error}) => { if (error) { // Inform your connected account user that there was an error. console.log(error.message); } else { if (setupIntent.status === "requires_confirmation") { // Your connected account user provided bank account details // When you pass `expand: ['payment_method']` to `collectBankAccountForSetup`, // `setupIntent.payment_method` has data about the Payment Method, including // the Financial Connections Account ID, if your connected account user used // Financial Connections to provide their bank account details. const usedFinancialConnections = typeof setupIntent.payment_method.financial_connections_account === 'string'; console.log(setupIntent.payment_method.id); // => 'pm_1Mb4UkJGNKiWrCEmJ1PS72Cd' return stripe.confirmUsBankAccountSetup(clientSecret).then(({setupIntent, error}) => { if (error) { // Inform your connected account user that there was an error, and check your request logs for errors console.log(error.message); } else { if (setupIntent.status === 'succeeded') { // SetupIntent confirmed, Payment Method attached to the Customer // Your logic to create a payout account could go here } else { // Unable to confirm the SetupIntent, re-fetch the SetupIntent for details } } }); } else { // Your connected account user didn't provide bank account details. You // can re-prompt them using `collectBankAccountForSetup` return null; } } }); }); ``` `collectBankAccountForSetup` returns a `Promise`. When your connected account completes the Stripe.js dialog, the `Promise` resolves with a `result` object that has one of the following keys: - `setupIntent`, when your connected account exits the dialog - `error` if there’s an unrecoverable error when displaying the dialog If the `Promise` resolves with a `setupIntent` key, and `result.setupIntent.status` is `"requires_confirmation"`, confirm the `SetupIntent` by calling `confirmUsBankAccountSetup` with the `SetupIntent` `client_secret`. `confirmUsBankAccountSetup` also returns a `Promise` that resolves with the same type of `result` object as `collectBankAccountForSetup`. On successful confirmation, `result.setupIntent.status` is `"succeeded"`. This means that you can use the `SetupIntent`’s `payment_method` to create a bank account token on your server. When you call `stripe.collectBankAccountForSetup`, Stripe.js loads the [authentication flow](https://docs.stripe.com/financial-connections/fundamentals.md#authentication-flow), an on-page dialog that gives your connected accounts information about what data they’ll share, lets them find and select their financial institution, and lets them securely log in to their account to verify access. By default your connected accounts can only add a checking or savings account in the authentication flow because Stripe can only facilitate payouts to an account enabled for ACH. Manual entry of account and routing number is also available if your connected account can’t find their institution or authenticate their account. The manual entry flow might look like the following: ![Authentication flow with manual entry fallback](https://b.stripecdn.com/docs-statics-srv/assets/manual_fallback.c910f590ec792b6133bb88947332604c.png) If you want to prevent your connected account users from entering their bank account details manually, pass `payment_method_options[us_bank_account][verification_method]=instant` when creating the `SetupIntent`. ### Create an external account that you can use for payouts (Server-side) After you confirm the SetupIntent, use the attached Payment Method to create a Bank Account Token, then use the Token to create an external payout account. First, create a bank account token. ```curl curl https://api.stripe.com/v1/tokens \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d "bank_account[payment_method]"="{{PAYMENTMETHOD_ID}}" \ -d customer="{{CUSTOMER_ID}}" ``` Then use the token’s ID to create an external payout account. ```curl curl https://api.stripe.com/v1/accounts/{{ACCOUNT_ID}} \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d external_account="{{TOKEN_ID}}" ``` By default, providing an external account sets it as the new default external account for its currency, and deletes the old default account, if one exists. You’re now ready to send payouts to your connected account. For more details on how to create and manage an external account for payouts, see [create external bank account](https://docs.stripe.com/api/external_account_bank_accounts/create.md). ### Retrieve data on a Financial Connections account (Server-side) You can determine if your user linked a Financial Connections Account by retrieving the SetupIntent with the `payment_method` property expanded. ```curl curl -G https://api.stripe.com/v1/setup_intents/{{SETUP_INTENT_ID}} \ -u "<>:" \ -d "expand[]"=payment_method ``` Which will return an API response similar to the following: ```javascript { "id": "{{SETUP_INTENT_ID}}", "object": "setup_intent", // ... "payment_method": { "id": "{{PAYMENT_METHOD_ID}}", "object": "payment_method", // ... "type": "us_bank_account", "us_bank_account": { // ... // the value of "financial_connections_account" may be null "financial_connections_account": "{{FINANCIAL_CONNECTIONS_ACCOUNT_ID}}", // ... } }, // ... } ``` If the `payment_method` object’s `us_bank_account` object for the SetupIntent includes a `financial_connections_account` property, then your user linked a Financial Connections Account. You can use the `financial_connections_account` value to access or refresh the data you specified in the SetupIntent’s `payment_method_options[us_bank_account][financial_connections][permissions]` parameter. To protect the privacy of your user’s data, account data accessible to you is limited to the data you specified in this parameter. Follow the guides for [balances](https://docs.stripe.com/financial-connections/balances.md), [ownership](https://docs.stripe.com/financial-connections/ownership.md), and [transactions](https://docs.stripe.com/financial-connections/transactions.md) data to start retrieving account data. ### (Optional) Use the Payment Method to process payments You won’t be able to use a PaymentMethod collected using the above integration to process payments using PaymentIntents, because the SetupIntent is only requesting `"outbound"` permission, and you haven’t obtained authorization from your user by displaying a [mandate](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md#web-collect-mandate-and-submit). If you’d like to allow your user to use the same account to make payments and receive payouts, 1. Remove the `flow_directions` parameter from the Create Setup Intent API call. 1. Collect a [mandate](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md#web-collect-mandate-and-submit) from your user. See the [ACH Direct Debit guide](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md) for additional details. This integration pattern triggers microdeposit verification if your user provides their bank account details using the manual entry form. #### iOS ## Include additional dependency for Financial Connections(Client-side) The [Stripe iOS SDK](https://github.com/stripe/stripe-ios) is open source, [fully documented](https://stripe.dev/stripe-ios/index.html), and compatible with apps supporting iOS 13 or above. #### Swift Package Manager To install the SDK, follow these steps: 1. In Xcode, select **File** > **Add Package Dependencies…** and enter `https://github.com/stripe/stripe-ios-spm` as the repository URL. 1. Select the latest version number from our [releases page](https://github.com/stripe/stripe-ios/releases). 1. Add the **StripeFinancialConnections** product to the [target of your app](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app). #### CocoaPods 1. If you haven’t already, install the latest version of [CocoaPods](https://guides.cocoapods.org/using/getting-started.html). 1. If you don’t have an existing [Podfile](https://guides.cocoapods.org/syntax/podfile.html), run the following command to create one: ```bash pod init ``` 1. Add this line to your `Podfile`: ```podfile pod 'StripeFinancialConnections' ``` 1. Run the following command: ```bash pod install ``` 1. Don’t forget to use the `.xcworkspace` file to open your project in Xcode, instead of the `.xcodeproj` file, from here on out. 1. In the future, to update to the latest version of the SDK, run: ```bash pod update StripeFinancialConnections ``` #### Carthage 1. If you haven’t already, install the latest version of [Carthage](https://github.com/Carthage/Carthage#installing-carthage). 1. Add this line to your `Cartfile`: ```cartfile github "stripe/stripe-ios" ``` 1. Follow the [Carthage installation instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos). Make sure to embed all of the required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripeFinancialConnections/README.md#manual-linking). 1. In the future, to update to the latest version of the SDK, run the following command: ```bash carthage update stripe-ios --platform ios ``` #### Manual Framework 1. Head to our [GitHub releases page](https://github.com/stripe/stripe-ios/releases/latest) and download and unzip **Stripe.xcframework.zip**. 1. Drag **StripeFinancialConnections.xcframework** to the **Embedded Binaries** section of the **General** settings in your Xcode project. Make sure to select **Copy items if needed**. 1. Repeat step 2 for all required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripeFinancialConnections/README.md#manual-linking). 1. In the future, to update to the latest version of our SDK, repeat steps 1–3. > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-ios/releases) page on GitHub. To receive notifications when a new release is published, [watch releases](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository) for the repository. ## Set up a return URL (Client-side) The customer might navigate away from your app to authenticate (for example, in Safari or their banking app). To allow them to automatically return to your app after authenticating, [configure a custom URL scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) and set up your app delegate to forward the URL to the SDK. Stripe doesn’t support [universal links](https://developer.apple.com/documentation/xcode/allowing-apps-and-websites-to-link-to-your-content). #### SceneDelegate #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { guard let url = URLContexts.first?.url else { return } let stripeHandled = StripeAPI.handleURLCallback(with: url) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } } ``` #### AppDelegate #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { let stripeHandled = StripeAPI.handleURLCallback(with: url) if (stripeHandled) { return true } else { // This was not a Stripe url – handle the URL normally as you would } return false } ``` #### SwiftUI #### Swift ```swift @main struct MyApp: App { var body: some Scene { WindowGroup { Text("Hello, world!").onOpenURL { incomingURL in let stripeHandled = StripeAPI.handleURLCallback(with: incomingURL) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } } } } } ``` ## Collect payment method details (Client-side) Use the class function `collectUSBankAccountParams` in `STPCollectBankAccountParams` to create the parameters required to call `collectBankAccountForSetup`. You must provide your connected account user’s full name to collect an ACH Direct Debit `PaymentMethod`. Create an instance of `BankAccountCollector` to call `collectBankAccountForSetup` and collect bank account details, create a `PaymentMethod`, and attach that `PaymentMethod` to the `SetupIntent`. Pass the `SetupIntent`’s `client_secret`, your return URL, and the `STPCollectBankAccountParams` parameters to `collectBankAccountForSetup`. #### Swift ```swift // Build params let collectParams = STPCollectBankAccountParams.collectUSBankAccountParams(with: name, email: email) // Calling this method displays a dialog for collecting bank account information let bankAccountCollector = STPBankAccountCollector() bankAccountCollector.collectBankAccountForSetup(clientSecret: clientSecret, returnURL: "your-app://stripe-redirect", params: collectParams, from: self) { intent, error in guard let intent = intent else { // handle error return } if case .requiresPaymentMethod = intent.status { // Customer canceled the Financial Connections dialog. Present them with other // payment method type options. } else if case .requiresConfirmation = intent.status { // We collected an account - possibly instantly verified, but possibly // manually-entered. let setupIntentParams = STPSetupIntentConfirmParams(clientSecret: clientSecret, paymentMethodType: .USBankAccount) // Confirm the SetupIntent STPPaymentHandler.shared().confirmSetupIntent( setupIntentParams, with: self ) { (status, intent, error) in switch status { case .failed: // Setup failed case .canceled: // Setup was canceled case .succeeded: // Setup succeeded, Payment Method attached to the Customer // Your logic to create a payout account could go here @unknown default: fatalError() } } } } ``` This loads the [authentication flow](https://docs.stripe.com/financial-connections/fundamentals.md#authentication-flow), a dialog that gives your connected accounts information about what data they’ll share, lets them find and select their financial institution, and lets them securely log in to their account to verify access. `collectBankAccountForSetupWithClientSecret` completes with either the `SetupIntent` or an error. When it completes with a `SetupIntent` and its status is `requires_confirmation`, confirm the `SetupIntent` by calling `confirmSetupIntent` on the shared `STPPaymentHandler` instance. `confirmSetupIntent` completes with the same parameters as `collectBankAccountForSetupWithClientSecret`. On successful confirmation, the `SetupIntent` will have a status of `succeeded`. This means that you can use the `SetupIntent`’s `payment_method` to create a bank account token on your server. By default your connected accounts can only add a checking or savings account in the authentication flow because Stripe can only facilitate payouts to an ACH-enabled account. Manual entry of account and routing number is also available if your connected account can’t find their institution or authenticate their account. The manual entry flow might look like the following: ![Authentication flow with manual entry fallback](https://b.stripecdn.com/docs-statics-srv/assets/manual_fallback.c910f590ec792b6133bb88947332604c.png) If you want to prevent your connected account users from entering their bank account details manually, pass `payment_method_options[us_bank_account][verification_method]=instant` when creating the `SetupIntent`. ### Create an external account that you can use for payouts (Server-side) After you confirm the SetupIntent, use the attached Payment Method to create a Bank Account Token, then use the Token to create an external payout account. First, create a bank account token. ```curl curl https://api.stripe.com/v1/tokens \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d "bank_account[payment_method]"="{{PAYMENTMETHOD_ID}}" \ -d customer="{{CUSTOMER_ID}}" ``` Then use the token’s ID to create an external payout account. ```curl curl https://api.stripe.com/v1/accounts/{{ACCOUNT_ID}} \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d external_account="{{TOKEN_ID}}" ``` By default, providing an external account sets it as the new default external account for its currency, and deletes the old default account, if one exists. You’re now ready to send payouts to your connected account. For more details on how to create and manage an external account for payouts, see [create external bank account](https://docs.stripe.com/api/external_account_bank_accounts/create.md). ### Retrieve data on a Financial Connections account (Server-side) You can determine if your user linked a Financial Connections Account by retrieving the SetupIntent with the `payment_method` property expanded. ```curl curl -G https://api.stripe.com/v1/setup_intents/{{SETUP_INTENT_ID}} \ -u "<>:" \ -d "expand[]"=payment_method ``` Which will return an API response similar to the following: ```javascript { "id": "{{SETUP_INTENT_ID}}", "object": "setup_intent", // ... "payment_method": { "id": "{{PAYMENT_METHOD_ID}}", "object": "payment_method", // ... "type": "us_bank_account", "us_bank_account": { // ... // the value of "financial_connections_account" may be null "financial_connections_account": "{{FINANCIAL_CONNECTIONS_ACCOUNT_ID}}", // ... } }, // ... } ``` If the `payment_method` object’s `us_bank_account` object for the SetupIntent includes a `financial_connections_account` property, then your user linked a Financial Connections Account. You can use the `financial_connections_account` value to access or refresh the data you specified in the SetupIntent’s `payment_method_options[us_bank_account][financial_connections][permissions]` parameter. To protect the privacy of your user’s data, account data accessible to you is limited to the data you specified in this parameter. Follow the guides for [balances](https://docs.stripe.com/financial-connections/balances.md), [ownership](https://docs.stripe.com/financial-connections/ownership.md), and [transactions](https://docs.stripe.com/financial-connections/transactions.md) data to start retrieving account data. ### (Optional) Use the Payment Method to process payments You won’t be able to use a PaymentMethod collected using the above integration to process payments using PaymentIntents, because the SetupIntent is only requesting `"outbound"` permission, and you haven’t obtained authorization from your user by displaying a [mandate](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md#web-collect-mandate-and-submit). If you’d like to allow your user to use the same account to make payments and receive payouts, 1. Remove the `flow_directions` parameter from the Create Setup Intent API call. 1. Collect a [mandate](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md#web-collect-mandate-and-submit) from your user. See the [ACH Direct Debit guide](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md) for additional details. This integration pattern triggers microdeposit verification if your user provides their bank account details using the manual entry form. #### Android ## Include additional dependency for Financial Connections(Client-side) The [Stripe Android SDK](https://github.com/stripe/stripe-android) is open source and [fully documented](https://stripe.dev/stripe-android/). To install the SDK, add `financial-connections` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Financial Connections Android SDK implementation("com.stripe:financial-connections:23.0.2") } ``` > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). ## Collect payment method details (Client-side) Use `CollectBankAccountConfiguration.USBankAccount` to create the parameters required to call `presentWithSetupIntent`. You must provide your connected account user’s full name to collect an ACH Direct Debit `PaymentMethod`. Initialize a CollectBankAccountLauncher instance inside `onCreate` of your payout Activity, passing a method to handle the result. Then proceed to call `presentWithSetupIntent` to collect bank account details, create a `PaymentMethod`, and attach that `PaymentMethod` to the `SetupIntent`. #### Kotlin ```kotlin import androidx.appcompat.app.AppCompatActivity class PayoutActivity : AppCompatActivity() { private lateinit var setupIntentClientSecret: String private lateinit var collectBankAccountLauncher: CollectBankAccountLauncher private val paymentLauncher: PaymentLauncher = PaymentLauncher.Companion.create( this, "YOUR_PUBLISHABLE_KEY", null, ::onPaymentResult ) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Create collector collectBankAccountLauncher = CollectBankAccountLauncher.create( this ) { result: CollectBankAccountResult -> when (result) { is CollectBankAccountResult.Completed -> { val intent = result.response.intent if (intent.status == StripeIntent.Status.RequiresPaymentMethod) { // Customer canceled the Financial Connections dialog. Present them with other // payment method type options. } else if (intent.status == StripeIntent.Status.RequiresConfirmation) { // We collected an account - possibly instantly verified, but possibly // manually-entered. // Confirm the SetupIntent val confirmParams = ConfirmSetupIntentParams.create( clientSecret = setupIntentClientSecret, paymentMethodType = PaymentMethod.Type.USBankAccount ) paymentLauncher.confirm(confirmParams) } } is CollectBankAccountResult.Cancelled -> { // handle cancellation } is CollectBankAccountResult.Failed -> { // handle error print("Error: ${result.error}") } } } } fun collectPayoutAccount() { // ... // Build params val collectParams: CollectBankAccountConfiguration = CollectBankAccountConfiguration.USBankAccount( name, email ) // Calling this method triggers the Financial Connections dialog to be displayed collectBankAccountLauncher.presentWithSetupIntent( publishableKey, setupIntentClientSecret, collectParams ) } private fun onPaymentResult(paymentResult: PaymentResult) { when (paymentResult) { is PaymentResult.Completed -> { // Setup succeeded, Payment Method attached to the Customer // Your logic to create a payout account could go here } is PaymentResult.Canceled -> { // handle cancel flow } is PaymentResult.Failed -> { // handle failures } } } } ``` This loads the [authentication flow](https://docs.stripe.com/financial-connections/fundamentals.md#authentication-flow), a dialog that gives your connected accounts information about what data they’ll share, lets them find and select their financial institution, and lets them securely log in to their account to verify access. `CollectBankAccountLauncher` completes with a result object that contains either the `SetupIntent` or an error. When it completes with a `SetupIntent` and its status is `"requires_confirmation"`, confirm the `SetupIntent` using the `confirm` method on a `PaymentLauncher` instance. When it completes, `confirm` calls a configurable method with a [PaymentResult](https://stripe.dev/stripe-android/payments-core/com.stripe.android.payments.paymentlauncher/-payment-result/index.html?query=sealed%20class%20PaymentResult%20:%20Parcelable) object. On successful confirmation, the `PaymentResult` object is a `PaymentResult.Completed`. This means that you can use the `SetupIntent`’s `payment_method` to create a Bank Account Token on your server. By default your connected accounts can only add a checking or savings account in the authentication flow because Stripe can only facilitate payouts to an ACH-enabled account. Manual entry of account and routing number is also available if your connected account can’t find their institution or authenticate their account. The manual entry flow might look like the following: ![Authentication flow with manual entry fallback](https://b.stripecdn.com/docs-statics-srv/assets/manual_fallback.c910f590ec792b6133bb88947332604c.png) If you want to prevent your connected account users from entering their bank account details manually, pass `payment_method_options[us_bank_account][verification_method]=instant` when creating the `SetupIntent`. ### Create an external account that you can use for payouts (Server-side) After you confirm the SetupIntent, use the attached Payment Method to create a Bank Account Token, then use the Token to create an external payout account. First, create a bank account token. ```curl curl https://api.stripe.com/v1/tokens \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d "bank_account[payment_method]"="{{PAYMENTMETHOD_ID}}" \ -d customer="{{CUSTOMER_ID}}" ``` Then use the token’s ID to create an external payout account. ```curl curl https://api.stripe.com/v1/accounts/{{ACCOUNT_ID}} \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d external_account="{{TOKEN_ID}}" ``` By default, providing an external account sets it as the new default external account for its currency, and deletes the old default account, if one exists. You’re now ready to send payouts to your connected account. For more details on how to create and manage an external account for payouts, see [create external bank account](https://docs.stripe.com/api/external_account_bank_accounts/create.md). ### Retrieve data on a Financial Connections account (Server-side) You can determine if your user linked a Financial Connections Account by retrieving the SetupIntent with the `payment_method` property expanded. ```curl curl -G https://api.stripe.com/v1/setup_intents/{{SETUP_INTENT_ID}} \ -u "<>:" \ -d "expand[]"=payment_method ``` Which will return an API response similar to the following: ```javascript { "id": "{{SETUP_INTENT_ID}}", "object": "setup_intent", // ... "payment_method": { "id": "{{PAYMENT_METHOD_ID}}", "object": "payment_method", // ... "type": "us_bank_account", "us_bank_account": { // ... // the value of "financial_connections_account" may be null "financial_connections_account": "{{FINANCIAL_CONNECTIONS_ACCOUNT_ID}}", // ... } }, // ... } ``` If the `payment_method` object’s `us_bank_account` object for the SetupIntent includes a `financial_connections_account` property, then your user linked a Financial Connections Account. You can use the `financial_connections_account` value to access or refresh the data you specified in the SetupIntent’s `payment_method_options[us_bank_account][financial_connections][permissions]` parameter. To protect the privacy of your user’s data, account data accessible to you is limited to the data you specified in this parameter. Follow the guides for [balances](https://docs.stripe.com/financial-connections/balances.md), [ownership](https://docs.stripe.com/financial-connections/ownership.md), and [transactions](https://docs.stripe.com/financial-connections/transactions.md) data to start retrieving account data. ### (Optional) Use the Payment Method to process payments You won’t be able to use a PaymentMethod collected using the above integration to process payments using PaymentIntents, because the SetupIntent is only requesting `"outbound"` permission, and you haven’t obtained authorization from your user by displaying a [mandate](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md#web-collect-mandate-and-submit). If you’d like to allow your user to use the same account to make payments and receive payouts, 1. Remove the `flow_directions` parameter from the Create Setup Intent API call. 1. Collect a [mandate](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md#web-collect-mandate-and-submit) from your user. See the [ACH Direct Debit guide](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md) for additional details. This integration pattern triggers microdeposit verification if your user provides their bank account details using the manual entry form. #### React Native ## Collect payment method details (Client-side) Pass the `SetupIntent`’s `client_secret` and your connected account user’s full name to `collectBankAccountForSetup` to collect the Payment Method. ```javascript import {collectBankAccountForSetup, confirmSetup} from '@stripe/stripe-react-native'; export default function PayoutAccountCollectionButton() { // Get SetupIntent client secret, connected account user's full name, and email address. // in this example, from a custom hook. const {clientSecret, name, email} = useMyCustomState(); const handleCollectBankAccountPress = async (clientSecret) => { const {setupIntent, error} = await collectBankAccountForSetup( clientSecret, { paymentMethodType: 'USBankAccount', paymentMethodData: { billingDetails: { name, email } } }, ); if (error) { // Inform your connected account user that there was an error. } else if (setupIntent) { if (setupIntent.status === SetupIntents.Status.RequiresConfirmation) { // Your connected account user provided bank account details // Confirm the SetupIntent const {error: confirmError, setupIntent: confirmedSetupIntent} = await confirmSetup(clientSecret, { type: 'USBankAccount' }); if (confirmError) { // Unable to confirm the SetupIntent, inform your connected account user there was an error } else if (confirmedSetupIntent) { if (confirmedSetupIntent.status === SetupIntents.Status.Succeeded) { // Setup succeeded, Payment Method attached to the Customer // Your logic to create a payout account could go here } else { // Unable to confirm the SetupIntent, re-fetch the SetupIntent for details } } } else { // Connected account user didn't link an account or provide details manually } } }; return (