--- title: "ACH Direct Debit chargebacks" description: "Learn about ACH returns and when you can retry an ACH Direct Debit payment." url: "https://docs.adyen.com/risk-management/chargeback-guidelines/ach-chargebacks" source_url: "https://docs.adyen.com/risk-management/chargeback-guidelines/ach-chargebacks.md" canonical: "https://docs.adyen.com/risk-management/chargeback-guidelines/ach-chargebacks" last_modified: "2026-05-23T12:56:20+02:00" language: "en" --- # ACH Direct Debit chargebacks Learn about ACH returns and when you can retry an ACH Direct Debit payment. [View source](/risk-management/chargeback-guidelines/ach-chargebacks.md) ACH refers to chargebacks as *returns*. It is not possible to defend ACH returns. You have the following options: * To reduce the risk of chargebacks, you can [use an external account validation service](#reduce-the-chargeback-risk). * In case of a Notification of Change, you can prevent future returns by [asking the customer to update their account details](#notification-of-change). * In some cases you can [retry the payment](#ach-retry). ## Causes of ACH chargebacks Because the ACH network is unable to provide real-time authorizations, an authorised payment can be reversed due to insufficient funds. Such chargebacks usually happen three to five days after the date of the direct debit payment. Additionally, consumers can dispute direct debit payments up to two years after the settlement date, claiming they did not authorize the payment or withdrew their authorization. Businesses can do this up to one year after settlement. This is different from credit card transactions, where a customer can initiate a chargeback by claiming that a product or service was not what they expected. ## Reduce the chargeback risk To reduce the risk of ACH returns, we recommend using an external service to [validate the customer's account details](/payment-methods/ach-direct-debit#account-validation) on their first transaction. External services that we support: * [giact gVERIFY](/payment-methods/ach-direct-debit/verification-with-giact/) ## Refunding disputed payments Adyen delays refunds for three days after a payment has settled. This delay helps prevent a scenario where, after a payment has settled, you issue a refund and a customer initiates a chargeback at around the same time. If you try to issue a refund but a customer inititates a chargeback within those three days, the refund request is canceled automatically and you will receive a [CHARGEBACK](https://docs.adyen.com/api-explorer/Webhooks/latest/post/CHARGEBACK) webhook. ## ACH return flow After an ACH Direct Debit payment is authorized, captured, and settled, the ACH return flow is as follows: 1. Optional: [Notification of Change](#notification-of-change) 2. Optional: [Request for Permission to Return](#request-for-permission-to-return) 3. Optional: [Information Supplied](#information-supplied) 4. [Notification of Chargeback](#notification-of-chargeback) 5. [Chargeback](#chargeback) 6. [Retry](#ach-retry) ![](/user/pages/docs/10.risk-management/21.chargeback-guidelines/ach-chargebacks/ACH-return-flow.png) ## Optional: Notification of Change If bank account details have changed, Adyen receives a Notice of Change. This happens, for example, if the customer's bank has been taken over by another bank. Usually there is a grace period when payments using the old account details are still accepted. But when the grace period ends, payments using the old account details are returned. If you subscribed to [DIRECT\_DEBIT\_NOTICE\_OF\_CHANGE\_NOTIFICATION](https://docs.adyen.com/api-explorer/Webhooks/latest/post/DIRECT_DEBIT_NOTICE_OF_CHANGE_NOTIFICATION) webhooks, Adyen then sends an **ach.notificationOfChange** webhook event with the details. When banks inform us that account details have changed, we update the account details saved in our system as much as possible. If you make [recurring payments](/online-payments/tokenization/), the existing `shopperReference` is updated with the new account details in many cases. However, you should still inspect the Direct Debit Notice of Change Notification webhook to see if details are missing and you need ask the customer to update their account details in your system. The following example illustrates the content of a Direct Debit Notice of Change Notification webhook with an **ach.notificationOfChange** event. **Direct Debit Notice of Change Notification** ```json { "type": "ach.notificationOfChange", "version": "1", "createdAt": "2023-08-16T18:22:45-03:00", "environment": "live", "data": { "pspReference": "XB7XNCQ8HXSKGK82", "shopperReference": "YOUR_SHOPPER_REFERENCE", "notificationOfChange": { "reasonCode": "C07", "newBankAccountNumber": "012345678901", "newBranchCode": "012003456", "newBankAccountType": "Savings" } } } ``` ## Optional: Request for Permission to Return To verify the account holder, the issuing bank has asked for supporting documents. Adyen contacts you to provide those documents.\ At this point, funds are not yet deducted from your account. ## Optional: Information Supplied Adyen has received your supporting documents and has shared them with the issuing bank.\ At this point, funds are not yet deducted from your account. ## Notification of Chargeback The issuing bank or the customer has initiated an ACH return. You receive a [NOTIFICATION\_OF\_CHARGEBACK](https://docs.adyen.com/api-explorer/Webhooks/latest/post/NOTIFICATION_OF_CHARGEBACK) webhook with the details. You cannot defend the return, but it may be allowed to [retry](#ach-retry) the payment. ## Chargeback Your account is debited for the ACH return. You receive a [CHARGEBACK](https://docs.adyen.com/api-explorer/Webhooks/latest/post/CHARGEBACK) webhook. You cannot defend the return, but it may be allowed to [retry](#ach-retry) the payment. ## Decide if you can retry the payment To indicate the reason of the return, ACH provides a reason code that we return in the **NOTIFICATION\_OF\_CHARGEBACK** and **CHARGEBACK** webhooks, and in your [Customer Area](https://ca-test.adyen.com/) > **Revenue & risk** > **Disputes**. Depending on the reason code, you can retry the transaction or take some other action. However, some transactions cannot possibly succeed, for example because the customer's account has been closed. If you repeatedly retry transactions that will never succeed, the [National Automated Clearinghouse Association](https://www.nacha.org/) (Nacha) imposes fines, and we have to block you from sending any new ACH Direct Debit transactions. Use the following table with the most common ACH return reason codes to determine if it is allowed to retry a returned ACH Direct Debit payment. | Reason code | Reason | Description / Resolution | Retry? | | ----------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | | R01 | Insufficient funds | You can retry the transaction up to two times within 30 days of the original authorization date. | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") **max 2x** | | R02 | Account closed | Retrying the transaction is not allowed. Initiate a new transaction using an [external validation service](#reduce-the-chargeback-risk). | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R03 | No Account/Unable to locate account | The provided account information is incorrect. Retrying the transaction is not allowed. Initiate a new transaction using an [external validation service](#reduce-the-chargeback-risk). | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R04 | Invalid account number | The provided account number is incorrect. Retrying the transaction is not allowed. Initiate a new transaction using an [external validation service](#reduce-the-chargeback-risk). | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R05 | Unauthorized debit to consumer account | A corporate transaction was charged to a consumer account and was disputed by the customer. Suspend any recurring payments and resolve the issue with the customer. If you are going to debit the same account for a new transaction, make sure the customer's bank stops blocking transactions from your company to this account. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R06 | Returned per ODFIs request | Your bank asked the customer's bank to reverse the transaction. Retrying the transaction is not allowed. Contact your bank. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R07 | Authorization revoked by customer | The customer informed their bank they revoked authorization for the transaction. Suspend any recurring transactions and resolve the issue with the customer. If you are going to debit the same account for a new transaction, make sure the customer's bank stops blocking transactions from your company to this account. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R08 | Payment stopped or stop payment on item | The customer instructed their bank to not honor a payment they previously authorized. Resolve the issue with the customer. When initiating a new transaction (using an [external validation service](#reduce-the-chargeback-risk)), get new proof of authorization from the customer. If you are going to debit the same account, make sure the customer's bank stops blocking transactions from your company to this account. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R09 | Uncollected funds | Insufficient funds. You can retry the transaction up to two times within 30 days of the original authorization date. | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") **max 2x** | | R10 | Customer Advises Originator is Not Known to Receiver and/or Originator is Not Authorized by Receiver to Debit Receiver’s Account | The customer disputed the transaction. Retrying the transaction is not allowed. Resolve the issue with the customer. If you are going to debit the same account for a new transaction, make sure the customer's bank stops blocking transactions from your company to this account. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R11 | Customer Advises Entry Not in Accordance with the Terms of the Authorization | The customer informed their bank that the payment is not in accordance with the authorization terms. Suspend any recurring transactions and resolve the issue with the customer. You can retry the transaction within 60 days of the original settlement date. | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | R12 | Branch sold to another DFI | The customer's account has migrated to another financial institution. Ask the customer to update their account details in your system. | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | R13 | Invalid ACH routing number | The provided routing number does not belong to any bank in the ACH network. Ask the customer for the correct routing number, or contact your bank if you are sure the number is correct. | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | R15 | Beneficiary or account holder deceased | Contact the bank of the deceased account holder or account beneficiary. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R16 | Account frozen | Contact your customer to obtain a different form of payment. The bank account cannot be used while it is frozen. This return code should be a red flag for your business. If you see this code, do your due diligence around verifying the identity of your customer. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R17 | File record edit criteria | The customer's bank had a technical problem with processing the ACH transaction. | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | R20 | Non-transaction account | The provided bank account cannot be used for ACH payments. Ask the customer for permission to charge a different, ACH-enabled bank account. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R29 | Corporate customer advises not authorized | The company you tried to charge has disputed the transaction. Retrying the transaction is not allowed. Resolve the issue with the other company. If you are going to debit the same account for a new transaction, make sure the other company's bank stops blocking transactions from your company to this account. It is possible the issue is resolved if the other company adds the [Adyen ACH Company ID](/payment-methods/ach-direct-debit#ach-company-id-for-b2b-payments) for payments to the allowlist of their business account. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R31 | Permissible return entry | The business account holder or their bank has asked to reverse the transaction. Contact your bank for more information. Contact the customer to resolve the issue. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | R51 | Item is ineligible, notice not provided, signature not genuine | To determine what to do, you need to find out the underlying reason why the payment was returned. Contact Adyen if you need help. | ![-x-](/user/data/smileys/emoji/x.png "-x-") | ## Test a chargeback scenario You can try out the ACH return flow by sending an ACH Direct Debit test payment. The `ownerName` in the test payment indicates the chargeback scenario that you want to test. Note that in the test environment the return flow goes directly to the Chargeback stage. The optional stages and the Notification of Chargeback stage are skipped. To test a chargeback: 1. Send an ACH Direct Debit payment request using the following account details. | Parameter | Description | | ------------------- | -------------------------------------------------------------------------- | | `ownerName` | **chargeback:[REASON\_CODE](#ach-retry)**. For example, **chargeback:R01** | | `bankAccountNumber` | Any correctly formatted account number. For example, **1234567890** | | `bankLocationId` | The routing number. Use **011000138** or **121000358** | | `billingAddress` | The account owner's address. Use any correctly formatted US address. | **Testing return reason code R01** #### curl ```bash curl https://checkout-test.adyen.com/v72/payments \ -H 'x-API-key: YOUR_X_API_KEY' \ -H 'content-type: application/json' \ -d '{ "merchantAccount":"YOUR_MERCHANT_ACCOUNT", "amount":{ "currency":"USD", "value":"1000" }, "reference":"YOUR_ORDER_NUMBER", "{hint:state.data.paymentMethod from onSubmit}paymentMethod{/hint}":{ "type":"ach", "bankAccountNumber":"1234567890", "bankAccountType":"checking", "bankLocationId":"121000358", "ownerName":"chargeback:R01" }, "billingAddress":{ "houseNumberOrName":"50", "street":"Test Street", "city":"Amsterdam", "stateOrProvince":"NY", "postalCode":"12010", "country":"US" } }' ``` #### Java ```java // Adyen Java API Library v25.0.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.checkout.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.model.RequestOptions; import com.adyen.service.checkout.*; Client client = new Client("ADYEN_API_KEY", Environment.TEST); // Request objects Amount amount = new Amount() .currency("USD") .value(1000L); AchDetails achDetails = new AchDetails() .bankAccountType(AchDetails.BankAccountTypeEnum.CHECKING) .ownerName("chargeback:R01") .bankAccountNumber("1234567890") .type(AchDetails.TypeEnum.ACH) .bankLocationId("121000358"); BillingAddress billingAddress = new BillingAddress() .country("US") .stateOrProvince("NY") .city("Amsterdam") .houseNumberOrName("50") .street("Test Street") .postalCode("12010"); PaymentRequest paymentRequest = new PaymentRequest() .reference("YOUR_ORDER_NUMBER") .amount(amount) .merchantAccount("YOUR_MERCHANT_ACCOUNT") .paymentMethod(new CheckoutPaymentMethod(achDetails)) .billingAddress(billingAddress); // Make the request PaymentsApi service = new PaymentsApi(client); PaymentResponse response = service.payments(paymentRequest, new RequestOptions().idempotencyKey("UUID")); ``` #### PHP ```php // Adyen PHP API Library v17.4.0 use Adyen\Client; use Adyen\Environment; use Adyen\Model\Checkout\Amount; use Adyen\Model\Checkout\CheckoutPaymentMethod; use Adyen\Model\Checkout\BillingAddress; use Adyen\Model\Checkout\PaymentRequest; use Adyen\Service\Checkout\PaymentsApi; $client = new Client(); $client->setXApiKey("ADYEN_API_KEY"); $client->setEnvironment(Environment::TEST); // Request objects $amount = new Amount(); $amount ->setCurrency("USD") ->setValue(1000); $checkoutPaymentMethod = new CheckoutPaymentMethod(); $checkoutPaymentMethod ->setBankAccountType("checking") ->setOwnerName("chargeback:R01") ->setBankAccountNumber("1234567890") ->setType("ach") ->setBankLocationId("121000358"); $billingAddress = new BillingAddress(); $billingAddress ->setCountry("US") ->setStateOrProvince("NY") ->setCity("Amsterdam") ->setHouseNumberOrName("50") ->setStreet("Test Street") ->setPostalCode("12010"); $paymentRequest = new PaymentRequest(); $paymentRequest ->setReference("YOUR_ORDER_NUMBER") ->setAmount($amount) ->setMerchantAccount("YOUR_MERCHANT_ACCOUNT") ->setPaymentMethod($checkoutPaymentMethod) ->setBillingAddress($billingAddress); $requestOptions['idempotencyKey'] = 'UUID'; // Make the request $service = new PaymentsApi($client); $response = $service->payments($paymentRequest, $requestOptions); ``` #### C\# ```cs // Adyen .net API Library v14.3.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Checkout; using Adyen.Service.Checkout; var config = new Config() { XApiKey = "ADYEN_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Fill in your request objects Amount amount = new Amount { Currency = "USD", Value = 1000 }; AchDetails achDetails = new AchDetails { BankAccountType = AchDetails.BankAccountTypeEnum.Checking, OwnerName = "chargeback:R01", BankAccountNumber = "1234567890", Type = AchDetails.TypeEnum.Ach, BankLocationId = "121000358" }; BillingAddress billingAddress = new BillingAddress { Country = "US", StateOrProvince = "NY", City = "Amsterdam", HouseNumberOrName = "50", Street = "Test Street", PostalCode = "12010" }; PaymentRequest paymentRequest = new PaymentRequest { Reference = "YOUR_ORDER_NUMBER", Amount = amount, MerchantAccount = "YOUR_MERCHANT_ACCOUNT", PaymentMethod = new CheckoutPaymentMethod(achDetails), BillingAddress = billingAddress }; // Make the request var service = new PaymentsService(client); var response = service.Payments(paymentRequest, requestOptions: new RequestOptions { IdempotencyKey = "UUID"}); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v16.1.0 // Require the parts of the module you want to use const { Client, CheckoutAPI } = require('@adyen/api-library'); // Initialize the client object const client = new Client({apiKey: "YOUR_X_API_KEY", environment: "TEST"}); // Create the request object const paymentRequest = { merchantAccount: "YOUR_MERCHANT_ACCOUNT", amount: { currency: "USD", value: "1000" }, reference: "YOUR_ORDER_NUMBER", paymentMethod: { type: "ach", bankAccountNumber: "1234567890", bankAccountType: "checking", bankLocationId: "121000358", ownerName: "chargeback:R01" }, billingAddress: { houseNumberOrName: "50", street: "Test Street", city: "Amsterdam", stateOrProvince: "NY", postalCode: "12010", country: "US" } } // Make the request const checkoutAPI = new CheckoutAPI(client); const response = checkoutAPI.PaymentsApi.payments(paymentRequest, { idempotencyKey: "UUID" }); ``` #### Go ```go // Adyen Go API Library v9.2.0 import ( "context" "github.com/adyen/adyen-go-api-library/v9/src/common" "github.com/adyen/adyen-go-api-library/v9/src/adyen" "github.com/adyen/adyen-go-api-library/v9/src/checkout" ) client := adyen.NewClient(&common.Config{ ApiKey: "ADYEN_API_KEY", Environment: common.TestEnv, }) // Fill in your request objects amount := checkout.Amount{ Currency: "USD", Value: 1000, } achDetails := checkout.AchDetails{ BankAccountType: common.PtrString("checking"), OwnerName: common.PtrString("chargeback:R01"), BankAccountNumber: common.PtrString("1234567890"), Type: common.PtrString("ach"), BankLocationId: common.PtrString("121000358"), } billingAddress := checkout.BillingAddress{ Country: "US", StateOrProvince: common.PtrString("NY"), City: "Amsterdam", HouseNumberOrName: "50", Street: "Test Street", PostalCode: "12010", } paymentRequest := checkout.PaymentRequest{ Reference: "YOUR_ORDER_NUMBER", Amount: amount, MerchantAccount: "YOUR_MERCHANT_ACCOUNT", PaymentMethod: checkout.AchDetailsAsCheckoutPaymentMethod(&achDetails), BillingAddress: &billingAddress, } // Make the request service := client.Checkout() req := service.PaymentsApi.PaymentsInput().IdempotencyKey("UUID").PaymentRequest(paymentRequest) res, httpRes, err := service.PaymentsApi.Payments(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v12.0.0 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "YOUR_X_API_KEY" adyen.client.platform = "test" # The environment to use library in. json_request = { "merchantAccount": "YOUR_MERCHANT_ACCOUNT", "amount": { "currency": "USD", "value": "1000" }, "reference": "YOUR_ORDER_NUMBER", "paymentMethod": { "type": "ach", "bankAccountNumber": "1234567890", "bankAccountType": "checking", "bankLocationId": "121000358", "ownerName": "chargeback:R01" }, "billingAddress": { "houseNumberOrName": "50", "street": "Test Street", "city": "Amsterdam", "stateOrProvince": "NY", "postalCode": "12010", "country": "US" } } result = adyen.checkout.payments_api.payments(request=json_request, idempotency_key="UUID") ``` #### Ruby ```rb # Adyen Ruby API Library v9.1.0 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'YOUR_X_API_KEY' adyen.env = :test # Set to "live" for live environment request_body = { :merchantAccount => 'YOUR_MERCHANT_ACCOUNT', :amount => { :currency => 'USD', :value => '1000' }, :reference => 'YOUR_ORDER_NUMBER', :paymentMethod => { :type => 'ach', :bankAccountNumber => '1234567890', :bankAccountType => 'checking', :bankLocationId => '121000358', :ownerName => 'chargeback:R01' }, :billingAddress => { :houseNumberOrName => '50', :street => 'Test Street', :city => 'Amsterdam', :stateOrProvince => 'NY', :postalCode => '12010', :country => 'US' } } result = adyen.checkout.payments_api.payments(request_body, headers: { 'Idempotency-Key' => 'UUID' }) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v16.2.0 // Require the parts of the module you want to use import { Client, CheckoutAPI, Types } from "@adyen/api-library"; // Initialize the client object const client = new Client({apiKey: "ADYEN_API_KEY", environment: "TEST"}); // Create the request objects const amount: Types.checkout.Amount = { currency: "USD", value: 1000 }; const achDetails: Types.checkout.AchDetails = { bankAccountType: Types.checkout.AchDetails.BankAccountTypeEnum.Checking, ownerName: "chargeback:R01", bankAccountNumber: "1234567890", type: Types.checkout.AchDetails.TypeEnum.Ach, bankLocationId: "121000358" }; const billingAddress: Types.checkout.BillingAddress = { country: "US", stateOrProvince: "NY", city: "Amsterdam", houseNumberOrName: "50", street: "Test Street", postalCode: "12010" }; const paymentRequest: Types.checkout.PaymentRequest = { reference: "YOUR_ORDER_NUMBER", amount: amount, merchantAccount: "YOUR_MERCHANT_ACCOUNT", paymentMethod: achDetails, billingAddress: billingAddress }; // Make the request const checkoutAPI = new CheckoutAPI(client); const response = checkoutAPI.PaymentsApi.payments(paymentRequest, { idempotencyKey: "UUID" }); ``` 2. Note that the request succeeds with `resultCode`: **Authorised**.\ The [ACH return flow](#ach-return-flow) starts after the test payment is captured and settled. 3. Wait for the **CHARGEBACK** webhook and check your [Customer Area](https://ca-test.adyen.com/) > **Revenue & risk** > **Disputes**.\ The webhook and your Customer Area show a chargeback with the return reason code that you specified in the payment request. ## See also * [ACH Direct Debit](/payment-methods/ach-direct-debit) * [Account validation with giact](/payment-methods/ach-direct-debit/verification-with-giact)