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.

📘

Use externalId for safe retries

For Treasury, PCE treats the externalId in the request body as the idempotency key; there's no separate header. Send a unique externalId per collection, and retrying with the same value creates it only once.

📘

Get authorization before you debit

An ACH debit pulls money from someone's account, so NACHA requires their authorization (a mandate). Set processingDetail.authType to 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 gated

One-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

ParameterRequiredDescription
methodSet to ACH
externalIdRecommendedYour own reference ID, also the idempotency key. Retrying with the same value won't create a duplicate.
sourceThe bank account to debit. See Source types for the supported shapes.
destination.account.id (or externalId)The Passport Account to credit
amountAmount 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)

ParameterRequiredDescription
source.contact.id or externalIdUnique identifier of the Contact
source.contact.externalAccount.id or externalIdUnique identifier of the External Account linked to the Contact

One-time bank account (inline, nothing saved, Scenario 2; Business Customers only, requires program enablement)

ParameterRequiredDescription
source.externalAccount.holderNameName of the account holder
source.externalAccount.accountNumberBank account number
source.externalAccount.routingNumber9-digit routing number
source.externalAccount.typeSAVING or CHECKING
source.externalAccount.holderTypeCONSUMER or CORPORATE
🚧

PENDING-PUBLISH: the exact parameter path for one-time source details (shown here as source.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).

ParameterRequiredDescription
processingDetail.processingModeRecommendedFORWARD (default): settles next business day (end-of-day batch). SAME_DAY: settles same day if submitted before cutoff, otherwise next business day.
processingDetail.companyNameRecommendedName populated in the NACHA file. Defaults to your program's configuration if not provided.
processingDetail.companyDescriptionRecommendedShort description shown on the payer's bank statement. Defaults to your program's configuration if not provided.
processingDetail.authTypeConditionalHow the debit was authorized: WRITTEN (signed), PHONE (recorded call), or ONLINE (digital/web).
processingDetail.addendaRecommendedReference 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 and FAILED reason 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:

PracticeDescription
Get and retain authorizationPer NACHA, hold a valid mandate for every ACH debit; you may need to produce it within 10 days.
Use the correct auth typePass processingDetail.authType (WRITTEN, PHONE, ONLINE) to reflect how authorization was obtained.
Verify one-time account detailsFor one-time collections, check the account and routing numbers before submitting to reduce returns.
Set meaningful descriptorsPopulate processingDetail.companyName and companyDescription so the debit is identifiable on the payer's statement.

Next steps

See also


.readme-logo { display: none !important; }