Skip to main content
Cresora Commerce
Integration Guides

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

ACHCard
Settlement1–3 business daysNext business day
Return windowUp to 60 days (R10)60–120 days (chargeback)
CostLower per-transactionHigher per-transaction
Failure modeR-code returnsDeclines

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:

🔒NACHA authorization

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
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"
  }'
Python
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",
    },
)
Node.js
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:

CodeReasonAction
R01Insufficient fundsRetry after agreement from customer
R02Account closedStop attempting; update payment method
R10Customer advises not authorizedStop immediately; dispute likely
R29Corporate not authorizedRe-obtain written authorization
Warning

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

RoutingResult
021000021Approval
999999999R01 — Insufficient funds
111111118R10 — Not authorized