Stripe ACH Direct Debit lets you pull payments from a customer's US bank account using the `us_bank_account` payment method. The customer accepts a mandate, Stripe verifies the account instantly through Financial Connections or with a microdeposit, and the payment then sits in `processing` for up to four business days before it succeeds or fails. Returns and disputes can still arrive after that.

This guide is for engineers and product owners building bank debits on Stripe. It explains how the payment moves, how the two verification paths differ, what a mandate has to say, how long settlement takes, which webhook events to build on, what the common ACH return codes mean, how disputes and refunds behave, and how to test every failure path before going live. Everything Stripe-specific was checked against Stripe's ACH Direct Debit documentation in October 2026; where a rule depends on your account, your country or Nacha's rules, we say so. For the wider integration choices (Checkout vs PaymentIntents, keys, idempotency), start with our Stripe integration guide; this article goes deep on the bank-debit part only.

How does ACH Direct Debit work on Stripe?

ACH Direct Debit is a reusable, delayed-notification payment method: you learn whether a debit succeeded only after the bank network responds, which Stripe says can take up to four business days. Until then the PaymentIntent is `processing`, and your system must treat the money as expected, not received.

Stripe's documentation lists three things that make bank debits different from cards. The customer must authorize the payment terms (the mandate). The bank account must be verified. And the PaymentMethod's `billing_details` must include the account holder's name, plus a full address when the merchant of record is outside the US. Customers must be in the US and the presentment currency is USD; Stripe's documented minimum is 0.50 USD. Stripe accounts in the US and in a long list of European countries can accept these payments, with Canada in private preview at the time of writing.

The lifecycle, in the order your code sees it, looks like this:

  1. Collect and verify. You create a PaymentIntent (or SetupIntent) that allows `us_bank_account`. Stripe.js or a Stripe-hosted page opens the Financial Connections flow; if the customer cannot sign in to their bank, they can type the numbers and verify with a microdeposit.
  2. Mandate. The customer accepts mandate terms. Stripe-hosted surfaces show the wording and record acceptance; a custom form must show it before confirmation.
  3. Confirm. After confirmation the PaymentIntent moves to `processing` (instant verification) or `requires_action` (waiting for microdeposits).
  4. Outcome. Days later, Stripe sends `payment_intent.succeeded` or `payment_intent.payment_failed`. The charge-level events `charge.pending`, `charge.updated`, `charge.succeeded` and `charge.failed` track the same journey in more detail.
  5. After success. Funds become available in your Stripe balance and are paid out on your payout schedule. A late return or a dispute can still reverse the payment later, and Stripe surfaces it as a dispute.
The happy path runs down the left. Either branch on the right can arrive after you thought the payment was settled, so the order record must be able to move backwards.

Stripe also offers Instant Bank Payments, available only through Link, which confirm instantly and, per Stripe's comparison table, carry Stripe's guarantee on bank-initiated returns. ACH Direct Debit is the slower option Stripe describes as popular for large or recurring transactions.

Stripe Financial Connections vs microdeposits: how is a bank account verified?

Stripe verifies a US bank account in one of two ways: instantly, when the customer signs in to their bank through Stripe Financial Connections, or with microdeposits, when the customer types the routing and account numbers by hand. Financial Connections with a microdeposit fallback is the default.

You control this with `payment_method_options.us_bank_account.verification_method`, which Stripe documents on PaymentIntents, SetupIntents, Checkout Sessions, Invoices, Subscriptions and the Payment Element. The three values are `automatic` (Financial Connections with manual entry and microdeposits as a fallback), `instant` (Financial Connections only) and `microdeposits` (manual entry only).

Instant verification with Financial Connections

In the instant path, the customer authenticates with their bank inside a Stripe-hosted modal (a redirect on mobile). The resulting PaymentMethod carries a `financial_connections_account` ID that points to a Financial Connections Account. With the right permissions requested up front, that account can expose balances, ownership and transactions as well as the tokenized account and routing numbers needed for the debit. Stripe's Financial Connections guide for ACH lists what each is for: balances to reduce insufficient-funds failures, ownership to compare against your own records and catch potential fraud, and transactions to see when the customer's income usually lands.

Three details matter in practice. First, additional data needs a submitted and approved Financial Connections application in your Dashboard before it works in live mode. Second, permissions are fixed at collection time: Stripe notes that to expand access later, the customer has to re-link the account. Third, all data retrieval is asynchronous. You either `prefetch` balances when the account is linked or call the Refresh API later, wait for `financial_connections.account.refreshed_balance`, then read the balance. Stripe also warns that some institutions return only a current balance, a balance up to 24 hours old, or nothing at all.

