Bank Account Payment Flow (ACH)
Overview
Bank account payments use ACH (Automated Clearing House) transfers. Unlike card payments, ACH transactions have delayed settlement — the payment is accepted by the processor but funds are not immediately available. This introduces the ACCEPTED state, which is unique to bank account payments.
Key differences from card payments:
authorizeCardandpartialAuthorizationare ignored forBANK_ACCOUNT- Only
SALEtransaction type (no pre-auth) - Requires valid customer consent
- Settlement takes 3-5 business days
ACCEPTEDintermediate state beforeCOMPLETED- Higher risk of post-settlement failure (returned ACH)
Sequence Diagram
API Request
Sample Request — Bank Account Payment
curl -X POST "https://api-stg.uhg.com/api/financial/commerce/nonprodcheckout/v2/payments" \
-H "Authorization: Bearer <token>" \
-H "X-Merchant-Id: b955db5e-aef2-47de-bbb9-c80b9cc16e8f" \
-H "X-Upstream-Env: dev" \
-H "Content-Type: application/json" \
-d '{
"merchantTransactionId": "ach-20260404-001",
"amount": 50000,
"currencyCode": "USD",
"customer": {
"hsid": "b313c1d1-b5b6-4ec7-8b5a-3a9cf7755060"
},
"consent": {
"type": "ONLINE",
"timestamp": "2026-04-04T09:00:00Z",
"ipAddress": "192.168.1.100"
},
"paymentAllocations": [
{
"amount": 50000,
"paymentMethodId": "d5e6f7a8-b9c0-1234-5678-90abcdef5678"
}
]
}'
Consent Object
ACH payments require valid consent. The consent object records proof that the customer authorized the debit.
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Consent type: ONLINE, WRITTEN, VERBAL |
timestamp | string (ISO 8601) | Yes | When consent was given |
ipAddress | string | Recommended | Customer's IP address at time of consent |
ACH consent is a NACHA regulatory requirement. Processing a bank account payment without valid consent is a compliance violation. The consent object must be populated with accurate, verifiable information.
API Response — 202 Accepted
{
"data": {
"id": "880e8400-e29b-41d4-a716-446655440000",
"merchantTransactionId": "ach-20260404-001",
"amount": 50000,
"status": "INITIATED",
"authorizeCard": false,
"partialAuthorization": false
}
}
GET — After Acceptance (200 OK)
{
"data": {
"id": "880e8400-e29b-41d4-a716-446655440000",
"amount": 50000,
"status": "ACCEPTED",
"paymentAllocations": [
{
"id": "dddd1111-2222-3333-4444-555566667777",
"amount": 50000,
"status": "ACCEPTED",
"paymentMethod": {
"type": "BANK_ACCOUNT",
"bankAccount": {
"lastFour": "6789",
"bankName": "Chase"
}
}
}
]
}
}
Webhook — PAYMENT_ACCEPTED
Fired when the ACH processor accepts the transaction (before settlement).
{
"name": "PAYMENT_ACCEPTED",
"source": "merchant-portal",
"payload": {
"id": "880e8400-e29b-41d4-a716-446655440000",
"merchantTransactionId": "ach-20260404-001",
"amount": 50000,
"status": "ACCEPTED",
"paymentAllocations": [
{
"id": "dddd1111-2222-3333-4444-555566667777",
"amount": 50000,
"status": "ACCEPTED"
}
]
}
}
Failure Modes
| Scenario | When | Payment Status | Webhook |
|---|---|---|---|
| Invalid consent | At request time | FAILED | PAYMENT_FAILED |
| Insufficient funds | During processing | FAILED | PAYMENT_FAILED |
| Account closed | During processing | FAILED | PAYMENT_FAILED |
| ACH return | 3-5 days post-acceptance | FAILED (transitions from ACCEPTED) | PAYMENT_FAILED |
ACH returns can occur days after the ACCEPTED state. The system handles Stripe webhook events for ACH failures and transitions the payment from ACCEPTED → FAILED. Merchants must implement PAYMENT_FAILED webhook handling to catch late ACH failures.