Stripe | Financial Infrastructure to Grow Your Revenue

Stripe | Financial Infrastructure to Grow Your Revenue

5282 articles

Migrating to new ACH Direct Debit APIs


Migrating to new ACH Direct Debit APIs

Learn why and how to migrate to new APIs.

Stripe is removing support for ACH Direct Debit using legacy integrations.

If you create legacy ACH Direct Debit payments, you must migrate to the Payment Intents API or Checkout Sessions API.

Feature comparison

Stripe’s new APIs offer features that aren’t available in legacy integrations:

FeatureLegacy IntegrationsPayment Intents API or Checkout Sessions API
Checkout supportNoYes
Payment Element supportNoYes
Dynamic payment method supportNoYes
Settlement speedT+6T+4 (T+2 when using faster settlement)
Instant bank account verificationOnly available through custom, third-party integrationsInstant verification with Financial Connections
Fraud preventionNoRadar for ACH Balance checks using Financial Connections Smart Retries
Supported countriesUSUS, EU and UK

Compare the Checkout Sessions and Payment Intents APIs

Stripe offers two new APIs to accept ACH Direct Debits payments: Payment Intents and Checkout Sessions APIs.

  • Checkout Sessions API: Supports common checkout workflows with built-in features that remove the need for custom code and is recommended for most developers.
  • Payment Intents API: A lower-level API for building your own checkout flow. It requires significantly more code and ongoing maintenance. We recommend Checkout Sessions for most integrations.

Learn more about the differences, and how to evaluate which is right for you.

Build an ACH Direct Debit integration

To build an ACH Direct Debit integration on Payment Intents or Checkout Sessions:

  1. Enable ACH Direct Debit in your Payment methods settings.
  2. To collect and use new payment methods, integrate with ACH on Payment Intents or Checkout Sessions.
  3. For bank accounts previously collected using the Tokens API, you can continue to use saved BankAccount objects as PaymentMethod objects with the Payment Intents API. For details, see Migrate existing bank accounts.
  4. Test your integration.
  5. Gradually migrate all payments using existing bank accounts to the Payment Intents or Checkout Sessions API.
  6. Remove your legacy integration.

Behavioural differences

Some features that exist in both APIs work differently. If you rely on any of the following behaviours, update your integration accordingly.

BehaviourLegacy IntegrationsPayment Intents or Checkout Sessions API
MandatesNot enforced by the API.Enforced by the API. Payments can’t be initiated without an active mandate. Mandates can become inactive, which renders the payment method unusable. This can occur when a customer disputes a payment, when certain payment failures occur, or when Stripe becomes aware that the payment method is no longer valid. For more information, see Blocked bank accounts. If you reuse bank accounts created with the Tokens API, you must first create mandates for them. See Migrate existing bank accounts.
Balance transactionsCreated when the charge is created. The Balance transaction object is present in the charge.pending event and the API response.Created when the payment is submitted to the banking partner. The Balance transaction object is present in the charge.updated event, but not the API response.
Payouts/TransfersFunds settle in source_type=bank_account.Funds settle in source_type=card, shared with cards and other payment methods. If you manually specify the balance type for payouts or Connect transfers, update your integration to use the new balance type. During migration, you receive one payout for each balance type until all new payments use the new API. For separate charges and transfers with source_transaction, wait for the charge.updated webhook before creating a transfer. Payout statement descriptors may differ between source_type=bank_account and source_type=card payouts.
MicrodepositsTwo microdeposits of random, small amounts for verification. No hosted verification UI.One 1¢ microdeposit with a descriptor code for verification. In rare cases, Stripe sends two microdeposits of random, small amounts instead. Stripe provides a hosted verification page and sends automatic reminder emails to customers. Customers must verify their bank account within 10 days. If they don’t verify in time, the PaymentIntent or SetupIntent reverts to requiring new payment method details.
EmailsStripe doesn’t send automatic emails.Stripe automatically emails customers a mandate confirmation when mandates are created. When a customer attempts to verify a bank account using microdeposits, Stripe emails customers with a link to a hosted verification page. You can disable Stripe emails and send custom notifications instead. For sample mandate text and required content, see Mandate and microdeposit emails.

Webhook differences

If you previously listened to Charge events, you might need to update your integration to listen to new event types. The following table shows how webhook events differ.

Old webhookNew webhook on CheckoutNew webhook on Payment IntentsSpecial instructions
charge.pendingpayment_intent.processingpayment_intent.processingIn legacy integrations, charge.pending includes balance transaction. In new integrations, the balance transaction isn’t available until the charge.updated event.
charge.updatedcharge.updatedcharge.updatedSent when the payment is submitted to the banking partner. Includes the balance transaction.
charge.succeededcheckout.session.completedpayment_intent.succeededThe charge.succeeded webhook is also sent, so you don’t have to update your integration to listen to the new webhook.
charge.failedNot applicable. The customer can re-attempt the payment on the same Checkout Session until it expires, at which point you receive a checkout.session.expired event.payment_intent.payment_failedThe charge.failed webhook is also sent, so you don’t have to update your integration to listen to the new webhook.
charge.dispute.createdcharge.dispute.createdcharge.dispute.createdNot applicable
Not applicablemandate.updatedmandate.updatedSent when a mandate becomes inactive.

Identify Legacy ACH Payments

On a Charge object, the payment_method_details.type property is ach_debit for the legacy integration and us_bank_account for the newer integration.

A legacy ACH payment is created when a legacy BankAccount is the payment source. This happens when:

  • You call the Create Charge API .
  • A Subscription or Invoice charges a customer whose default _ source is a legacy BankAccount, and no default _ payment _ method is set on the customer, subscription, or invoice.
  • You call the Payment Intents API with a payment _ method _ type of ach _ debit .
Last verified 2026-09-25

Is this helpful?