Microdeposit verification

When a customer enters numbers manually, confirmation returns `requires_action` with `next_action.type` set to `verify_with_microdeposits`. Stripe normally sends a single 0.01 USD deposit whose statement descriptor contains a 6-digit code starting with SM, and may fall back to two small deposits under the descriptor ACCTVERIFY if that fails. The deposits take 1-2 business days to appear. If you supplied a billing email, Stripe emails the customer a link to a hosted verification page; otherwise you send them `hosted_verification_url` or build your own form with `stripe.verifyMicrodepositsForPayment`.

The limits are strict. Stripe allows ten failed attempts for descriptor codes and three for amounts, and verification times out after 10 days, at which point the intent returns to `requires_payment_method`. Manually entered accounts also never get a `financial_connections_account`, so none of the balance or ownership checks are available for them.

Both paths end in a verified account, but on very different clocks. The left token finishes in one session; the right one waits for the bank.

Which verification method should you choose?

  • Use `automatic` for most consumer and small-business flows. It keeps conversion for customers whose bank is not supported or who will not sign in, at the cost of a slower, leakier path for those customers.
  • Use `instant` when you need data before the first debit, for example a balance check on large amounts, or when you cannot wait days for verification. Customers who cannot link a bank simply cannot pay this way, so offer another method.
  • Use `microdeposits` rarely, typically for customers whose institutions do not support Financial Connections and where your own form is required. You must then build the collection form and, if you turn off Stripe's emails, the verification form too.
  • Measure the fallback. Track how many customers enter `requires_action` and how many finish within 10 days. A large drop-off there is a product problem, not a payments one.

What does an ACH debit authorization need to say?

An ACH debit authorization (Stripe calls it a mandate) is the customer's permission for your business to debit their account on agreed terms. Stripe-hosted surfaces show the wording and record acceptance for you; if you confirm PaymentIntents from your own form, you must display the mandate text before confirming.

Stripe stores the authorization against the PaymentMethod and records the business name, whether it is one-time or recurring, and the date and method of acceptance, including IP address, user agent and timestamp for online flows. Checkout, the Payment Element and the hosted invoice page display the mandate automatically. A custom form needs to show it only the first time you collect the account. Stripe's documentation gives recommended text, which says in substance that the customer authorizes your business to debit the account for amounts owed under your terms until revoked, with 30 days' notice to amend or cancel. If you will debit again later through `setup_future_usage` or a saved account, Stripe gives a second paragraph to add, covering periodic debits.

Further obligations from Stripe's mandate section:

  • Disclose how recurring amounts are calculated, or a range the customer can anticipate, when you originate recurring pre-authorized debits.
  • Give at least 7 calendar days' notice if you change the timing of recurring pre-authorized debits.
  • Send the customer a copy of the mandate. To comply with Nacha rules, each customer must receive an electronic or paper copy. Stripe emails a confirmation by default when it has a billing email; if you switch those emails off, you must send your own confirmation with the authorization date, account holder name, institution, routing number and last four digits, and also take over microdeposit reminder emails.
  • Handle revocation. Customers can revoke a mandate by contacting you. Stripe's guidance is to cancel pending payments tied to it and detach the PaymentMethod. Debits after cancellation fail.

Stripe also supports offline mandates, given in writing or by phone, and the API accepts `mandate_data[customer_acceptance][type]=offline` when re-confirming after a dispute. Keep that evidence where support can find it: with custom mandates, you must upload proof of authorization if a customer's bank asks.

How long does a Stripe ACH payment take to settle?

Standard settlement for Stripe ACH Direct Debit is four business days from payment creation (T+4), with a 21:00 US Eastern cutoff. Eligible US accounts can switch on faster settlement, two business days (T+2) with a 14:00 Eastern cutoff, from the payment method settings in the Dashboard.

Once a payment settles to your Stripe balance, payouts to your bank follow your normal payout schedule, so cash in your bank lands later than settlement. Stripe exposes an estimated debit date as `payment_method_details.us_bank_account.expected_debit_date` on the Charge, in API responses and in `charge.updated`, `charge.succeeded` and `charge.failed` events when it can be determined; it is explicitly an estimate. Stripe also notes that first payments from some bank accounts linked with temporary (tokenized) account numbers may settle more slowly.

