Financial Connections Fresh
Access your users' bank account data with their consent. Collect verified bank account information and retrieve balances, transactions, and ownership data.
How it works
- Your user initiates the bank account linking flow on your client
- Your server creates a Financial Connections Session
- You return the session's
client_secretto the client - The Stripe authentication UI launches via
collectFinancialConnectionsAccounts - The user consents to data sharing and links their bank account
- Stripe attaches
FinancialConnectionsAccountobjects to the session - You retrieve account data from your server
Authentication flow steps
| Step | Description |
|---|---|
| Give consent | User agrees to share requested data |
| Select institution | User selects from 5,000+ supported banks |
| Log into bank | User authenticates via OAuth or non-OAuth flow |
| Select accounts | User selects which accounts to link |
| Success | Authentication complete |
Supports web, iOS, Android, and mobile web views.
Create a Financial Connections Session
bash
curl https://api.stripe.com/v1/financial_connections/sessions \
-u "sk_test_YOUR_KEY:" \
-d "account_holder[type]=customer" \
-d "account_holder[customer]={{CUSTOMER_ID}}" \
-d "permissions[]=payment_method" \
-d "permissions[]=balances"Node.js:
javascript
const stripe = require('stripe')('sk_test_YOUR_KEY');
const session = await stripe.financialConnections.sessions.create({
account_holder: {
type: 'customer',
customer: 'cus_CUSTOMER_ID',
},
permissions: ['payment_method', 'balances'],
});
// Return session.client_secret to the frontendLaunch the authentication flow (client-side)
javascript
const stripe = Stripe('pk_test_YOUR_PUBLISHABLE_KEY');
const { financialConnectionsSession, error } = await stripe.collectFinancialConnectionsAccounts({
clientSecret: session.client_secret,
});
if (error) {
console.error(error.message);
} else {
const accounts = financialConnectionsSession.accounts;
// accounts is an array of linked FinancialConnectionsAccount objects
}Return user optimization
For return users who have previously linked accounts, create a Customer with their email before launching the flow. Stripe's Link integration allows users to reuse saved bank accounts across Stripe businesses in fewer steps:
bash
curl https://api.stripe.com/v1/customers \
-u "sk_test_YOUR_KEY:" \
-d email={{CUSTOMER_EMAIL}}Pass the customer ID in the account_holder when creating the session.
Data permissions
| Permission | Data available | Use cases |
|---|---|---|
payment_method | Tokenized account and routing number | ACH payments, payouts |
ownership | Account owner names and mailing addresses | Fraud prevention, KYC |
balances | Current and available balance | Lending, financial management |
transactions | Pending and posted transactions | PFM apps, lending underwriting |
Request only the permissions you need. Users can see which data types you've requested and must explicitly consent to each.
After collecting an account you always receive (without special permissions):
- Last four digits of account number
- Account category (checking, savings)
- Account nickname (if available)
Account numbers are tokenized by default. Full account numbers for off-Stripe ACH processing are available only to businesses that meet Stripe's risk and eligibility criteria.
Retrieve account data
After the authentication flow, retrieve data from your server:
bash
# List accounts attached to a session
curl https://api.stripe.com/v1/financial_connections/sessions/{{SESSION_ID}} \
-u "sk_test_YOUR_KEY:" \
-d "expand[]=accounts"
# Retrieve balances for a specific account
curl https://api.stripe.com/v1/financial_connections/accounts/{{ACCOUNT_ID}}/refresh \
-u "sk_test_YOUR_KEY:" \
-d "features[]=balances"
curl https://api.stripe.com/v1/financial_connections/accounts/{{ACCOUNT_ID}} \
-u "sk_test_YOUR_KEY:" \
-d "expand[]=balance"OAuth vs non-OAuth authentication
Stripe defaults to OAuth (bank-hosted) authentication when available:
| Method | Description |
|---|---|
| OAuth | User goes to bank's site/app, grants permission, bank redirects back. No credentials shared with Stripe. |
| Non-OAuth | User provides credentials directly to Stripe or a trusted partner. Used when OAuth is unavailable at the institution. |
Your integration doesn't need to treat OAuth and non-OAuth accounts differently.
FinancialConnectionsAccount object
| Field | Description |
|---|---|
id | Account ID (fca_...) |
category | cash, investment, credit, other |
subcategory | checking, savings, mortgage, credit_card, etc. |
status | active, inactive, disconnected |
balance | Current and available balance (if balances permission granted) |
ownership | Owner names and addresses (if ownership permission granted) |
last4 | Last 4 digits of account number |
institution_name | Name of the financial institution |
Payments integration
For ACH payments, Financial Connections is the recommended way to collect and verify bank account details. Integrate with Payment Intents or Setup Intents:
javascript
const paymentMethod = await stripe.paymentMethods.create({
type: 'us_bank_account',
us_bank_account: {
financial_connections_account: 'fca_ACCOUNT_ID',
},
});Or use the payment_method token returned from the authentication flow directly in your PaymentIntent.
Microdeposits fallback
For payments integrations, configure microdeposit fallback for users who can't complete instant verification:
javascript
const setupIntent = await stripe.setupIntents.create({
payment_method_types: ['us_bank_account'],
payment_method_options: {
us_bank_account: {
financial_connections: {
permissions: ['payment_method'],
},
verification_method: 'microdeposits', // fallback
},
},
});