Prompt
How do I set up ACH payments API workflows for recurring invoicing and return handling?
Latest observation
Here’s a practical way to set up ACH payments API workflows for recurring invoicing and return handling.
1) Core ACH workflow pieces
You generally need these building blocks:
- Customer bank account collection
- Bank account verification
- Mandate / authorization capture
- Payment initiation
- Invoice linkage
- Return / NSF handling
- Retry / dunning logic
- Reconciliation and reporting
ACH is not instant, so your workflow should be built around asynchronous states.
2) Recurring invoicing workflow
A. Collect and verify bank details
At onboarding:
- Collect bank account info securely
- Verify the account
- Instant verification via bank login/aggregation, or
- Micro-deposits, or
- Processor-provided verification
- Store a tokenized payment method, not raw bank data
B. Capture authorization
Before charging ACH, make sure you have a valid authorization:
- Customer agreement text
- Date/time accepted
- IP / metadata if needed
- Payment frequency and amount rules
- Cancellation terms
Store this with the customer profile because it may be needed for disputes.
C. Create invoice schedule
For recurring billing:
- Generate invoices on a schedule
- Attach the ACH payment method as the default payment source
- Set due date and grace period
- Define retry logic for failed payments
D. Submit ACH debit
When an invoice becomes due:
- Create payment intent / ACH debit
- Mark invoice as
processing - Submit to ACH network through your provider
- Wait for settlement / final result
Typical states:
pendingsubmittedsettledfailedreturned
E. Reconcile invoice and payment
When the debit settles:
- Mark invoice
paid - Record settlement date
- Save transaction ID / trace number
- Update customer balance
3) Recommended event-driven architecture
Use webhooks or callbacks from your payments provider.
Example events to handle
payment.createdpayment.submittedpayment.settledpayment.failedpayment.returnedcustomer.bank_account.verifiedinvoice.paid
Internal state machine
A simple pattern:
- Invoice created
- Payment initiated
- Await network result
- If settled → close invoice
- If returned → reopen invoice and start recovery flow
4) Return handling workflow
ACH returns can happen for many reasons:
- Insufficient funds
- Invalid account
- Unauthorized debit
- Account closed
- Stop payment
- Duplicate entry
A. Capture return data
When a return happens, store:
- Return code
- Return reason
- Return date
- Original transaction ID
- Amount
- Customer/account reference
B. Classify the return
Split returns into:
- Retryable: NSF, temporary issue
- Non-retryable: closed account, unauthorized, stop payment
C. Decide next action
For retryable returns:
- Notify customer
- Retry after X days
- Offer alternate payment method
For non-retryable returns:
- Suspend ACH attempts
- Request new bank account
- Escalate to collections if needed
D. Update invoice status
A returned payment usually means the invoice is not truly paid.
Possible handling:
- Change invoice back to
open - Add return fee if allowed and disclosed
- Log the return against the customer ledger
5) Retry strategy for recurring ACH
ACH retries should be conservative.
Suggested pattern:
- Retry only on eligible return codes
- Wait a few days between retries
- Limit attempts, for example 2–3 total
- Avoid repeated retries on unauthorized or closed accounts
Example:
- Day 0: debit submitted
- Day 2: return received NSF
- Day 5: retry once
- Day 8: final retry or move to alternate method
6) Suggested database objects
Customer
customer_idnameemailach_authorization_status
Bank account
bank_account_idcustomer_idtokenlast4routing_last4verified_statusactive
Invoice
invoice_idcustomer_idamountstatusdue_datepaid_at
ACH payment
payment_idinvoice_idbank_account_idamountstatustrace_numbersubmitted_atsettled_at
Return record
return_idpayment_idreturn_codereturn_reasonreceived_at
7) API endpoints you may want
A typical REST design might include:
POST /customersPOST /customers/{id}/bank-accountsPOST /bank-accounts/{id}/verifyPOST /subscriptionsPOST /invoicesPOST /invoices/{id}/collectPOST /payments/achGET /payments/{id}POST /webhooks/ach
8) Example flow
Recurring invoice payment
- Customer signs up and adds bank account
- You verify the account
- Customer authorizes recurring ACH debits
- Monthly invoice is generated
- Payment request is submitted
- Provider confirms settlement
- Invoice marked paid
Return handling
- ACH debit returns NSF
- Webhook receives return event
- Invoice marked unpaid again
- Customer notified
- Retry scheduled or alternate method requested
9) Important compliance and operational considerations
- Use a PCI-like secure posture even though ACH is not card data
- Store only tokenized bank details if possible
- Keep authorization evidence
- Respect NACHA rules and return windows
- Implement idempotency keys for payment creation
- Log all state transitions
- Protect against duplicate debits
- Have clear customer notifications for retries and returns
10) Best-practice implementation pattern
If you’re building this yourself or integrating a processor:
Use:
- Idempotent payment creation
- Webhook-driven updates
- State machine for each payment
- Separate invoice and payment records
- Return-code-based decision logic
Avoid:
- Assuming ACH is paid immediately
- Auto-retrying every failure
- Marking invoices paid before settlement
- Reusing raw bank details in multiple systems
11) Minimal workflow summary
- Collect and verify bank account
- Capture ACH authorization
- Generate recurring invoice
- Create ACH debit on due date
- Wait for settlement webhook
- If settled: mark invoice paid
- If returned: reopen invoice, classify return, retry or escalate
If you want, I can also provide:
- a sample ACH payments API design
- a webhook event schema
- a state machine diagram
- or a code example in Node.js, Python, or Ruby.
Observation history
Unlock observation history
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.