Illustrative settlement windows from Stripe's documented timings. A Friday-evening payment under T+4 does not settle until the following Thursday or later, before any payout delay.

You can also schedule a debit. `payment_method_options.us_bank_account.target_date` sets the day money should leave the customer's account; Stripe requires it to be at least three days and no more than 15 days ahead, moves weekends and holidays to the next business day, and lets you cancel up to three business days before the date. The intent goes to `processing` as soon as you confirm. Stripe calls this best effort, because each bank posts on its own calendar.

For Connect platforms, who controls settlement speed depends on account type and charge type: the platform for Express and Custom accounts, and for Standard accounts it depends on platform controls and charge type, as Stripe's table sets out. Our guide to direct vs destination charges explains those charge types; for ACH the charge type also decides whose name appears on the mandate, the confirmation emails and the customer's bank statement.

How do you build Stripe US bank account payments with PaymentIntents?

Create a PaymentIntent on the server that allows `us_bank_account`, collect and verify the account in the browser with Stripe.js, show the mandate and confirm, then drive every downstream action from webhooks, never from the browser's return. Saved accounts can be debited later by confirming a new PaymentIntent with the stored PaymentMethod.

If you can use Checkout or the Payment Element, do: they handle the bank sign-in, the microdeposit fallback, the mandate text and its recording. Build on the lower-level calls when you need your own UI. In the browser that means `stripe.collectBankAccountForPayment` to open Financial Connections and attach the PaymentMethod, then, after the customer accepts your mandate text, `stripe.confirmUsBankAccountPayment`. The status that comes back is `processing`, `requires_action` for microdeposits, or `requires_payment_method` if the customer backed out.

The server side is short. The first function below creates the PaymentIntent for a first, on-session payment, saving the account and mandate for future use and requesting balance data. When you pass `payment_method_types` explicitly, Stripe's Financial Connections guide says you must list the permissions in every call. The second function debits a saved account later, after two pre-flight checks: a blocked-account flag and, where you have it, an available balance. Amounts and IDs are illustrative.

Create an ACH PaymentIntent and debit a saved bank account (Node.js)
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

// 1) First payment, customer on session: collect, verify and mandate the account.
export async function createAchPaymentIntent({ customerId, amountCents, orderId }) {
  return stripe.paymentIntents.create(
    {
      amount: amountCents, // USD cents; Stripe's ACH minimum is 0.50 USD
      currency: "usd",
      customer: customerId,
      payment_method_types: ["us_bank_account"],
      setup_future_usage: "off_session", // save the account and mandate for later debits
      payment_method_options: {
        us_bank_account: {
          verification_method: "automatic", // instant first, microdeposit fallback
          financial_connections: {
            // payment_method is needed for the debit; balances needs Stripe's approval
            permissions: ["payment_method", "balances"],
            prefetch: ["balances"],
          },
        },
      },
      metadata: { order_id: orderId },
    },
    { idempotencyKey: "ach-pi-" + orderId },
  );
}

// 2) A later debit against the saved, mandated account.
export async function debitSavedAccount({ customerId, paymentMethodId, amountCents, invoiceRef }) {
  const pm = await stripe.paymentMethods.retrieve(paymentMethodId);
  if (pm.us_bank_account?.status_details?.blocked) {
    return { skipped: true, reason: "blocked_account" }; // talk to the customer first
  }

  const fcaId = pm.us_bank_account?.financial_connections_account; // null for manual entry
  if (fcaId) {
    const account = await stripe.financialConnections.accounts.retrieve(fcaId);
    const available = account.balance?.cash?.available?.usd; // may be stale or missing
    if (typeof available === "number" && available < amountCents) {
      return { skipped: true, reason: "low_available_balance" }; // your policy decides
    }
  }

  return stripe.paymentIntents.create(
    {
      amount: amountCents,
      currency: "usd",
      customer: customerId,
      payment_method: paymentMethodId,
      payment_method_types: ["us_bank_account"],
      confirm: true,
      metadata: { invoice_ref: invoiceRef },
    },
    { idempotencyKey: "ach-debit-" + invoiceRef },
  );
}

Some notes on that code. The balance read uses whatever the last refresh returned; for a large debit, trigger a refresh first and act on `financial_connections.account.refreshed_balance`. The available-balance check is a policy input, not a guarantee, because other debits can land before yours. The idempotency key ties each debit to one invoice, so a retried request cannot create a second debit; our webhooks and idempotency guide covers that pattern in depth. And a blocked account is a reason to contact the customer, not to try a different amount.

