Accept an ACH Direct Debit payment
Build a custom payment form or use Stripe Checkout to accept payments with ACH Direct Debit.
Accepting ACH Direct Debit payments on your website consists of:
- Creating an object to track a payment
- Collecting payment method information with instant verifications enabled by Stripe Financial Connections
- Submitting the payment to Stripe for processing
- Verifying your customer’s bank account
注意
ACH Direct Debit is a delayed notification payment method, which means that funds aren’t immediately available after payment. A payment typically takes 4 business days to arrive in your account.
Stripe uses the payment object, the Payment Intent, to track and handle all the states of the payment until the payment completes.
Create or retrieve a customerRecommendedServer-side
Create a Customer object when your user creates an account with your business, or retrieve an existing Customer associated with this user. Associating the ID of the Customer object with your own internal representation of a customer enables you to retrieve and use the stored payment method details later. Include an email address on the Customer to enable Financial Connections’ return user optimization.
创建 PaymentIntent服务器端
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 a PaymentIntent on your server and specify the amount to collect and the usd currency. If you already have an integration using the Payment Intents API, add us_ to the list of payment method types for your PaymentIntent. Specify the id of the Customer.
If you want to reuse the payment method in the future, provide the setup_future_usage parameter with the value of off_.
By default, collecting bank account payment information uses Financial Connections to instantly verify your customer’s account, with a fallback option of manual account number entry and microdeposit verification. See the Financial Connections docs to learn how to configure Financial Connections and access additional account data to optimize your ACH integration. For example, you can use Financial Connections to check an account’s balance before initiating the ACH payment.
注意
To expand access to additional data after a customer authenticates their account, they must re-link their account with expanded permissions.
检索客户端私钥
PaymentIntent 中包含的是一个客户端私钥,用于在客户端安全地完成支付流程。有不同的方法可以将客户端私钥传递到客户端。
收集支付方式详情客户端
When a customer clicks to pay with ACH Direct Debit, we recommend you use Stripe.js to submit the payment to Stripe. Stripe.js is our foundational JavaScript library for building payment flows. It will automatically handle integration complexities, and enables you to easily extend your integration to other payment methods in the future.
在您的结账页面包含 Stripe.js 脚本,方法是将它添加到您的 HTML 文件的 head 部分。
<head> <title>Checkout</title> <script src="https://js.stripe.com/clover/stripe.js"></script> </head>
用下面的 JavaScript 在您的结账页面创建一个 Stripe.js 实例。
// Set your publishable key. Remember to change this to your live publishable key in production! // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe();'pk_test_TYooMQauvdEDq54NiTphI7jx'
Rather than sending the entire PaymentIntent object to the client, use its client secret from the previous step. This is different from your API keys that authenticate Stripe API requests.
Handle the client secret carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer.
Use stripe.collectBankAccountForPayment to collect bank account details with Financial Connections, create a PaymentMethod, and attach that PaymentMethod to the PaymentIntent. Including the account holder’s name in the billing_ parameter is required to create an ACH Direct Debit PaymentMethod.
// Use the form that already exists on the web page. const paymentMethodForm = document.getElementById('payment-method-form'); const confirmationForm = document.getElementById('confirmation-form'); paymentMethodForm.addEventListener('submit', (ev) => { ev.preventDefault(); const accountHolderNameField = document.getElementById('account-holder-name-field'); const emailField = document.getElementById('email-field'); // Calling this method will open the instant verification dialog. stripe.collectBankAccountForPayment({ clientSecret: clientSecret, params: { payment_method_type: 'us_bank_account', payment_method_data: { billing_details: { name: accountHolderNameField.value, email: emailField.value, }, }, }, expand: ['payment_method'], }) .then(({paymentIntent, error}) => { if (error) { console.error(error.message); // PaymentMethod collection failed for some reason. } else if (paymentIntent.status === 'requires_payment_method') { // Customer canceled the hosted verification modal. Present them with other // payment method type options. } else if (paymentIntent.status === 'requires_confirmation') { // We collected an account - possibly instantly verified, but possibly // manually-entered. Display payment method details and mandate text // to the customer and confirm the intent once they accept // the mandate. confirmationForm.show(); } }); });
The Financial Connections authentication flow automatically handles bank account details collection and verification. When your customer completes the authentication flow, the PaymentMethod automatically attaches to the PaymentIntent, and creates a Financial Connections Account.
常见错误
Bank accounts that your customers link through manual entry and microdeposits won’t have access to additional bank account data like balances, ownership, and transactions.
To provide the best user experience on all devices, set the viewport minimum-scale for your page to 1 using the viewport meta tag.
<meta name="viewport" content="width=device-width, minimum-scale=1" />
可选Access data on a Financial Connections bank account服务器端
You can only access Financial Connections data if you request additional data permissions when you create your PaymentIntent .
After your customer successfully completes the Stripe Financial Connections authentication flow, the us_ PaymentMethod returned includes a financial_connections_account ID that points to a Financial Connections Account. Use this ID to access account data.
常见错误
Bank accounts that your customers link through manual entry and microdeposits don’t have a financial_ ID on the Payment Method.
To determine the Financial Connections account ID, retrieve the PaymentIntent and expand the payment_ attribute:
{ "id": "{{PAYMENT_INTENT_ID}}", "object": "payment_intent", // ... "payment_method": { "id": "{{PAYMENT_METHOD_ID}}", // ... "type": "us_bank_account" "us_bank_account": { "account_holder_type": "individual", "account_type": "checking", "bank_name": "TEST BANK", "financial_connections_account": "{{FINANCIAL_CONNECTIONS_ACCOUNT_ID}}", "fingerprint": "q9qchffggRjlX2tb", "last4": "6789", "routing_number": "110000000" } } // ... }
If you opted to receive balances permissions, we recommend checking a balance at this stage to verify sufficient funds before confirming a payment.
Learn more about using additional account data to optimize your ACH integration with Financial Connections.
Collect mandate acknowledgement and submit the payment客户端
Before you can initiate the payment, you must obtain authorization from your customer by displaying mandate terms for them to accept.
To be compliant with Nacha rules, you must obtain authorization from your customer before you can initiate payment by displaying mandate terms for them to accept. For more information on mandates, see Mandates.
When the customer accepts the mandate terms, you must confirm the PaymentIntent. Use stripe.confirmUsBankAccountPayment to complete the payment when the customer submits the form.
confirmationForm.addEventListener('submit', (ev) => { ev.preventDefault(); stripe.confirmUsBankAccountPayment(clientSecret) .then(({paymentIntent, error}) => { if (error) { console.error(error.message); // The payment failed for some reason. } else if (paymentIntent.status === "requires_payment_method") { // Confirmation failed. Attempt again with a different payment method. } else if (paymentIntent.status === "processing") { // Confirmation succeeded! The account will be debited. // Display a message to customer. } else if (paymentIntent.next_action?.type === "verify_with_microdeposits") { // The account needs to be verified through microdeposits. // Display a message to consumer with next steps (consumer waits for // microdeposits, then enters a statement descriptor code on a page sent to them through email). } }); });
注意
stripe.confirmUsBankAccountPayment may take several seconds to complete. During that time, disable resubmittals of your form and show a waiting indicator (for example, a spinner). If you receive an error, show it to the customer, re-enable the form, and hide the waiting indicator.
If successful, Stripe returns a PaymentIntent object, with one of the following possible statuses:
| 状态 | 描述 | 后续步骤 |
|---|---|---|
requires_ | Further action is needed to complete bank account verification. | Step 6: Verifying bank accounts with microdeposits |
processing | The bank account was instantly verified or verification isn’t necessary. | Step 7: Confirm the PaymentIntent succeeded |
After successfully confirming the PaymentIntent, an email confirmation of the mandate and collected bank account details must be sent to your customer. Stripe handles these by default, but you can choose to send custom notifications if you prefer.
Verify bank account with microdeposits客户端
Not all customers can verify the bank account instantly. This step only applies if your customer has elected to opt out of the instant verification flow in the previous step.
In these cases, Stripe sends a descriptor_ microdeposit and might fall back to an amount microdeposit if any further issues arise with verifying the bank account. These deposits take 1-2 business days to appear on the customer’s online statement.
- Descriptor code. Stripe sends a single, 0.01 USD microdeposit to the customer’s bank account with a unique, 6-digit
descriptor_that starts with SM. Your customer uses this string to verify their bank account.code - Amount. Stripe sends two, non-unique microdeposits to the customer’s bank account, with a statement descriptor that reads
ACCTVERIFY. Your customer uses the deposit amounts to verify their bank account.
The result of the stripe.confirmUsBankAccountPayment method call in the previous step is a PaymentIntent in the requires_ state. The PaymentIntent contains a next_ field that contains some useful information for completing the verification.
next_action: { type: "verify_with_microdeposits", verify_with_microdeposits: { arrival_date: 1647586800, hosted_verification_url: "https://payments.stripe.com/…", microdeposit_type: "descriptor_code" } }
If you supplied a billing email, Stripe notifies your customer through this email when the deposits are expected to arrive. The email includes a link to a Stripe-hosted verification page where they can confirm the amounts of the deposits and complete verification.
警告
Verification attempts have a limit of ten failures for descriptor-based microdeposits and three for amount-based ones. If you exceed this limit, we can no longer verify the bank account. In addition, microdeposit verifications have a timeout of 10 days. If you can’t verify microdeposits in that time, the PaymentIntent reverts to requiring new payment method details. Clear messaging about what these microdeposits are and how you use them can help your customers avoid verification issues.
Optional: Send custom email notifications
Optionally, you can send custom email notifications to your customer. After you set up custom emails, you need to specify how the customer responds to the verification email. To do so, choose one of the following:
Use the Stripe-hosted verification page. To do this, use the
verify_URL in the next_action object to direct your customer to complete the verification process.with_ microdeposits[hosted_ verification_ url] If you prefer not to use the Stripe-hosted verification page, create a form on your site. Your customers then use this form to relay microdeposit amounts to you and verify the bank account using Stripe.js.
- At minimum, set up the form to handle the
descriptor codeparameter, which is a 6-digit string for verification purposes. - Stripe also recommends that you set your form to handle the
amountsparameter, as some banks your customers use may require it.
Integrations only pass in the
descriptor_orcode amounts. To determine which one your integration uses, check the value forverify_in thewith_ microdeposits[microdeposit_ type] next_object.action - At minimum, set up the form to handle the
stripe.verifyMicrodepositsForPayment(clientSecret, { // Provide either a descriptor_code OR amounts, not both descriptor_code: 'SMT86W', amounts: [32, 45], });
When the bank account is successfully verified, Stripe returns the PaymentIntent object with a status of processing, and sends a payment_intent.processing webhook event.
Verification can fail for several reasons. The failure may happen synchronously as a direct error response, or asynchronously through a payment_intent.payment_failed webhook event (shown in the following examples).
| Error Code | Synchronous or Asynchronous | 消息 | Status change |
|---|---|---|---|
payment_ | Synchronously, or asynchronously through webhook event | Microdeposits failed. Please check the account, institution and transit numbers provided | status is requires_, and last_ is set. |
payment_ | Synchronously | 提供的金额与发送到银行账户的金额不匹配。您还可以再尝试 {attempts_remaining} 次验证。 | Unchanged |
payment_ | Synchronously, or asynchronously through webhook event | Exceeded number of allowed verification attempts | status is requires_, and last_ is set. |
payment_ | Asynchronously through webhook event | Microdeposit timeout. Customer hasn’t verified their bank account within the required 10 day period. | status is requires_, and last_ is set. |
确认 PaymentIntent 成功服务器端
ACH Direct Debit is a delayed notification payment method. This means that it can take up to four business days to receive notification of the success or failure of a payment after you initiate a debit from your customer’s account.
The PaymentIntent you create initially has a status of processing. After the payment has succeeded, the PaymentIntent status is updated from processing to succeeded.
We recommend using webhooks to confirm the charge has succeeded and to notify the customer that the payment is complete. You can also view events on the Stripe Dashboard.
测试您的集成
了解如何使用 Financial Connections 进行即时验证来测试各种场景。
在沙盒中发送交易电子邮件
在您收集了银行账户详情并接受授权后,在沙盒中发送授权确认和微存款验证电子邮件。
如果您的域名是 {domain},并且您的用户名是 {username},请使用以下邮件格式发送测试交易邮件: {username}+test_email@{domain}。
例如,如果您的域名是 example.com,用户名是 info,则使用格式 info+test_email@example.com 来测试 ACH 直接借记支付。这种格式确保电子邮件路由正确。如果您不包含 +test_email 后缀,我们将不发送电子邮件。
常见错误
您需要激活您的 Stripe 账户后才能在测试时触发这些邮件。
测试账号
Stripe 提供了几个测试账号和相应的令牌,您可以用它们来确保您的手动输入银行账户的集成已经可以投入生产。
| 账号 | 令牌 | 路径号码 | 行为 |
|---|---|---|---|
000123456789 | pm_ | 110000000 | 付款成功。 |
000111111113 | pm_ | 110000000 | 付款因账户已关闭失败。 |
000000004954 | pm_ | 110000000 | 由于高欺诈风险,该支付被 Radar 阻止了。 |
000111111116 | pm_ | 110000000 | 付款因查无账户失败。 |
000222222227 | pm_ | 110000000 | 付款因资金不足失败。 |
000333333335 | pm_ | 110000000 | 付款因扣款未获授权失败。 |
000444444440 | pm_ | 110000000 | 付款因货币无效失败。 |
000666666661 | pm_ | 110000000 | 付款时未能发送微额存款。 |
000555555559 | pm_ | 110000000 | 这笔付款触发了争议。 |
000000000009 | pm_ | 110000000 | 支付会无限期地保持处理中。这对于测试 PaymentIntent 取消 很有用。 |
000777777771 | pm_ | 110000000 | 付款因支付金额导致账户超过每周支付限额失败了。 |
000888888885 | 110000000 | 付款失败是因为令牌化账户号已停用。 |
在测试交易完成之前,您需要验证所有付款能够自动成功或失败的测试账户。为此,请使用下面测试用的微存款金额或描述符代码。
测试微存款金额和描述符代码
要模拟不同的场景,请使用这些微存款金额_或_ 0.01 此描述符代码值。
| 微存款金额 | 0.01 描述代码的值 | 场景 |
|---|---|---|
32 和 45 | SM11AA | 模拟验证账户。 |
10 和 11 | SM33CC | 模拟次数超过允许的验证尝试次数。 |
40 和 41 | SM44DD | 模拟微存款超时。 |
测试结算行为
测试交易会即时结算并添加到您的可用测试余额中。该行为与真实模式不同,真实模式的交易可能需要数天才能结算到您的可用余额中。
可选Instant only verification服务器端
By default, US bank account payments allows your customers to use instant bank account verification or microdeposits. You can optionally require instant bank account verification only, using the verification_method parameter when you create the PaymentIntent.
This ensures that you don’t need to handle microdeposit verification. However, if instant verification fails, the PaymentIntent’s status is requires_, indicating a failure to instantly verify a bank account for your customer.
可选Microdeposit only verification服务器端
By default, US bank account payments allow your customers to use instant bank account verification or microdeposits. You can optionally require microdeposit verification only using the verification_method parameter when you create the PaymentIntent.
注意
If using a custom payment form, you must build your own UI to collect bank account details. If you disable Stripe microdeposit emails, you must build your own UI for your customer to confirm the microdeposit code or amount.
You must then collect your customer’s bank account with your own form and call stripe.confirmUsBankAccountPayment with those details to complete the PaymentIntent.
var form = document.getElementById('payment-form'); var accountholderName = document.getElementById('accountholder-name'); var email = document.getElementById('email'); var accountNumber = document.getElementById('account-number'); var routingNumber = document.getElementById('routing-number'); var accountHolderType= document.getElementById('account-holder-type'); var submitButton = document.getElementById('submit-button'); var clientSecret = submitButton.dataset.secret; form.addEventListener('submit', function(event) { event.preventDefault(); stripe.confirmUsBankAccountPayment(clientSecret, { payment_method: { billing_details: { name: accountholderName.value, email: email.value, }, us_bank_account: { account_number: accountNumber.value, routing_number: routingNumber.value, account_holder_type: accountHolderType.value, // 'individual' or 'company' }, }, }) .then(({paymentIntent, error}) => { if (error) { // Inform the customer that there was an error. console.log(error.message); } else { // Handle next step based on the intent's status. console.log("PaymentIntent ID: " + paymentIntent.id); console.log("PaymentIntent status: " + paymentIntent.status); } }); });
可选解决争议服务器端
Customers can generally dispute an ACH Direct Debit payment through their bank for up to 60 calendar days after a debit on a personal account, or up to 2 business days for a business account. In rare instances, a customer might be able to successfully dispute a debit payment outside these standard dispute timelines.
When a customer disputes a payment, Stripe sends a charge.dispute.closed webhook event, and the PaymentMethod authorization is revoked.
In rare situations, Stripe might receive an ACH failure from the bank after a PaymentIntent has transitioned to succeeded. If this happens, Stripe creates a dispute with a reason of:
insufficient_funds incorrect_account_ details bank_can't_ process
Stripe charges a failure fee in this situation.
Future payments reusing this PaymentMethod return the following error:
{ "error": { "message": "This PaymentIntent requires a mandate, but no existing mandate was found. Collect mandate acceptance from the customer and try again, providing acceptance data in the mandate_data parameter.", "payment_intent": { ... } "type": "invalid_request_error" } }
This error contains a PaymentIntent in the requires_ state. To continue with the payment, you must:
- Resolve the dispute with the customer to ensure future payments will not be disputed.
- Confirm authorization from your customer again.
To confirm authorization for the payment, you can collect mandate acknowledgement from your customer online with Stripe.js or confirm authorization with your customer offline using the Stripe API.
注意
If a customer disputes more than one payment from the same bank account, Stripe blocks their bank account. Contact Stripe Support for further resolution.
可选支付参考
The payment reference number is a bank-generated value that allows the bank account owner to use their bank to locate funds. When the payment succeeds, Stripe provides the payment reference number in the Dashboard and inside the Charge object.
| Charge State | Payment Reference Value |
|---|---|
| 待处理 | 不可用 |
| 失败 | 不可用 |
| 成功 | Available (for example, 091000015001234) |
In addition, when you receive the charge. webhook, view the content of payment_ to locate the payment_reference.
The following example event shows the rendering of a successful ACH payment with a payment reference number.
{ "id": "{{EVENT_ID}}", "object": "event", // omitted some fields in the example "type": "charge.succeeded", "data": { "object": { "id": "{{PAYMENT_ID}}", "object": "charge", //... "paid": true, "payment_intent": "{{PAYMENT_INTENT_ID}}", "payment_method": "{{PAYMENT_METHOD_ID}}", "payment_method_details": { "type": "us_bank_account", "us_bank_account": { "account_holder_type": "individual", "account_type": "checking", "bank_name": "TEST BANK", "fingerprint": "Ih3foEnRvLXShyfB", "last4": "1000", "payment_reference": "091000015001234", "routing_number": "110000000" } } // ... } } }
View the contents of the destination_ to locate the refund reference associated with the refunded ACH payments.
The following example event shows the rendering of a successful ACH refund with a refund reference number. Learn more about refunds.
{ "id": "{{EVENT_ID}}", "object": "event", "type": "charge.refund.updated", "data": { "object": { "id": "{{REFUND_ID}}", "object": "refund", //... "payment_intent": "{{PAYMENT_INTENT_ID}}", "destination_details": { "type": "us_bank_transfer", "us_bank_transfer": { "reference": "091000015001111", "reference_status": "available" } } // ... } } }
可选Configure customer debit date服务器端
You can control the date that Stripe debits a customer’s bank account using the target date. The target date must be at least three days in the future and no more than 15 days from the current date.
The target date schedules money to leave the customer’s account on the target date. You can cancel a PaymentIntent created with a target date up to three business days before the configured date.
Target dates that meet one of the following criteria delay the debit until next available business day:
- Target date falls on a weekend, a bank holiday, or other non-business day.
- Target date is fewer than three business days in the future.
This parameter operates on a best-effort basis. Each customer’s bank might process debits on different dates, depending on local bank holidays or other reasons.