Collect via ACH
Debit an external bank account into your account using ACH direct debit.
Collecting via ACH debits an external bank account and credits a Passport Account over the ACH (Automated Clearing House) network. It's an ACH direct debit. Use it to collect customer payments, fees, or invoice payments, or to debit an account for payroll funding. You collect from a customer or third party saved as a Contact, or from a one-time bank account. For the full field list, jump to the Request reference.
Funding your own Passport Account from your own bank is a transfer of your own money, not a collection. See Transfer funds.
Common use cases
- Collect a payment from a customer's bank account
- Collect platform fees, subscriptions, or commissions
- Collect recurring or scheduled payments
- Collect an outstanding invoice
- Debit an account for payroll funding
Make your first collection
The fastest way to see it work: collect from a saved customer (Contact) into a Passport Account with the minimal fields below. The full set of options is in the Request reference.
POST /v1/customer/id/{id}/transaction
{
"externalId": "ach-collect-first-001",
"method": "ACH",
"amount": "300.00",
"source": {
"contact": {
"externalId": "customer-contact-001",
"externalAccount": { "externalId": "customer-bank-001" }
}
},
"destination": { "account": { "externalId": "passport-account-001" } }
}You'll get back a transaction with status: SCHEDULED. Store the returned id and your externalId to track it and for reconciliation.
UseexternalIdfor safe retriesFor Treasury, PCE treats the
externalIdin the request body as the idempotency key; there's no separate header. Send a uniqueexternalIdper collection, and retrying with the same value creates it only once.
Get authorization before you debitAn ACH debit pulls money from someone's account, so NACHA requires their authorization (a mandate). Set
processingDetail.authTypeto how you obtained it, keep the proof, and be ready to produce it within 10 days of a request.
PENDING-PUBLISH (Sandbox test data)Test in the sandbox first, using the accounts, routing numbers, and amounts on Sandbox test data. They exercise success, returns, NSF, OFAC holds, and inactive or blocked accounts. The page and its values are pending; eng to supply.
Scenarios
Every collection follows the transaction lifecycle. Because it's an inbound ACH debit, funds credit to the Passport Account only after the good-funds period. The only thing that changes per scenario is the source you collect from, so pick the one that matches your situation.
PENDING-PUBLISH (examples)Request values are illustrative. Response bodies are representative and may be incomplete (modeled on the Treasury transaction resource, not captured from a live call). Confirm the exact response fields, including
transactionClass, against live data before publishing.
Before you begin (all scenarios)
- The Passport Account you're crediting is active.
Each scenario below adds the source specific to where you're collecting from.
Scenario 1: Collect from a customer you bill regularly
(collect from a saved Contact)
Use this to collect a payment, fee, or invoice from a customer's bank account when you'll bill them again. Save them once as a Contact, then reference the contact on every collection.
You'll also need: the customer saved as a Contact with a linked external account, and their authorization to debit.
Request
POST /v1/customer/id/{id}/transaction
{
"externalId": "ach-collect-contact-001",
"method": "ACH",
"amount": "300.00",
"source": {
"contact": {
"externalId": "customer-contact-001",
"externalAccount": { "externalId": "customer-bank-001" }
}
},
"destination": { "account": { "externalId": "passport-account-001" } },
"processingDetail": { "processingMode": "FORWARD", "authType": "ONLINE", "companyDescription": "Invoice 4471" }
}Response
{
"resourceName": "transaction",
"url": "/v1/customer/id/4225975/transaction/id/230492021",
"id": 230492021,
"externalId": "ach-collect-contact-001",
"status": "SCHEDULED",
"statusDate": "06/29/2026 09:40:55",
"amount": 300,
"method": "ACH",
"statusReason": "On User Request",
"source": {
"contact": { "resourceName": "contact", "id": 4019600, "url": "/v1/customer/id/4225975/contact/id/4019600" }
},
"destination": {
"account": { "resourceName": "account", "id": 9915272, "url": "/v1/customer/id/4225975/account/id/9915272" }
}
}Scenario 2: Collect from a one-time payer
(one-time bank account)
Use this for a one-off collection when you don't want to save the payer. You pass the bank details inline.
You'll also need: the payer's holderName, routingNumber, and accountNumber, and their authorization.
One-time debit is gatedOne-time ACH debit is available for Business Customers only and must be enabled for your program before use. Confirm it's turned on before relying on this scenario.
Request
POST /v1/customer/id/{id}/transaction
{
"externalId": "ach-collect-onetime-001",
"method": "ACH",
"amount": "150.00",
"source": {
"externalAccount": {
"holderName": "Jane Doe",
"accountNumber": "987654321098",
"routingNumber": "021000089",
"type": "CHECKING",
"holderType": "CONSUMER"
}
},
"destination": { "account": { "externalId": "passport-account-001" } },
"processingDetail": { "processingMode": "FORWARD", "authType": "WRITTEN" }
}Response
{
"resourceName": "transaction",
"url": "/v1/customer/id/4225975/transaction/id/230492033",
"id": 230492033,
"externalId": "ach-collect-onetime-001",
"status": "SCHEDULED",
"statusDate": "06/29/2026 10:05:18",
"amount": 150,
"method": "ACH",
"statusReason": "On User Request",
"source": {
"externalAccount": { "holderName": "Jane Doe", "type": "CHECKING", "holderType": "CONSUMER" }
},
"destination": {
"account": { "resourceName": "account", "id": 9915272, "url": "/v1/customer/id/4225975/account/id/9915272" }
}
}Track the transaction
Subscribe to webhooks or GET the transaction to follow it to completion. Because a collection settles only after the good-funds period, watch for the status change rather than assuming success on submit. The statuses, the webhook payload, and the event types all live in Transaction lifecycle.
Request reference
The complete set of fields for the create-transaction request. Scenarios above use subsets of these.
Core parameters
| Parameter | Required | Description |
|---|---|---|
method | ✓ | Set to ACH |
externalId | Recommended | Your own reference ID, also the idempotency key. Retrying with the same value won't create a duplicate. |
source | ✓ | The bank account to debit. See Source types for the supported shapes. |
destination.account.id (or externalId) | ✓ | The Passport Account to credit |
amount | ✓ | Amount to debit (in USD) |
Source types
Provide one source shape, matching the scenario.
Saved Contact (a customer or third party you collect from, Scenario 1)
| Parameter | Required | Description |
|---|---|---|
source.contact.id or externalId | ✓ | Unique identifier of the Contact |
source.contact.externalAccount.id or externalId | ✓ | Unique identifier of the External Account linked to the Contact |
One-time bank account (inline, nothing saved, Scenario 2; Business Customers only, requires program enablement)
| Parameter | Required | Description |
|---|---|---|
source.externalAccount.holderName | ✓ | Name of the account holder |
source.externalAccount.accountNumber | ✓ | Bank account number |
source.externalAccount.routingNumber | ✓ | 9-digit routing number |
source.externalAccount.type | ✓ | SAVING or CHECKING |
source.externalAccount.holderType | ✓ | CONSUMER or CORPORATE |
PENDING-PUBLISH: the exact parameter path for one-time source details (shown here assource.externalAccount.*; the source page lists the fields without a prefix).
Processing detail
Optional as a whole, but certain fields may be required depending on your program's configuration (set by your Program Manager, the platform partner you onboarded through).
| Parameter | Required | Description |
|---|---|---|
processingDetail.processingMode | Recommended | FORWARD (default): settles next business day (end-of-day batch). SAME_DAY: settles same day if submitted before cutoff, otherwise next business day. |
processingDetail.companyName | Recommended | Name populated in the NACHA file. Defaults to your program's configuration if not provided. |
processingDetail.companyDescription | Recommended | Short description shown on the payer's bank statement. Defaults to your program's configuration if not provided. |
processingDetail.authType | Conditional | How the debit was authorized: WRITTEN (signed), PHONE (recorded call), or ONLINE (digital/web). |
processingDetail.addenda | Recommended | Reference data for reconciliation, such as an invoice number, customer reference ID, or order ID. |
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 transaction is created. Submission checks:
- Required fields are present and correctly formatted.
- The destination Passport Account is active.
- The source resolves (a saved Contact, or valid one-time bank details).
- Authorization for the debit is present.
Other conditions can only be judged once the collection is in flight, such as an inactive or blocked account, a compliance hold, or a bank return. These surface after creation as PENDING or FAILED; see Transaction lifecycle. For error codes, see Error Codes and Messages.
Statuses
Collect via ACH uses the shared transaction lifecycle. See it for every status, and for the good-funds period that holds inbound funds in PROCESSING before they're realized to COMPLETED.
If a collection fails
A collection moves to FAILED when the processing interval lapses without settlement, or when the bank returns the debit (for example, insufficient funds or a closed account; the return code is in the status reason). A PENDING collection is on hold because the source or destination account is inactive or blocked. In both cases, resolve the underlying issue and submit a new collection. For the specific return and error codes, see External Account Error codes and Transactions Error codes. To simulate returns and holds in the sandbox, use the trigger values on Sandbox test data.
PENDING-PUBLISH: the exact return andFAILEDreason strings, which error-codes page documents each, and the sandbox trigger values (eng to supply).
Go live
The shared pre-production checklist (production credentials, webhook subscription and signature validation, idempotency, and sandbox testing) is in Getting Started. Specific to collecting via ACH, also confirm:
- You hold a valid authorization (mandate) for every debit and can produce the proof (NACHA).
- If you collect from one-time payers, one-time ACH debit is enabled for your program.
Best practices
General practices (set a unique externalId, subscribe to webhooks, test in sandbox) are in Getting Started. Specific to collecting via ACH:
| Practice | Description |
|---|---|
| Get and retain authorization | Per NACHA, hold a valid mandate for every ACH debit; you may need to produce it within 10 days. |
| Use the correct auth type | Pass processingDetail.authType (WRITTEN, PHONE, ONLINE) to reflect how authorization was obtained. |
| Verify one-time account details | For one-time collections, check the account and routing numbers before submitting to reduce returns. |
| Set meaningful descriptors | Populate processingDetail.companyName and companyDescription so the debit is identifiable on the payer's statement. |
Next steps
See also
- Save Payees as Contacts: save the customers you collect from
- Transfer funds: fund a Passport Account from your own bank (a transfer, not a collection)
- Collect via Wire: collect by wire drawdown instead of ACH
- Error Codes and Messages: resolve a failed collection