Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Finance automation
Platforms and marketplaces
Money management
Developer tools
Get started
Payments
Finance automation
Get started
Payments
Finance automation
Platforms and marketplaces
Money management
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseManaged Payments
Use Payment Links
Build a checkout page
Build an advanced integration
Build an in-app integration
Payment methods
Add payment methods
    Overview
    Payment method integration options
    Manage default payment methods in the Dashboard
    Payment method types
    Cards
    Bank debits
    Bank redirects
    Bank transfers
      Accept a payment
      Customer balance
      Refunds
    Credit transfers (Sources)
    Buy now, pay later
    Real-time payments
    Vouchers
    Wallets
    Enable local payment methods by country
    Custom payment methods
Manage payment methods
Faster checkout with Link
Payment interfaces
Payment Links
Checkout
Web Elements
In-app Elements
Payment scenarios
Custom payment flows
Flexible acquiring
Orchestration
In-person payments
Terminal
Other Stripe products
Financial Connections
Crypto
Climate
HomePaymentsAdd payment methodsBank transfers

Accept a bank transfer

Use the Payment Intents API to accept bank transfer payments.

Copy page

The first time you accept a bank transfer payment from a customer, Stripe generates a virtual bank account for them, which you can then share with them directly. All future bank transfer payments from this customer get sent to this bank account. In some countries, Stripe also provides you with a unique transfer reference number that your customer should include with each transfer to make it easier to match the transfer against outstanding payments. Some countries have limits on the number of virtual bank account numbers that you can create for free.

You can find an overview of the common steps when accepting a bank transfer payment in the following sequence diagram:

Handling underpayments and overpayments

With bank transfer payments, it’s possible that the customer sends you more or less than the expected payment amount. If the customer sends too little, Stripe partially funds an open payment intent. Invoices won’t be partially funded and remain open until incoming funds cover the full invoice amount.

If the customer sends more than the expected amount, Stripe attempts to reconcile the incoming funds against an open payment and keep the remaining excess amount in the customer cash balance. You can find more details on how Stripe handles reconciliation in the reconciliation section of our documentation.

When a customer underpays:

When a customer overpays:

Handling multiple open payments or invoices

You might have multiple open payments or invoices which can be paid with a bank transfer. In the default setup, Stripe attempts to automatically reconcile the bank transfer by using information like the transfer’s reference code or the amount transferred.

You can disable automatic reconciliation and manually reconcile payments and invoices yourself. You can override the automatic reconciliation behavior on a per-customer basis by setting reconciliation mode to manual.

Set up Stripe
Server-side

First, you need a Stripe account. Register now.

Use our official libraries for access to the Stripe API from your application:

Command Line
Ruby
# Available as a gem sudo gem install stripe
Gemfile
Ruby
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Create or retrieve a Customer
Server-side

You must associate a Customer object to reconcile each bank transfer payment. If you have an existing Customer object, you can skip this step. Otherwise, create a new Customer object.

Command Line
cURL
curl -X POST https://api.stripe.com/v1/customers \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"

Create and confirm a PaymentIntent
Server-side

A PaymentIntent is an object that represents your intent to collect payment from a customer and tracks the lifecycle of the payment process through each stage. Create and confirm a PaymentIntent on the server, specifying the amount and currency you want to collect. You must also populate the customer parameter of the PaymentIntent creation request. Bank transfers aren’t available on PaymentIntents without a customer.

Before creating a Payment Intent, make sure to turn Bank transfer on in the payment methods settings page of your Dashboard.

Note

With Dynamic payment methods, Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow.

Command Line
cURL
curl https://api.stripe.com/v1/payment_intents \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d amount=1099 \ -d customer=
{{CUSTOMER_ID}}
\ -d currency=usd \ -d "automatic_payment_methods[enabled]"=true \ --data-urlencode return_url="https://example.com/return_url" \ -d "payment_method_data[type]"=customer_balance \ -d confirm=true

In the latest version of the API, specifying the automatic_payment_methods parameter is optional because Stripe enables its functionality by default.

If the customer already has a balance high enough to cover the payment amount, the PaymentIntent immediately succeeds with a succeeded status. Customers can accrue a balance when they accidentally overpay for a transaction—a common occurrence with bank transfers. You must reconcile customer balances within a certain period based on your location.

Instruct the customer to complete a bank transfer
Client-side

If the customer balance isn’t high enough to cover the request amount, the PaymentIntent shows a requires_action status. The response has a next_action field containing a type value of display_bank_transfer_instructions. The next_action[display_bank_transfer_instructions] hash contains information to display to your customer so that they can complete the bank transfer. To ensure fund settlements, instruct your customers to use the exact details provided, particularly for the account name and account number, if applicable.

Note

In live mode, Stripe supplies each customer with a unique set of bank transfer details. In contrast, Stripe offers invalid bank transfer details to all customers in testing environments. Unlike live mode, these invalid details might not always be unique.

FieldDescription
typeThe type of bank transfer to use. Type must be us_bank_transfer in the US.
referenceA unique reference code to identify the bank transfer. Instruct your customer to include this code in the reference field of their bank transfer.
amount_remainingThe remaining amount that needs to be transferred to complete the payment. Instruct your customer to transfer this amount. This might be different from the PaymentIntent amount if pre-existing funds in the customer balance were applied to the PaymentIntent or if your customer underpaid.
currencyThe currency for the remaining amount.
financial_addressesList of financial addresses for US bank accounts. Types include aba and swift. See below for details.
hosted_instructions_urlA link to a hosted page that guides your customer through completing the transfer.

