Introduction: The Hidden Risk in B2B Recurring Revenue
For digital agencies, B2B SaaS firms and managed service providers (MSPs), recurring retainers are the backbone of financial stability. Many of them pull those retainers by bank debit rather than card. In the US that means Automated Clearing House (ACH) debits. Canadian businesses use Pre-Authorized Debits (PADs).
The reason is cost. As of November 2026, Stripe’s published US pricing is 2.9% + 30¢ for online card payments and 0.8% (capped at $5) for ACH Direct Debit. On a $10,000 retainer, that is roughly $290 by card versus $5 by ACH. Rates vary by processor and contract, so check your own.
Card churn gets most of the attention in revenue operations because cards have visible expiration dates. The card networks also run account-updater services, such as Visa Account Updater and Mastercard Automatic Billing Updater, that refresh stored credentials in the background. Even these don’t catch everything: Stripe notes that some card details won’t be updated in time.
A bank account has no printed expiration date. A client can close an account, move treasury to a new bank after an acquisition, or tighten debit permissions without telling you. When that happens, the routing and account details in your billing system are stale.
Stale ACH details also fail slowly. A card decline arrives in seconds. Stripe says ACH Direct Debit can take up to four business days to confirm success or failure, and a debit can fail at any point after it is initiated. If a retainer payment is meant to fund domain, hosting, licence or ad-spend renewals, that delay can turn an administrative error into a service problem.
ACH vs. Card Processing: What Actually Differs
| Feature | Card payments | ACH debit |
|---|---|---|
| Confirmation | Approval or decline in seconds | Delayed. Stripe cites up to 4 business days to confirm success or failure |
| Credential expiry | Printed expiration date | None built in |
| Automated updates | Account-updater programs (not complete) | Receiving banks can send a Notification of Change (NOC) for some changes, such as bank mergers. A client opening a new account elsewhere sends no notice |
| Typical cost (Stripe, US) | 2.9% + 30¢ | 0.8%, capped at $5; $4 per failed debit; $15 per dispute; $1.50 per instant bank-account validation |
| Failure signal | Immediate decline code | Return code (R-code) sent back through the network |
1. Synchronous vs. asynchronous settlement
A card payment gets a response from the issuer almost immediately. That response is either an approval or a decline code, such as 05 (do not honor) or 54 (expired card).
An ACH debit is batched. Your Originating Depository Financial Institution (ODFI) submits the file to one of the network’s two operators, the Federal Reserve’s FedACH or The Clearing House’s Electronic Payments Network (EPN). The operator passes it to the client’s bank, the Receiving Depository Financial Institution (RDFI).
Same Day ACH exists, with three daily windows and a $1 million per-payment limit. Returns still arrive after the fact.
For most return reasons, including the account-data errors below, the RDFI must send the return by the opening of business on the second banking day after settlement. Unauthorized debits to consumer accounts can be returned for up to 60 calendar days. Business-to-business (CCD) debits have a much shorter window.
Provisional access adds a cash-flow risk. Stripe grants “instant provisional access” to ACH funds. If a payment fails after funds appear in your balance, Stripe immediately removes them.
2. Return codes tied to stale bank data
When a client’s banking details change without notice, these codes are the usual signals:
- R02 (Account Closed): The account was open but has since been closed.
- R03 (No Account / Unable to Locate Account): The receiving bank can’t match the account number to an open account.
- R04 (Invalid Account Number Structure): The number’s format is invalid for that institution.
- R29 (Corporate Customer Advises Not Authorized): A business account holder says a specific debit wasn’t authorized. For CCD debits this return must also arrive within two banking days. It can occur when a client’s bank applies ACH debit blocks or positive-pay filters and your company ID hasn’t been approved.
- R01 (Insufficient Funds): Not a stale-data error, but it often appears alongside the others in dunning logs. Stripe maps R01 and R09 to
insufficient_funds.
Stripe maps these codes to decline codes as follows:
| Network code | Stripe decline code |
|---|---|
| R02 | bank_account_closed |
| R03, R04 | bank_account_invalid_details |
| R05, R07, R08, R10, R11, R29, R31 | debit_not_authorized |
3. Notifications of Change: the quiet cousin of the return
Sometimes the receiving bank processes the debit but flags a correction by sending an NOC, which is a zero-dollar entry. The common change codes are:
- C01: incorrect account number
- C02: incorrect routing number, often after a merger or consolidation
- C03: both routing and account number incorrect
An RDFI that chooses to send an NOC must do so within two banking days of the original settlement date. The originator must apply the correction within six banking days of receiving it, or before sending another entry, whichever is later. Ask your processor or bank whether NOCs are applied automatically or land in a report someone must read.
Why Returns Matter Beyond One Late Payment
Don’t blindly retry administrative returns
Nacha treats R02, R03 and R04 as administrative returns. Originators shouldn’t resubmit these entries without first correcting the underlying problem. Stripe’s documentation states the same principle. When debits are returned for reasons other than insufficient funds, Nacha rules require originators to review and confirm the account, or take other action, before re-initiating. Stripe may block bank accounts after certain returns.
For billing logic, that means failed debits caused by closed or invalid accounts need a human or client-facing workflow, not a retry timer. Stripe’s automatic Direct Debit retries cover insufficient-funds failures only, at most twice within 40 days.
Return-rate thresholds
Nacha monitors originators’ return rates against three levels:
| Measure | Return codes | Threshold |
|---|---|---|
| Unauthorized return rate | R05, R07, R10, R11, R29, R51 | 0.5% |
| Administrative return rate | R02, R03, R04 | 3% |
| Overall return rate | All debit returns (excluding RCK) | 15% |
Exceeding the unauthorized threshold is itself a rules violation. The 3% and 15% figures are levels that can trigger an inquiry. ODFIs enforce these thresholds and sometimes set stricter ones. For a small agency with a few dozen clients, one stale account can make percentages look high, so check how your bank or processor treats small volumes.
Anatomy of an Operational Failure (Illustrative Scenario)
This is a hypothetical scenario, not a real incident. An agency bills a client $15,000 by CCD debit. The same week, the agency has hosting and domain renewals due for that client, and its cash planning assumes the payment will clear.
| When | What happens |
|---|---|
| Monday | The billing engine originates the debit. The client closed the old account two weeks earlier after a treasury migration. The dashboard shows “processing.” |
| Tuesday–Wednesday | The debit is in the return window. Nothing looks wrong, and automation proceeds as though payment will succeed. |
| Wednesday–Thursday | The RDFI returns the entry as R02. Through a processor like Stripe, confirmation can take up to four business days. |
| Thursday | The status flips to “failed.” Renewals funded around the expected cash have already run or are about to. |
What happens next depends on the provider. A domain registrar may offer an optional auto-renew grace period of 0 to 45 days. If the domain isn’t renewed and is deleted, ICANN’s 30-day Redemption Grace Period applies. During it the domain stops functioning, and restoring it carries an extra fee. Hosting providers set their own suspension timelines, and these are often shorter. The risk is real, but the severity depends on each provider’s policy.
The Regulatory Framework: What Nacha Actually Requires
Nacha writes the operating rules for the ACH Network. Several rules bear on stale-credential risk. Some of them are commonly misapplied to B2B billing, so the scope of each matters.
Business accounts use CCD, and the authorization lives in your contract
Debits to business accounts use the CCD entry class. Consumer accounts use PPD, WEB, TEL and similar codes. For CCD, the authorization sits in the business agreement between the two companies. Your MSA is therefore the authorization document, and it should be specific.
The WEB account-validation rule is for consumer debits
Nacha’s rule requiring “commercially reasonable” fraud detection with account validation applies to WEB debits. These are internet-authorized debits to consumer accounts, and validation is required on first use of an account number or when it changes. It was phased in starting in March 2021. It doesn’t directly govern CCD retainers. Validating new bank details is still sound practice, and processors such as Stripe require verification.
New in 2026: fraud monitoring for all non-consumer originators
Nacha’s fraud-monitoring rule requires ODFIs and non-consumer originators, third-party service providers and third-party senders to establish risk-based processes reasonably intended to identify ACH entries initiated due to fraud. Phase 1 took effect on March 20, 2026 for originators with 6 million or more entries in 2023. Phase 2 extended it to all other non-consumer originators in June 2026. Nacha’s materials cite both June 19 and June 22 for that date. Processes must be reviewed at least annually.
The rule targets fraud, not stale data. Still, a request to change bank details should be verified through a trusted channel before you accept it. That control also catches honest mistakes.
Micro-entries
Nacha defines micro-entries as ACH credits of less than $1, plus any offsetting debits, used to verify an account. The rules require:
-
ACCTVERIFYin the Company Entry Description field. - Offsetting debits are optional. If used, they must be sent simultaneously with the credits, and the total of the debits can’t exceed the total of the credits.
- Originators must use commercially reasonable fraud detection on micro-entries, including monitoring forward and return volumes. This has applied since March 17, 2023.
Prenotes
A prenotification is an optional zero-dollar entry sent before the first live debit. If you send one, the live entry must be dated at least three banking days after the prenote settles. A returned prenote or an NOC tells you to fix the details first.
A prenote confirms only that the account number is valid and accepts entries. It doesn’t confirm ownership or balance, and the receiving bank isn’t required to check the account name. Availability depends on your bank or processor.
Building a Pre-Renewal Verification Protocol
The protocol below is recommended practice, not a Nacha requirement. Adjust thresholds to your risk tolerance.
Step 1: Move the debit date earlier
Schedule debits for critical retainers well ahead of the earliest hard-expiry date they fund. Allow for the processor’s confirmation time (up to four business days at Stripe), the return window, and a few days to collect new details.
Check your authorization terms before changing dates. Stripe’s documentation says that if you originate recurring preauthorized debits, you must give customers at least seven calendar days’ notice of changes to timing.
Step 2: Define re-verification triggers
Re-verify bank details when any of these occur:
- The client submits a new or changed account
- A prior debit returned R02, R03, R04 or R29
- A long gap has passed since the last successful debit (the threshold is your call)
- The client announces an acquisition, restructuring or finance-team change
- Your processor or bank-linking provider raises an alert. Stripe sends
payment_method.automatically_updatedevents withus_bank_account.status_details.blockedwhen it blocks an account. Plaid sendsPENDING_DISCONNECT(seven days before consent expires in the US and Canada),USER_PERMISSION_REVOKEDandITEM_LOGIN_REQUIRED.
Step 3: Choose the verification method
- Instant bank linking. Stripe Financial Connections or Plaid lets the client log into their bank. Stripe charges $1.50 per instant validation. This is fast, but links can break. Plaid warns that using account and routing numbers without completing re-authentication after consent is revoked may result in ACH returns. Balance data can also be cached unless you request a fresh balance. Plaid’s Signal product scores ACH return risk.
- Micro-entries (
ACCTVERIFY). Slower, since the client has to find and enter the amounts. Stripe gives customers 10 days to complete microdeposit verification. - Prenote. If your bank or processor supports it, send at least three banking days plus a buffer before the first live debit.
Step 4: Require a fallback payment method
Ask clients to keep a secondary method on file, such as a corporate card or a second verified bank account. The MSA should authorize charging it if the ACH debit fails. If you add a fee to card charges, confirm card-network surcharging rules with your processor first.
Step 5: Build dunning around the return type
| Signal | Likely meaning | Suggested response |
|---|---|---|
| R02, R03, R04 | Bad bank data | Don’t retry. Contact the client’s accounts-payable contact with a secure update link |
R29 or debit_not_authorized | Client’s bank blocked or didn’t recognize the debit | Stop. Have the client’s treasury team approve your company ID, or collect a new authorization |
R01 or insufficient_funds | Funds issue | Retry within processor limits, and notify the client |
Technical Implementation: Webhook-Driven Verification
The examples below use Stripe. Treat them as starting points, and test field names against your own API version.
Checking a linked account before a debit
// Node.js: check a Financial Connections link before scheduling a retainer debit const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); async function checkLinkedAccount(fcAccountId, retainerCents) { const account = await stripe.financialConnections.accounts.retrieve(fcAccountId); // "status" describes the data link (active | inactive | disconnected), // not whether the underlying bank account is open. if (account.status !== 'active') { return { ok: false, reason: `LINK_${account.status.toUpperCase()}` }; } // Balance is keyed by currency, in the smallest unit (cents for USD). // It is a snapshot and may be stale or absent depending on permissions. const usd = account.balance?.current?.usd; if (typeof usd === 'number' && usd < retainerCents) { return { ok: true, warning: 'BALANCE_BELOW_RETAINER' }; } return { ok: true }; } An active link doesn’t prove the account is open. Pair this check with a fresh debit-side verification.
Handling failures and early warnings
// Express handler; verify the signature before trusting any event app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), (req, res) => { const event = stripe.webhooks.constructEvent( req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET ); if (event.type === 'payment_intent.payment_failed') { const err = event.data.object.last_payment_error || {}; const reason = err.decline_code || err.code; // log the full payload in test mode first switch (reason) { case 'bank_account_closed': // R02 case 'bank_account_invalid_details': // R03, R04 holdDependentAutomations(event); // pause renewals that depend on this payment notifyAccountManager(event); sendBankUpdateLink(event); // do NOT auto-retry break; case 'debit_not_authorized': // R05, R07, R08, R10, R11, R29, R31 notifyAccountManager(event); // stop and contact the client break; case 'insufficient_funds': // R01, R09 scheduleFollowUp(event); break; } } if (event.type === 'payment_method.automatically_updated') { // Stripe blocked or unblocked a bank account: early warning before the next debit flagForReverification(event); } res.sendStatus(200); }); Stripe’s test-mode bank numbers let you rehearse failures. For example, routing 110000000 with account 000111111116 simulates a no_account failure. charge.dispute.created is a separate event, sent when a customer disputes an ACH payment. It is not a general return notification.
Contract Guidelines for Agency Retainers
Technical controls work best when the MSA backs them. These are example clauses, and a lawyer should review them for your jurisdiction.
- Bank-change notice. Require clients to give written notice, or update their billing portal, before closing or migrating the account used for debits. A 14-day notice period is a common starting point.
- ACH authorization. For CCD debits, the authorization lives in your agreement, so state the debit authorization clearly, including how amounts are determined.
- Failover consent. Authorize charging a secondary method if the primary debit fails.
- Allocation of responsibility. State who bears the consequences if a client-side payment failure delays renewals of third-party services.
- Timing changes. Make clear how you will notify clients if debit dates move.
Summary Checklist for RevOps and Billing Teams
- Move debit dates earlier than the hard expiry they fund, allowing for confirmation delays and time to fix bad details.
- Verify new or changed accounts with instant bank linking or micro-entries (
ACCTVERIFY) before the first debit. - Use prenotes where supported, with the three-banking-day wait.
- Don’t retry R02, R03 or R04 without corrected details.
- Handle NOCs within six banking days, or before the next entry.
- Require a backup payment method and written failover authorization.
- Wire up webhooks for payment failures and blocked-account events so a human sees them the same day.
- Ask your bank or processor how they have implemented Nacha’s 2026 fraud-monitoring rule, and what your return rates look like against the 3% and 15% levels.
Originally published at https://instarenewal.com/blog/the-stale-ach-trap-why-bank-account-changes-break-automated-agency-retainers