Which webhook events matter for ACH?

Stripe documents `payment_intent.processing`, `payment_intent.succeeded` and `payment_intent.payment_failed` as the core events, with charge events for detail; Stripe notes that once `charge.updated` arrives, the payment can no longer be cancelled. Add `charge.dispute.created` for disputes and late returns, and `payment_method.automatically_updated` for blocked accounts. The handler below verifies the signature, ignores duplicates and maps each event to an internal state.

Webhook handler for ACH payment, failure, dispute and block events (Node.js)
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export async function handleStripeWebhook(rawBody, signature, db) {
  const event = stripe.webhooks.constructEvent(
    rawBody,
    signature,
    process.env.STRIPE_WEBHOOK_SECRET,
  );
  if (await db.events.seen(event.id)) return; // Stripe can deliver an event more than once

  const obj = event.data.object;
  switch (event.type) {
    case "payment_intent.processing":
      // Submitted to the bank. Not paid yet: do not ship or release funds.
      await db.payments.mark(obj.id, "pending_bank");
      break;
    case "payment_intent.succeeded":
      // Funds arrived. A late return can still become a dispute afterwards.
      await db.payments.mark(obj.id, "paid");
      break;
    case "payment_intent.payment_failed": {
      // Includes failed debits and failed microdeposit verification.
      const code = obj.last_payment_error?.code ?? "unknown";
      await db.payments.mark(obj.id, "failed", { code });
      break;
    }
    case "charge.failed":
      // failure_code carries Stripe's decline code (for example insufficient_funds).
      await db.payments.noteFailure(obj.payment_intent, obj.failure_code);
      break;
    case "charge.dispute.created":
      // ACH disputes are final; the mandate on this payment method is now invalid.
      await db.payments.mark(obj.payment_intent, "disputed", { reason: obj.reason });
      await db.mandates.requireNew(obj.payment_intent);
      break;
    case "payment_method.automatically_updated": {
      // Sent when a blockable return blocks a saved account, and again when the block lifts.
      const blocked = obj.us_bank_account?.status_details?.blocked ?? null;
      await db.paymentMethods.setBlocked(obj.id, blocked);
      break;
    }
    default:
      break;
  }
  await db.events.record(event.id);
}

The most common ACH bug we see is fulfilling on the browser's success screen. For a bank debit, a successful confirmation only means the payment was submitted. If you use Checkout, the same trap applies to `checkout.session.completed`, which fires while the payment is still processing; our integration guide explains why delayed methods need `checkout.session.async_payment_succeeded` instead.

What are the common Stripe ACH return codes, and what should you do with each?

An ACH return is the customer's bank sending a debit back, with an R-code that says why. Stripe translates the raw code into a decline code on the failed payment, so your logic can branch on `insufficient_funds`, `bank_account_closed`, `debit_not_authorized` and the rest instead of parsing R-codes.

Stripe's network decline codes table maps the ACH codes as follows. R01 and R09 become `insufficient_funds`. R02 is `bank_account_closed`. R03 and R04 are `bank_account_invalid_details`. R05, R07, R08, R10, R11, R29 and R31 all become `debit_not_authorized`, meaning the payment lacks a valid mandate. R15 is `recipient_deceased`, R16 is `bank_account_frozen`, and R20 is `bank_account_restricted`, where the bank or the customer has blocked direct debits.

Group your handling by Stripe decline code, not by R-code. The red row is the one where retrying is the wrong move.

The decline code tells you which of three kinds of failure you are dealing with:

  • Funds problems (`insufficient_funds`). The account is fine; the money was not there. A later retry can succeed. Stripe does not block accounts for past insufficient-funds returns.
  • Account problems (`bank_account_closed`, `bank_account_invalid_details`, `bank_account_frozen`, `bank_account_restricted`). The same account will fail again. Ask for new details or for the customer to resolve it with their bank. Stripe may block the account until the issue is confirmed resolved.
  • Authorization problems (`debit_not_authorized`). The customer or their bank says the debit was not authorized. Do not retry. Contact the customer, and collect a new mandate before any further debit.

Returns can also arrive after a PaymentIntent has already moved to `succeeded`. In that case Stripe creates a dispute with a reason of `insufficient_funds`, `incorrect_account_details` or `bank_cannot_process`, removes the funds and charges a failure fee. Your ledger must be able to reverse a payment that was marked paid.

How do ACH disputes and refunds work on Stripe?

