Skip to main content
Version: v2

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:

  • authorizeCard and partialAuthorization are ignored for BANK_ACCOUNT
  • Only SALE transaction type (no pre-auth)
  • Requires valid customer consent
  • Settlement takes 3-5 business days
  • ACCEPTED intermediate state before COMPLETED
  • 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"
}
]
}'

ACH payments require valid consent. The consent object records proof that the customer authorized the debit.

FieldTypeRequiredDescription
typestringYesConsent type: ONLINE, WRITTEN, VERBAL
timestampstring (ISO 8601)YesWhen consent was given
ipAddressstringRecommendedCustomer's IP address at time of consent
Compliance

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

ScenarioWhenPayment StatusWebhook
Invalid consentAt request timeFAILEDPAYMENT_FAILED
Insufficient fundsDuring processingFAILEDPAYMENT_FAILED
Account closedDuring processingFAILEDPAYMENT_FAILED
ACH return3-5 days post-acceptanceFAILED (transitions from ACCEPTED)PAYMENT_FAILED
ACH Returns

ACH returns can occur days after the ACCEPTED state. The system handles Stripe webhook events for ACH failures and transitions the payment from ACCEPTEDFAILED. Merchants must implement PAYMENT_FAILED webhook handling to catch late ACH failures.