Accept an ACH Payment
Charge a customer's bank account via ACH in a single API call
Accepting an ACH payment debits a customer's bank account and credits your merchant account over the ACH network. It's the bank-account counterpart to a card Sale: the customer pays you for goods or services, on a lower-cost rail. You submit it on the same payment API — set tenderType to ACH, pass the bank account, and set the entry class that matches your authorization. For the full field list, jump to the Request reference.
Moving funds already inside your program (funding a Passport Account, disbursing, or a treasury-level pull) is a different job — see Treasury → Collections.
Common use cases
- Take a bank-account payment at online checkout instead of a card
- Collect an invoice or bill payment directly from a customer's bank account
- Accept recurring bank-account payments for subscriptions or installments
Make your first payment
The fastest way to see it work: charge a bank account with the minimal fields below. The full set of options is in the Request reference.
POST /checkout/v3/payment
Content-Type: application/json
x-api-key: YOUR_API_KEY
{
"merchantId": 1000157980,
"amount": 120.00,
"tenderType": "ACH",
"paymentType": "Sale",
"entryClass": "PPD",
"bankAccount": {
"name": "Alex Johnson",
"routingNumber": "021000021",
"accountNumber": "1234567890",
"type": "Checking"
},
"source": "API"
}You'll get back a 201 Created. Because ACH isn't approved instantly by an issuer, the payment starts as status: PendingACH and settles over the following business days. Store the returned id (use it to retrieve or void the payment before it settles) and paymentToken (use it for follow-up refunds after settlement).
PENDING-PUBLISHThe example response below mirrors the create-payment schema (
tenderType,amount,status,type,id,paymentToken). Confirm the exact ACH response echo — maskedbankAccount, and any ACH-specific fields (e.g.achIndicator,achAuthorizationEmail) — against a live sandbox ACH call before publish.
{
"created": "2026-08-20T07:11:30.9Z",
"id": 4100000000869901,
"paymentToken": "PYVrf077uthlfkIiAMXMEE0BJECoXkrf",
"merchantId": 1000157980,
"tenderType": "ACH",
"amount": "120.00",
"entryClass": "PPD",
"bankAccount": {
"name": "Alex Johnson",
"type": "Checking"
},
"status": "PendingACH",
"type": "Sale"
}The endpoint is documented in the API reference at POST /checkout/v3/payment.
UsereplayIdfor safe retriesAccept Payments uses the
replayIdfield in the request body for safe retries; there's no separate header. Send a uniquereplayIdper payment, and if a request with the same value arrives again, we return the original response instead of debiting the account twice. See Idempotent Requests.
Get authorization before you debitAn ACH debit pulls money from a customer's account, so NACHA requires their authorization. Set
entryClassto reflect how you obtained it (PPD,WEB,TEL,CCD,CTX), keep the proof, and be ready to produce it on request.
Scenarios
Every ACH payment follows the same payment lifecycle, starting at PendingACH. The only thing that changes per scenario is how you supply the bank account, so pick the one that matches the problem you're solving.
sequenceDiagram
participant You as Your Application
participant PCE as PCE
participant Bank as Customer's Bank
You->>PCE: POST /checkout/v3/payment (tenderType: ACH)
PCE->>PCE: Validate request + authorization
PCE-->>You: 201 Created (status: PendingACH)
PCE->>Bank: Submit ACH debit to network
Note over PCE: Settlement window (business days)
PCE-->>You: Webhook (settled or returned)
Before you begin (all scenarios)
- Your merchant account is active and enabled for ACH acceptance.
- You hold the customer's authorization to debit their account.
Scenario 1: Charge a bank account entered at checkout
(raw bank details passed inline)
Use this when a customer enters their bank details to pay you and you don't save them. Pass the routing number, account number, holder name, and account type directly in bankAccount, and set entryClass to match your authorization.
You'll also need: the customer's routing number, account number, account type, and authorization.
Request
POST /checkout/v3/payment
Content-Type: application/json
x-api-key: YOUR_API_KEY
{
"merchantId": 1000157980,
"amount": 250.00,
"tenderType": "ACH",
"paymentType": "Sale",
"entryClass": "WEB",
"bankAccount": {
"name": "Alex Johnson",
"routingNumber": "021000021",
"accountNumber": "1234567890",
"type": "Checking"
},
"customerName": "Alex Johnson",
"customerCode": "01455",
"source": "API"
}Scenario 2: Collect a business (B2B) payment
(corporate account, CCD entry class)
Use this to collect from a business customer's corporate account — for example, an invoice paid by another company. Set entryClass to CCD (or CTX if you're sending structured remittance addenda).
You'll also need: the business's authorization to debit their corporate account.
Request
POST /checkout/v3/payment
Content-Type: application/json
x-api-key: YOUR_API_KEY
{
"merchantId": 1000157980,
"amount": 4200.00,
"tenderType": "ACH",
"paymentType": "Sale",
"entryClass": "CCD",
"bankAccount": {
"name": "Northwind Supplies LLC",
"routingNumber": "021000021",
"accountNumber": "9987654321",
"type": "Checking"
},
"customerCode": "INV-4471",
"source": "API"
}Track the payment
An ACH payment starts at PendingACH and doesn't confirm on submit, so follow it rather than assuming success. Retrieve it with GET /checkout/v3/payment/{id}, or subscribe to webhooks.
PENDING-PUBLISHConfirm the ACH webhook event names for settlement and return (the card flow uses
PaymentSuccess/PaymentFail; ACH return handling may use different events) against Webhook Event Types before publish.
The statuses, the flow to settlement, and the webhook events all live in Payment Lifecycle and Webhook Event Types.
Request reference
The complete set of fields for the create-payment request when tenderType is ACH. Scenarios above use subsets of these.
Core parameters
| Parameter | Required | Description |
|---|---|---|
merchantId | ✓ | Your PCE merchant identifier that receives the payment. |
amount | ✓ | Amount to charge, in the account currency (USD by default). |
paymentType | ✓ | Set to Sale. |
tenderType | ✓ | Set to ACH. |
bankAccount | ✓ | The bank account to debit. Required when tenderType is ACH. See Bank account fields. |
entryClass | ✓ | ACH entry class (SEC code): PPD, WEB, TEL, CCD, or CTX. Required when tenderType is ACH. |
replayId | Recommended | Your unique retry key. Retrying with the same value returns the original response instead of debiting again. See Idempotent Requests. |
customerName | Optional | Customer's full name. |
customerCode | Optional | Your reference for the customer, included in settlement. |
source | Optional | Origin of the payment. Possible values: API, QuickPay, Recurring, Link2Pay, Terminal. |
Bank account fields
Required when tenderType is ACH.
| Parameter | Required | Description |
|---|---|---|
bankAccount.routingNumber | ✓ | 9-digit bank routing number. |
bankAccount.accountNumber | ✓ | Bank account number. |
bankAccount.name | ✓ | Full name of the bank account holder. |
bankAccount.type | ✓ | Checking or Savings. |
Validation
The prerequisites above are the validations, and PCE enforces them when you submit. A submission is checked synchronously; if a check fails, the request returns an error and no payment is created. Submission checks:
- Required fields are present and correctly formatted (routing number, account number, account type, entry class).
- Your merchant account is enabled for ACH acceptance.
- Authorization for the debit is present.
Conditions that can only be judged once the debit is in flight — insufficient funds, a closed account, or a bank return — surface after submission as the payment moves out of PendingACH. See Payment Lifecycle.
Statuses
An ACH payment returns PendingACH on submit and resolves over the following business days as the debit settles or is returned. Accept Payments uses the shared Payment Lifecycle for every status and how a payment progresses to settlement.
PENDING-PUBLISHDocument the ACH settled/returned terminal states and typical timing on Payment Lifecycle (confirm against the MXM status model and ACH return codes) before publish.
Go live
The shared pre-production checklist (production credentials, webhook subscription, idempotency, and sandbox testing) is in Getting Started. Specific to ACH, also confirm:
- ACH acceptance is enabled for your
merchantId. - You hold a valid authorization for every debit and set the matching
entryClass. - You handle the
PendingACH→ settled/returned flow rather than treating the payment as final on submit. - You generate a unique
replayIdper payment for safe retries.
Best practices
General practices (set a unique replayId, subscribe to webhooks, test in sandbox) are in Getting Started. Specific to ACH:
| Practice | Description |
|---|---|
| Set the correct entry class | Match entryClass to how you obtained authorization (PPD/WEB/TEL consumer, CCD/CTX business). |
| Retain authorization | Keep proof of the customer's authorization; you may need to produce it on request. |
| Verify bank details | Check the routing and account numbers before submitting to reduce returns. |
| Wait for settlement | Don't fulfil high-value orders until the ACH payment clears PendingACH. |
Next steps
See also
- Online ACH Payments: overview and SEC entry classes
- Sale: the card counterpart on the same payment API
- Payment Lifecycle: statuses, tracking, and settlement
- Reports & Reconciliation: ACH Activity and ACH Returns
- Treasury → Collections: managing money already in your program (a different job)
Updated about 17 hours ago