ACH disputes on Stripe are final: there is no evidence process to win the money back through the ACH network. Customers can generally dispute a debit for up to 60 calendar days on a personal account, or up to two business days on a business account. Refunds are full refunds only, asynchronous, and can be issued up to 180 days after the payment.

Disputes

Stripe notifies you of an ACH dispute by email, in the Dashboard and with `charge.dispute.created`. You cannot submit evidence to contest it, and Stripe does not refund the dispute fee. A dispute also invalidates the mandate on that PaymentMethod: to debit again, you must resolve things with the customer and collect a new authorization. If the same customer disputes a later payment, Stripe blocks the bank account from reuse. Rarely, a customer wins a dispute outside the standard windows; Stripe calls this a late return, and the banks decide the outcome.

There is one case where evidence matters. If the customer's bank asks for proof of authorization, Stripe raises an inquiry with status `warning_needs_response` and a deadline. With Stripe-hosted mandates, Stripe answers with the stored authorization itself. With custom mandates through the PaymentIntents API, you upload the mandate copy, and ideally a receipt and customer identity information, once, before the deadline. Miss it and the dispute is accepted.

Refunds

Stripe's ACH capability table lists full refunds as supported and partial refunds as not supported, with a 180-day submission window and up to three business days to complete. Refunds cannot be cancelled. They always go out as a separate credit to the customer's account, referencing the original statement descriptor rather than appearing as a reversal, so tell the customer it is coming. Stripe waits for the original payment to succeed before submitting the refund, and if a refund fails, the money returns to your balance and you must pay the customer some other way.

Refunds and disputes can collide. Issuing a refund does not stop a dispute, and if the customer's bank processes a dispute while your refund is in flight, the customer can be credited twice. Stripe's advice is to tell the customer you are refunding, and when, so they do not also go to their bank.

ACH risk and limits: Nacha return thresholds, blocked accounts and Radar

ACH risk sits in two places: Nacha's network rules, which set return-rate thresholds for every originator, and Stripe's own controls, which include blocking bank accounts after certain returns, Radar screening and account-level limits. Stay well under the thresholds by verifying accounts, writing clear mandates and using a recognizable statement descriptor.

Nacha sets the rules for the ACH Network. Its risk and enforcement rule summary describes three return-rate levels: 0.5 percent for unauthorized debit returns (R05, R07, R10, R29 and R51), 3.0 percent for administrative returns (R02, R03 and R04), and 15.0 percent for all debit returns, excluding RCK entries. Rates are measured over the preceding sixty days or two calendar months. The same summary is clear that an unauthorized debit cannot be fixed by sending it again; reinitiating needs a new authorization. Rules change, so check Nacha's current text rather than relying on any summary, including this one.

Stripe enforces part of this for you. According to Stripe's blocked bank accounts guide, when a debit is returned for reasons other than insufficient funds, Nacha rules require the originator to review the account before debiting again, so Stripe blocks the account until the issue is resolved. Blocked accounts fail confirmation with HTTP 402 and the `bank_account_unusable` error, the PaymentMethod shows `us_bank_account.status_details.blocked` with the raw `network_code` and a `reason`, and Stripe sends `payment_method.automatically_updated` for affected saved methods, and again when the block is lifted. Each reason has its own unblock route and paperwork, from a bank letter to a voided check.

Other controls to plan for:

  • Radar. Stripe says Radar evaluates ACH payments with models trained for ACH and may be on by default for supported payment methods. Stripe's test numbers include one that Radar blocks for high risk, so you can test the outcome.
  • Volume limits. Stripe's test data includes a failure for exceeding a weekly payment volume limit. Treat volume limits as something to confirm with Stripe for your account, not something to discover in production.
  • Bank auto-blocks. Some business accounts reject debits from unknown originators. Stripe suggests customers give their bank Stripe's ACH company IDs to allow the debits.
  • Statement descriptors. ACH descriptors are truncated to the first 16 alphanumeric characters. A name the customer does not recognize turns into an unauthorized-return claim.
  • Eligibility. Stripe may review your account after activation to confirm ACH eligibility, and lists extra restricted categories for some regions. Confirm your business model is supported before you build.

Can you use Stripe ACH Direct Debit for recurring billing?

Yes. Stripe lists recurring payments, Billing and Invoicing as supported for ACH Direct Debit. Save the account with a SetupIntent or with `setup_future_usage` on the first payment, make sure the mandate covers periodic debits, and design subscription access around a payment that stays `processing` for days.

