ACH Guide
Accept bank account (ACH) payments and handle NACHA returns correctly.
ACH (Automated Clearing House) payments let you debit a customer's US bank account directly. ACH is commonly used for high-value transactions, recurring billing, and healthcare payments.
ACH vs. card payments
| ACH | Card | |
|---|---|---|
| Settlement | 1–3 business days | Next business day |
| Return window | Up to 60 days (R10) | 60–120 days (chargeback) |
| Cost | Lower per-transaction | Higher per-transaction |
| Failure mode | R-code returns | Declines |
Authorization language (NACHA requirement)
Before debiting a bank account, you must obtain the customer's authorization. NACHA requires specific language depending on the payment type:
You must display NACHA-compliant authorization language before collecting bank account details. See ACH Authorization Language → for the exact required text.
Create an ACH payment
curl -X POST https://sandbox-api.cresoracommerce.com/api/v1/transactions/sale \
-H "Authorization: Bearer csk_test_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: idem_$(uuidgen)" \
-d '{
"amount": "500.00",
"currency": "USD",
"payment_method": "ach_debit",
"merchant_id": "mrch_xxxxxxxxxx",
"bank_account": {
"routing_number": "021000021",
"account_number": "1234567890",
"account_type": "checking",
"account_holder_name": "Jane Smith"
},
"authorization_type": "internet"
}'import requests, uuid
requests.post(
"https://sandbox-api.cresoracommerce.com/api/v1/transactions/sale",
headers={
"Authorization": "Bearer csk_test_xxxxxxxxxxxx",
"Idempotency-Key": f"idem_{uuid.uuid4()}",
},
json={
"amount": "500.00",
"currency": "USD",
"payment_method": "ach_debit",
"merchant_id": "mrch_xxxxxxxxxx",
"bank_account": {
"routing_number": "021000021",
"account_number": "1234567890",
"account_type": "checking",
"account_holder_name": "Jane Smith",
},
"authorization_type": "internet",
},
)await fetch("https://sandbox-api.cresoracommerce.com/api/v1/transactions/sale", {
method: "POST",
headers: {
Authorization: "Bearer csk_test_xxxxxxxxxxxx",
"Content-Type": "application/json",
"Idempotency-Key": "idem_" + crypto.randomUUID(),
},
body: JSON.stringify({
amount: "500.00",
currency: "USD",
payment_method: "ach_debit",
merchant_id: "mrch_xxxxxxxxxx",
bank_account: {
routing_number: "021000021",
account_number: "1234567890",
account_type: "checking",
account_holder_name: "Jane Smith",
},
authorization_type: "internet",
}),
});ACH returns
ACH returns occur when the receiving bank rejects the debit. Cresora fires an ach.return.received webhook:
{
"event": "ach.return.received",
"payment_id": "pay_xxxxxxxxxxxx",
"return_code": "R01",
"return_reason": "Insufficient funds"
}Common return codes:
| Code | Reason | Action |
|---|---|---|
R01 | Insufficient funds | Retry after agreement from customer |
R02 | Account closed | Stop attempting; update payment method |
R10 | Customer advises not authorized | Stop immediately; dispute likely |
R29 | Corporate not authorized | Re-obtain written authorization |
R10 (customer advises not authorized) is a serious signal. Stop all retries immediately and investigate. Continued debiting after an R10 violates NACHA rules.
Test routing numbers
| Routing | Result |
|---|---|
021000021 | Approval |
999999999 | R01 — Insufficient funds |
111111118 | R10 — Not authorized |