When returns arrive
Returns land within windows set by the ACH rules, which vary by reason:- Administrative returns (wrong or closed account, invalid number) usually arrive within about two banking days.
- Unauthorized returns (the account holder disputes the debit) can arrive up to 60 calendar days after settlement.
unauthorized, administrative, and
other, so you can treat them differently.
How Spritz surfaces a return
When a debit is returned:- The deposit’s
statusanddebitStatusbecomereturned, and the deposit carries areturnCodeandreturnReason. - The funding source becomes
disabled, withstatusReason: "returned"andpermanent: true. Read the ACH code from the deposit or return record; private source-disablement inputs are not returned. - The
achDebitReturn.createdwebhook fires.achDebitReturn.updatedcan fire as details change. Delivery order is not guaranteed.
dr_... ID from its webhook:
cryptoStateAtReturn is the key exposure signal: a return before the crypto is released
costs you nothing, while a return after fully_confirmed delivery is a realized loss.
Store returnCode for reconciliation and support, but branch the user experience only
on userAction. Treat returnReason as supporting text for logs and support tooling,
not as a stable machine-readable value.
User and frontend handling
Every return disables the bank account that produced it. Cache invalidation can make a funding-source read briefly lag the returned deposit, so reconcile it with bounded polling after eitherachDebitReturn.* webhook. Never offer the source again once it is
disabled. userAction is the authoritative result for the user’s wider ACH access.
Spritz’s escalation policy is intentionally not public; do not derive or reproduce it
from return codes or return counts.
Use direct, action-oriented copy:
Do not show a retry button for the disabled source. For
none, offer another bank. For
every other action, show the support path.
Common return codes
ACH return codes follow the NACHA standard (R01, R02, and so on). The ones you’ll
see most:
This is a subset. The full set of codes is defined by NACHA, and
returnReason carries
the human-readable text for whatever code applies.
Preventing avoidable returns
Only debit accounts the user linked and clearly authorized. Treat a blocked deposit as final for that attempt: do not vary amounts or retry in a loop. Reconcile every return promptly and followuserAction; Spritz may pause a source, user, or integration before
any new money moves.
Reconciling
1
Listen for the webhook
Subscribe to
achDebitReturn.created and achDebitReturn.updated so you learn about
returns and synchronize current state. Subscribe to achDebit.returned separately
when your integration sends push notifications. Never infer a return push from a
generic return update.2
Persist the return
Key your record by the return
id. Fetch
GET /v1/integrator/ach-debit/returns/{id} for authoritative state whenever either
event arrives. Reconcile the paginated GET /v1/integrator/ach-debit/returns feed
after outages or missed deliveries.3
Assess exposure
Use
cryptoStateAtReturn and lossAmountUsd to decide whether the return is a real
loss or was caught before delivery.4
Update the user experience
Remove the disabled source from the payment picker. Branch on
userAction to offer a
different bank or the support path.