Four things change compared with cards. First, the renewal invoice is not paid when it is finalized; it is paid when the debit succeeds, so decide what access the customer has in between. Most SaaS products keep access during processing and act only on failure. Second, Stripe Billing can retry failed Direct Debit payments caused by insufficient funds, a maximum of two times and within 40 days of the original attempt, once you enable Direct Debit retries; our guide to failed subscription payments and dunning covers how to design the access policy around retries. Third, the Customer Portal is not listed as a supported product for ACH Direct Debit, so plan how customers change their bank account. Fourth, your mandate must disclose how amounts are calculated or their range, and timing changes need seven days' notice.

To collect bank accounts on subscriptions or invoices, set `payment_settings.payment_method_options.us_bank_account` with the same `verification_method` and Financial Connections permissions used on intents. The events your billing system cares about are the invoice and subscription events covered in our subscription webhooks guide, with the ACH-specific events above layered on top. If you are moving existing ACH customers onto Stripe Billing, treat their mandates as part of the migration plan; our article on migrating subscriptions to Stripe Billing covers the cutover.

How do you test Stripe ACH payments before going live?

Use Stripe's test routing number 110000000 with its documented test account numbers to force each outcome, use the test microdeposit codes to simulate verification, and remember that test payments settle instantly, so your code must not depend on the delay to work correctly.

Stripe's ACH accept-a-payment guide publishes test account numbers, each with a matching PaymentMethod token, for every outcome you need: a successful debit (000123456789), a closed account (000111111113), no account found (000111111116), insufficient funds (000222222227), debits not authorized (000333333335), a dispute (000555555559), failed microdeposits (000666666661), a payment that stays processing indefinitely (000000000009), a Radar block (000000004954), the weekly volume limit (000777777771) and a deactivated tokenized account number (000888888885). Accounts entered manually must be verified before test payments complete: SM11AA (or amounts 32 and 45) verifies, SM33CC (10 and 11) exhausts the attempts, and SM44DD (40 and 41) simulates a timeout.

Two testing traps catch teams out. Test transactions settle instantly into your test balance, so a test run will never show you the multi-day `processing` window your UI and support team have to handle; drive that state deliberately with the always-processing account and cancel it. And mandate and microdeposit emails are sent in a sandbox only to addresses in the form `username+test_email@yourdomain`, after your account is set up.

Collecting MCA remittances or loan payments by ACH: what changes?

The mechanics in this guide are the same for a lender, but the obligations are not only Stripe's. Lenders, MCA funders and servicers that collect remittances by ACH debit are originators under Nacha's rules and must also meet their own contractual, state and federal obligations, which vary by product and state. This section is engineering context, not legal advice.

Several of Stripe's documented behaviors land differently on remittance collection. Debits against business accounts have a short standard dispute window, up to two business days, but a late return can still arrive. Daily or weekly remittances hit the insufficient-funds path more often than a monthly subscription does, and Nacha's limits on reinitiation apply to how you retry. Variable remittances need mandate language that discloses how amounts are calculated or their range, and timing changes need notice. If you reconcile remittances against a split of the merchant's receivables, the ledger must handle a debit that reverses days after it was marked collected.

Before you build on Stripe for this, confirm with Stripe that your business and use case are eligible, have counsel review the authorization language and collection practices, and decide who on your team monitors return rates. Engineering can make each debit traceable to its authorization, its outcome and the person who acted on it. Our article on lending operations automation for MCA funders and ISOs covers the surrounding workflow.

From here, this article is about Cevrynt

How Cevrynt's engineers build ACH Direct Debit on Stripe

Cevrynt is a Stripe partner, a member of the Stripe Partner Ecosystem, and our bank-debit work starts with the slow path: what your system does while a payment is processing, when it is returned and when it is disputed. Arindam Pradhan, our founder, is a Stripe Certified Professional (Implementation Architect), and Anupam Pradhan and Subhadip Giri are Stripe Certified Professionals (Payments Architect). We write the verification choice, mandate handling and payment states down with your team, then build the intents, webhook handlers and reconciliation in your own repository and Stripe account, tested against every failure case above in test mode.

Every Stripe project is scoped and priced in writing after a technical review. See the Stripe services overview, our Stripe Billing service if ACH sits under subscriptions, or the Stripe Connect service if you collect on behalf of sellers. To start, send us the details.

If you are a funder or ISO collecting remittances, our lending ops automation service builds on the CRM and tools you already use, with no migration project: statement parsing, deal intake, CRM and webhook automation, and document pipelines. Your team keeps the decisions and the legal responsibility for how you collect.