aba hash

Example of an aba hash:

{ "aba": { "account_number": "111222333444", "bank_name": "Wells Fargo Bank, NA", "routing_number": "444555666" }, "supported_networks": [ "ach", "domestic_wire_us" ], "type": "aba" }
Field Values Description
typeabaThe type of financial address.
supported_networks
  • ach
  • domestic_wire_us
The list of networks supported by this address.
aba.account_number111222333444The ABA account number.
aba.routing_number444555666The ABA routing number.
aba.bank_nameWells Fargo Bank, NAThe name of the bank.

swift hash

Example of a swift hash:

{ "swift": { "account_number": "111222333444", "bank_name": "Wells Fargo Bank, NA", "swift_code": "AAAA-BB-CC-123" }, "supported_networks": [ "swift" ], "type": "swift" }
Field Values Description
typeswiftThe type of financial address.
supported_networks
  • swift
The list of networks supported by this address.
swift.account_number111222333444The SWIFT account number.
swift.swift_codeAAAA-BB-CC-123The SWIFT code.
swift.bank_nameWells Fargo Bank, NAThe name of the bank.

Settlement timing

After instructing your customer to initiate a transfer with their bank using the information you provide, it can take up to 5 days for the transfer to complete. The settlement timing depends on the banking rails that the transfer arrived through to Stripe:

  • ACH transfers arrive within 1-3 business days.
  • Domestic wire transfers (Fedwire) arrive on the same day (depending on whether the transfer is sent before the bank’s cut-off time).
  • International wire transfers (SWIFT) arrive within 1-5 business days.

Confirm the PaymentIntent succeeded

The PaymentIntent stays in a requires_action status until funds arrive in the bank account. When funds are ready, the PaymentIntent status updates from requires_action to succeeded.

You need to set up your webhook endpoint to start receiving the payment_intent.partially_funded event.

You can add a webhook from the Dashboard.

Alternatively, you can use the Webhook Endpoints API to start receiving the payment_intent.partially_funded event.

Stripe sends the following events during the payment funding flow when we update the PaymentIntent.

EventDescriptionNext steps
payment_intent.requires_actionSent during confirmation when the customer balance doesn’t have sufficient funds to reconcile the PaymentIntent, the PaymentIntent transitions to requires_action.Instruct your customer to send a bank transfer with the amount_remaining.
payment_intent.partially_fundedThe customer sent a bank transfer that was applied to the PaymentIntent, but wasn’t enough to complete the payment. This might happen because the customer transferred an insufficient amount (because of a mistaken underpayment or fees charged by their bank) or because a remaining customer balance was applied to this PaymentIntent. PaymentIntents that are partially funded aren’t reflected in your account balance until the payment is complete.Instruct your customer to send another bank transfer with the new amount_remaining to complete the payment. If you want to complete the payment with the partially applied funds, you can update the amount and confirm the PaymentIntent again.
payment_intent.succeededThe customer’s payment succeeded.Fulfill the goods or services that the customer purchased.

Caution

When you change the amount of a partially funded PaymentIntent, the funds are returned to the customer balance. If other PaymentIntents are open, Stripe funds those automatically. If the customer is configured for manual reconciliation, you need to apply the funds again.

We recommend using webhooks to confirm the charge has succeeded and to notify the customer that the payment is complete.

Sample code

Ruby
require 'json' # Using Sinatra post '/webhook' do payload = request.body.read event = nil begin event = Stripe::Event.construct_from( JSON.parse(payload, symbolize_names: true)

View pending payments in the Dashboard

You can view all pending bank transfer PaymentIntents in the Dashboard by applying the Waiting on funding filter to Status .

Test your integration

You can test your integration by simulating an incoming bank transfer using either the Dashboard or an HTTP request.

With the Dashboard

To simulate a bank transfer using the Dashboard in a sandbox, navigate to the customer’s page in the Dashboard. Under Payment methods, click Add and select Fund cash balance (test only).

With the Stripe API

You can make an API call to simulate a bank transfer.

Command Line
cURL
curl https://api.stripe.com/v1/test_helpers/customers/ic_xxxxxxxxx/fund_cash_balance \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d amount=1000 \ -d currency=usd \ -d reference=REF-4242

Handling temporary availability issues

The following error codes indicate temporary issues with the availability of the payment method:

CodeDescriptionHandling
payment_method_rate_limit_exceededToo many requests were made in quick succession for this payment method, which has stricter limits than the API-wide rate limits.These errors can persist for several API requests when many of your customers try to use the same payment method, such as during an ongoing sale on your website. In this case, ask your customers to choose a different payment method.

Caution

If you anticipate heavy usage in general or because of an upcoming event, contact us as soon as you know about it.

OptionalCollecting payment method options from your customer

OptionalSend payment instruction emails

Was this page helpful?
YesNo
Need help? Contact Support.
Join our early access program.
Check out our changelog.
Questions? Contact Sales.
LLM? Read llms.txt.
Powered by Markdoc