Use APIs to integrate ACH direct debit payments
Last updated: Apr 24th, 11:10pm
ACH, or Automated Clearing House, is a network that allows for electronic funds transfers between banks in the United States. PayPal now allows merchants to use ACH direct debit payments to accept payments from a payer by debiting directly from their bank account. For example, government agencies may use this feature for one-time payments for taxes, citations, or permit fees.
ACH direct debit can be used for one-time and recurring payments. ACH can only be transacted in USD.
How it works
The Pay by Bank button shows up on your website when a customer uses a browser for checkout.

When your payer selects the Pay by Bank button and if bank verification is required:
- Payer is connected to PayPal's bank verification system
- Payer is presented with an option to select their banking institution.
- Upon selection, payer can login and choose the appropriate debit account.
- The payer confirms purchase details, including bank information, recipient, transaction amount, and transaction date.
- The payer finalizes the sales transaction.
Know before you code
- You must be an approved partner to integrate the ACH offering.
- The instructions in Get Started will help you get your access token.
- This server-side integration uses the Orders REST API.
- Set
intent: capturein the create order call for this feature to work. - Review the Nacha rules and other risks associated with ACH direct debit payments.
Review the liabilities
If an ACH payment is returned by your payer's bank, you are liable for the transaction amount PayPal might have already moved to your account and the return fees. These charges are reflected in the PayPal account set up during onboarding.
Understand the differences between unauthorized returns and the remaining type of returns to evaluate and control your exposure to any losses and manage your refund process. At a high level, the differences are as follows:
- Unauthorized returns: Your payer can raise an unauthorized dispute anytime after the funds move out of their bank account to yours, within a timeframe of 60 days for consumer accounts and two days for business accounts. In unauthorized dispute cases, PayPal will charge your account in the amount of the original transaction amount plus a $5 dispute fee.
- Other types of returns: Any non-unauthorized type of return, such as insufficient funds, invalid or closed account, or other reasons will not result in funds clearance. With these types of returns, you have less exposure to losses, unless you had requested PayPal to process the transaction as instant ACH. In the case you receive a non-unauthorized return and submitted the payment as standard ACH, then you will be liable for only the return fee. However, if you submitted the transaction as an instant ACH payment, then you will be liable for both the original transaction amount PayPal couldn't debit from your payer's bank account and the return fee.
You might be unnecessarily crediting your payer if you are issuing a refund to your payer, but the transaction gets returned from your payer's bank as a result of insufficient funds. To prevent any fraud or double-crediting your payers we recommend you:
- Don't issue a refund until after the funds settle in your account.
- Communicate to your payer immediately that you have started the refund process, and it will take at least 5 calendar days for them to receive the funds back in their bank account.
- Don't ship your product or service if you haven't received the funds from your payer, which should happen after 5 calendar days for funds clearance.
Review SEC options
This integration requires a standard entry class (SEC) code. The following codes are available:
Default: Internet Initiated Entry (WEB)- Corporate Credit or Debit (
CCD) - Telephone Initiated Entry (
TEL) - Prearranged Payment and Deposit Entry (
PPD)
Select a tab for more information about each SEC option:
WEB entries are direct debit payments initiated online. You must collect the authorization from your customer online. Refer to section on Authorization for a sample authorization you can use for WEB transactions. To remain in compliance with NACHA regulations, we recommend you store the full text of the authorization and following information as proof of consent:
- Amount of transaction and bank details
- Timestamp that indicates what date and time the consumer authorized the debit
Partner and merchant experience
Partners and merchants follow different steps to integrate with ACH using API integration on the PayPal Commerce Platform.
Partner integration overview
Setting up Company ID
Company ID is a 10-digit identifier used by banks and NACHA (governing and processing entity for ACH transactions), which uniquely identifies the entity collecting payments (aka Originator) via ACH.
Company ID is responsible for ensuring unique identification for entities and isolating transaction processing for these entities. These are in place to avoid any incorrect / fraudulent transactions and to isolate processing for each entity and which may be used to monitor and filter debits to unknown entities.
Details needed for Company ID creation:
- Partner Name
- Street Address
- City
- State
- Zip Code
- Country
- Proposed Company ID (10 character alphanumeric)
- Partner ID
- ACH-IN (does partner need unbranded ACH-IN)
- ACH-OUT
Note: Reach out to your Account Manager to initiate the Company ID Setup.
Onboarding
ACH as a payment method will be available to turn on for merchants on their PayPal Payment Settings page. Merchants will then be redirected to complete the remainder of the onboarding process. Depending on whether a merchant has previously onboarded for PPCP Advanced, merchants will experience a simplified one-click onboarding process. For new merchants, the onboarding process will require input of a series of short questions about a merchant's business information.
Onboard merchants
- You'll need to onboard your merchants so they can use this product.
- Modify your Partner Referral API call to include
ACHin theproductsarray for merchant onboarding. - Additionally, you can select PayPal Complete Payments Full Stack Offering Including ACH using the PPCP Onboarding API.
- See Onboard merchants before payment for more information.
Set up your sandbox account to accept ACH
Before you can accept ACH on your website, verify that your sandbox business account supports ACH. Merchants can use the PayPal Developer Dashboard to set up their sandbox accounts to accept ACH. The integration for partner accounts includes creating a sandbox business account through sandbox.paypal.com. If the ACH status for the account shows as disabled, complete the sandbox onboarding steps to enable ACH.
- Log into the PayPal Developer Dashboard and go to your sandbox account.
- Go to Apps & Credentials.
- Click on My Apps & Credentials, and switch to Sandbox mode.
- Click on the Sandbox app you want to use.
- Scroll down to the Features section and locate Pay by Bank: ACH under Accept Payments.
- If the check box is not enabled, select it and click on Save Changes to enable it.
If you created a sandbox business account through sandbox.paypal.com, and the ACH status for the account shows as disabled, complete the sandbox onboarding steps to enable ACH.
Tip: When your integration is ready to go live, read the Go live section for details about the additional steps needed for ACH onboarding.
Integrate ACH
Follow this integration process to add ACH as a checkout option, customize the payment experience, and process payments.
Create an order
To create an order for standard ACH direct debit payments, copy the following code and modify it:
1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders2 -H 'Content-Type: application/json'3 -H 'Authorization: Bearer ACCESS-TOKEN'4 -d '{5 "intent": "CAPTURE",6 "purchase_units": [7 {8 "amount": {9 "currency_code": "USD",10 "value": "100.00"11 },12 "payee": {13 "email_address": "[email protected]"14 }15 }16 ]17 }'
Modify the code
After you copy the code in the sample request, modify the following:
- Change
ACCESS-TOKENto your access token. - Set
intenttocapture. - Change the
standard_entry_class_code. Options areWEB,CCD,TEL, andPPD. - Optional: Change the
purchase_unit/payment_instruction/platform_feesarray to specify fees for the order.Tip: To help prevent chargebacks and unauthorized disputes, use thesoft_descriptorin the Orders API so that your payers can recognize the transaction when it posts to their account.
Step result
A successful request results in the following:
- A return status code of HTTP
201 Created. - A JSON response body that contains the order ID. You'll use the order ID to capture the order.
Create an order and initiate bank account verification
- Sample request
- Sample response
1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders2 -H 'Content-Type: application/json'3 -H 'PayPal-Request-Id: REQUEST-ID' -H 'Authorization: Bearer ACCESS-TOKEN'4 -d '{5 "intent": "CAPTURE",6 "purchase_units": [7 {8 "amount": {9 "currency_code": "USD",10 "value": "100.00"11 },12 "payee": {13 "email_address": "[email protected]"14 }15 }16 ],17 "payment_source": {18 "bank": {19 "ach_debit": {20 "billing_address": {21 "country_code": "US"22 },23 "attributes": {24 "verification": {25 "paypal": {26 "method": "INSTANT_ACCOUNT_VERIFICATION"27 }28 }29 },30 "experience_context": {31 "locale": "en-US",32 "return_url": "https://example.com/return",33 "cancel_url": "https://example.com/cancel"34 }35 }36 }37 }38 }'
Modify the code
- Change
ACCESS-TOKENto your access token. - Specify the preferred language and set
return_urlandcancel_url. This is required to redirect the payer back to your site.
Confirm payment source
This allows you to verify the user bank account through PayPal offered Instant Account Verification service or you can provide the customer bank account details as a payment source and call confirm payment source. The response result guides you next steps with regards to account verification.
- The bank account must be verified before you can collect any money from that account.
- The payer must authorize the direct debit. See Authorization section for more information.
- Standard Entry Classification (SEC) codes are used to define how your payer has authorized the payment. PayPal accepts
WEB,TEL,CCD, andPPDSEC codes. The default isWEB. - If you have an externally verified bank account to use, you shall set
verification.external.statusasVERIFIEDand PayPal will acknowledge this status. - It is recommended to provide a unique
merchant_customer_id. The id is used to track accounts and their verification status for the customer.
Step 2A: Use PayPal instant verification service
To verify the payer bank account through PayPal instant account verification service, copy the following code and modify it:
- Sample request
- Sample response
1curl -v -k -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN36475T/confirm-payment-source2 -H 'Content-Type: application/json'3 -H 'Authorization: Bearer ACCESS-TOKEN'4 -d '{5 "payment_source": {6 "bank": {7 "ach_debit": {8 "billing_address": {9 "country_code": "US"10 },11 "attributes": {12 "verification": {13 "paypal": {14 "method": "INSTANT_ACCOUNT_VERIFICATION"15 }16 }17 },18 "payment_context": {19 "standard_entry_class_code": "WEB"20 },21 "experience_context": {22 "locale": "en-US",23 "return_url": "https://example.com/return",24 "cancel_url": "https://example.com/cancel"25 }26 }27 }28 }29 }'
Modify the code
- Change
ACCESS-TOKENto your access token. - Specify the preferred language and set
return_urlandcancel_url. This is required to redirect the payer back to your site.
Step result
- A return status code of HTTP
200 OK. - PayPal generates and returns rel: payer-action HATEOAS link. This is the link to which you will need to redirect your customer to PayPal Instant Account Verification page.
- Redirect the customer to the bank account verification flow using the HATEOAS link.
- PayPal will redirect customer to the SUCCESS endpoint (RETURN URL) with the results of the verification. A SUCCESS will mean the bank account was verified successfully.
- A FAIL will imply the customer was not able to complete the bank account verification. Since transaction cannot be processed on an unverified bank account, prompt the customer to provide a different payment instrument.
- In case of verification error or customer cancellation, PayPal will redirect to the CANCEL URL. In case of retry-able errors, reinitiate the transaction from Confirm Payment Source onwards. For other situations, prompt the customer to provide a different payment instrument - transaction can only be processed on verified bank account.
Step 2B: Accounts are externally verified
- If you have bank accounts verified via external party and wish to skip PayPal's verification system, you may indicate the verification status using the
verification.external.statusfield. - Providing a unique a unique
merchant_customer_idis recommended. - Change the
standard_entry_class_code. Options areWEB,CCD,TEL, andPPD.
1curl -v -k -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN36475T/confirm-payment-source2 -H 'Content-Type: application/json'3 -H 'Authorization: Bearer ACCESS-TOKEN'4 -d '{5 "payment_source": {6 "bank": {7 "ach_debit": {8 "account_number": "ACCOUNT-NUMBER",9 "routing_number": "ROUTING-NUMBER",10 "account_holder_name": "ACCOUNT-HOLDER-NAME",11 "account_type": "ACCOUNT-TYPE",12 "ownership_type": "OWNERSHIP-TYPE",13 "billing_address": {14 "country_code": "US"15 },16 "attributes": {17 "verification": {18 "external": {19 "status": "VERIFIED"20 }21 }22 },23 "payment_context": {24 "standard_entry_class_code": "WEB"25 }26 }27 }28 }29 }'
Modify the code
After you copy the code in the sample request, modify the following:
- Change
Access-Tokento your access token. - Change following placeholders with the customer bank account information.
ACCOUNT-NUMBERROUTING-NUMBERACCOUNT-HOLDER-NAMEACCOUNT-TYPE- (CHECKING or SAVINGS)OWNERSHIP-TYPE- (PERSONAL or BUSINESS)
- For
CCDtransactions, always set"standard_entry_class_code": "CCD"and"ownership_type": "BUSINESS"in the body ofach_debit.
Step result
A successful request results:
- A return status code of HTTP
200 OK. - Order status will be
APPROVED.
Get order
Confirmation is required by the payer on the finalization of the transaction before the order can be captured.
- Sample request
- Sample response
1curl -v -X GET https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T2 -H 'Content-Type: application/json'3 -H 'Authorization: Bearer ACCESS-TOKEN'
Authorization
For all ACH transactions, you are required to collect an authorization from the customer indicating that you have their explicit permission to debit their bank account. To remain in compliance with NACHA regulations, we recommend you store the full text of the authorization with amount of transaction, bank details and timestamp of authorization. You may be required to provide proof of the authorization when requested by PayPal, customer’s bank or by NACHA.
A reference authorization text is provided below. Include this text or a variation in your checkout flow, at or near the final "buy" (checkout, complete, submit etc.) button.
Use Case 1: ONE TIME PURCHASE ("Single Entry")
"I authorize [Merchant business name] to initiate a one-time ACH/electronic debit to my account as follows: Amount: [insert amount], Authorization Date: [insert date], Account holder: [insert full name], Bank: [insert bank name], [Checking / Savings] Account Number: [insert account number], Routing Number: [insert routing number]. I agree that ACH transactions I authorize comply with all applicable laws." [CTA: Agree and Continue]
Capture an order
Before you can capture an order using ACH direct debit, the status of the order must be APPROVED. The order status is set to APPROVED when the payer successfully completes the checkout flow.
After the bank account is verified and the payer authorizes the direct debit, you can call capture order to capture the payer's funds.
Copy the following code and modify it:
1curl -v -X GET https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/capture2 -H 'Content-Type: application/json'3 -H 'Authorization: Bearer ACCESS-TOKEN'4 -d '{}'
Modify the code
- Change
Access-Tokento your access token.
Step result
A successful result for a standard ACH direct debit returns the following:
- If the transaction is not declined, the response is
PAYMENT.CAPTURE.PENDING. This status changes in 5 calendar days to eitherPAYMENT.CAPTURE.COMPLETEDorPAYMENT.CAPTURE.DECLINED. - If the payment is completed, the response is
PAYMENT.CAPTURE.COMPLETED. This payment can be returned in certain situations, such as with an unauthorized return. - If the payment is declined, the response is
PAYMENT.CAPTURE.DECLINED. A payment may be declined for incorrect routing or account numbers or for other reasons.
- Listen for the
CHECKOUT.ORDER.APPROVEDwebhook in order to retrieve order details. - Listen for the
PAYMENT.CAPTURE.PENDING,PAYMENT.CAPTURE.COMPLETED, andPAYMENT.CAPTURE.DECLINEDwebhooks, which indicate payment capture status.
Capture an order by passing order ID
- Sample request
- Sample response
1curl -v -X GET https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T2 -H 'Content-Type: application/json'3 -H 'Authorization: Bearer ACCESS-TOKEN'
Go Live
Make ACH available to payers using your website or app.
Important: Before going live, complete production onboarding to process ACH payments with your live PayPal account.
Test your live environment
When testing a purchase in production, consider:
- The business account receiving money can't also make the purchase.
- If you create a personal account with the same information as the business account, those accounts might experience restrictions.
How to test ACH payments in a live environment
- Open your test page with on a web browser.
- Select the ACH button to trigger the ACH payment experience.
- Proceed with the ACH bank verification.
- Continue to confirm the transaction.
- On the confirmation page on your merchant website, confirm the payment.
- Log in to your seller account and confirm that the money has moved into that account.
Review daily reports
Refer to the daily reports to reconcile all returns you received on that day. Then, you can work with any payer on the steps they should take to resubmit the payment. Use the following reports:
Decline Analysis Report
The Decline Analysis Report contains all returned/declined standard ACH debit transactions including the reason codes received from the ACH network.
Financial Summary Report
The Financial Summary Report contains the liability charges posted on your account as a result of returned ACH debit transactions. Instant ACH transactions that resulted in bank returns are also included in this daily report. The report includes the original transaction that was returned and what fees you incurred from returned transactions.
Review reason codes
If an ACH transaction is returned by your payer's bank, a reason code for the returned transaction is included. Depending on the reason code, the transaction can be corrected and re-submitted for processing.
The table below provides return reason codes and explains what steps you can take if an ACH transaction was not processed and returned to you:
| Reason Code | Description | What it means | What you should do |
|---|---|---|---|
| R01 | Insufficient Funds | The bank account you submitted to PayPal for payment does not have sufficient balance to cover the amount on the transaction. | Contact your payer immediately to avoid any disruption in the service or the delivery of your product, and let them know you were not able to charge their bank account as a result of insufficient funds. You can ask them to add funds to their bank account and have them go through the payment experience again, or present them an option to pay with a different bank account or a different payment method and submit a new transaction. |
| R02 | Account Closed | The bank account you submitted for payment has been closed. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R03 | No Account/Unable to Locate Account | The bank account you submitted for payment is invalid. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R04 | Invalid Account Number Structure | The bank account you submitted for payment is invalid. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R05 | Unauthorized Debit to Consumer Account Using Corporate SEC Code | Payment has been submitted on a corporate account using a consumer SEC code. | Correct the payment SEC code and resubmit. |
| R06 | Returned per ODFI’s Request | Payment stopped as required by PayPal. | Resubmit the transaction. If PayPal has stopped payment on your behalf, contact PayPal. |
| R07 | Authorization Revoked by Customer | Payment has been marked as unauthorized by payer. Payment has been reversed by payer by revoking authorization. | Contact payer to resolve the issue. |
| R08 | Payment Stopped | Stop payment issued by payer on account for PayPal Payment has been stopped by payer. | Contact payer to resolve the issue. |
| R09 | Uncollected Funds | Collected funds are not sufficient for payment of the debit entry | Contact the payer to inform them of insufficient funds. As per your procedures you may resubmit the transaction or request the payer to update payment method or payment account. |
| R10 | Customer Advises Unauthorized, Improper, Ineligible, or part of an Incomplete Transaction | Payment has been marked as unauthorized by payer. Payment has been reversed by payer by revoking authorization. | Contact payer to resolve the issue. |
| R12 | Account Sold to another DFI | RDFI is unable to post entry destined for a bank account maintained at a branch sold to another financial institution. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R13 | Invalid ACH Routing Number | Financial institution does not receive commercial ACH entries. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R14 | Representative Payee Deceased or Unable to Continue in that capacity | The representative payee authorized to accept entries on behalf of a beneficiary is either deceased or unable to continue in that capacity. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R15 | Beneficiary of Account Holder Deceased | The beneficiary entitled to payments is deceased and/or the bank account holder other than a representative payee is deceased. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R16 | Account Frozen/Entry Returned per OFAC Instruction | Funds in bank account are unavailable due to action by RDFI or legal order. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R17 | File Record Edit Criteria | Certain payment fields rejected by RDFI processing (identified in return addenda) | Correct the payment fields and resubmit. |
| R20 | Non Transaction Account | The ACH entry is sent to a non-transaction account. | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
| R24 | Duplicate Entry | RDFI has received a duplicate entry. | Check if this transaction was a duplicate or has already completed, before resending the payment. |
| R29 | Corporate Customer Advises not authorized | Payment has been marked as unauthorized by payer. | Payment has been reversed by payer by revoking authorization. Contact payer to resolve the issue. |
| R34 | Limited Participation DFI | RDFI participation has been limited by a federal or state supervisor | Contact the payer to update payment method or payment account. Stop any recurring payments from this account. If the transaction you received this code on is a prenote, don't process any further transactions on this account. |
Appendix: Test accounts for bank verification
| Usecase | Login Credential (Sandbox) | Bank Name |
|---|---|---|
| Single CHECKING Account | pyplopenbankingubsb.site16441.1 site16441.1 | DEMO BANK |
| Multiple CHECKING/SAVINGS Account | pyplopenbankingubsb.site16441.2 site16441.2 | DEMO BANK |
| One Checking and One CD | pyplopenbankingubsb.site16441.5 site16441.5 | DEMO BANK |
| No CHECKING/SAVING Account | pyplopenbankingub.site16441.4 site16441.4 | DEMO BANK |
| Multiple Holders | pyplopenbankingubsb.site16441.3 site16441.3 | DEMO BANK |
| Business Account | pyplopenbankingubsb.site16441.2 site16441.2 Account last 4: 7753 | |
| Oauth Bank | pyplopenbankingubsb.site19335.1 site19335.1 | DEMO BANK - Dag Oauth Site |
| ACCOUNT_LOCKED | Username: error_407 Password: error_407 | |
| INCORRECT_CREDENTIALS | Username: error_402 Password: error_402 | |
| INVALID_ADDL_INFO_PROVIDED | Site: Dag Site Multilevel Username: agg.site16442.1 Password: site16442.1 Note: Enter Security Token answer incorrectly |
|
| ADDL_AUTHENTICATION_REQUIRED | Username: error_518 Password: error_518 | |
| CREDENTIALS_UPDATE_NEEDED | Username: error_410 Password: error_410 | |
| NEW_AUTHENTICATION_REQUIRED | Username: error_506 Password: error_506 | |
| SITE_UNAVAILABLE | Username: error_409 Password: error_409 | |
| SITE_BLOCKING_ERROR | Username: error_426 Password: error_426 | |
| USER_ACTION_NEEDED_AT_SITE | Username: error_406 Password: error_406 | |
| TECH_ERROR | Username: error_403 Password: error_403 |