Transfer statuses & webhooks
status tells you whether money moved, and transfer.updated webhooks tell you when it changes. Use this page to decide when a payment counts as successful and how to handle the cases where it doesn't.
Don't treat a 2xx from POST /transfers as success. Funds have arrived when the transfer reaches completed. For card payments, a cardDetails.status of confirmed means the issuer approved the authorization; the transfer stays pending until funds reach the merchant's wallet.
Transfer statuses
| Status | Description |
|---|---|
created |
A transfer has been created |
queued |
A transfer that is part of a group will have the queued status until the preceding transfer has successfully completed |
pending |
The transfer is in progress, but not yet completed |
completed |
The transfer has completed |
canceled |
The transfer was canceled before it moved, or it's part of a transfer group and an earlier transfer failed |
failed |
The transfer did not succeed |
reversed |
The transfer completed, but funds were returned to the source |
awaiting-capture |
API version v2026.10.00 and later. The transfer has been accepted and funds are reserved on the originating side, but the capture has not completed |
Each leg also has a rail-specific status under source and destination:
| Rail | Status field | Status reference |
|---|---|---|
| Card | cardDetails.status |
Card transfer statuses |
| ACH | achDetails.status |
ACH statuses |
| Instant payments (RTP or FedNow) | instantBankDetails.status |
Instant payment statuses |
| Push to card | cardDetails.status |
Push to card |
Transfer webhooks
Subscribe to these webhook events instead of polling. Every payload includes the transferID; call the retrieve a transfer endpoint for full details.
| Event | Fires when | Watch for |
|---|---|---|
transfer.created |
The transfer is created | Store the transferID |
transfer.updated |
The transfer or one of its legs changes status | completed, failed, reversed, canceled |
cancellation.created, cancellation.updated |
A cancellation is requested or changes status | completed or failed |
refund.created, refund.updated |
A card refund is requested or changes status | completed or failed |
dispute.created, dispute.updated |
A cardholder disputes a payment, or the dispute changes | See disputes |
Create transfer responses
The HTTP code from POST /accounts/{accountID}/transfers (API reference) tells you whether Moov accepted the request, not whether money moved. Send X-Wait-For: rail-response to get the payment network's answer in the response, and handle timeouts.
| HTTP code | Meaning | What to do |
|---|---|---|
| 200 OK | Transfer created; with X-Wait-For, the body includes the rail response |
Read status and the rail details, then follow transfer.updated |
| 201 Created | Transfer created, but the synchronous rail response failed, so you get the asynchronous object | Retrieve the transfer later or wait for transfer.updated |
| 202 Accepted | Transfer or refund created, but the network didn't answer within 15 seconds | Don't mark it successful or ship goods yet; retrieve it later or wait for transfer.updated |
| 400 Bad request | The payload is invalid | Fix the request using the error message |
| 409 Conflict | A transfer already exists for this X-Idempotency-Key; the body contains it |
Use that transfer. Never retry with a new key, which creates a second transfer |
| 422 Unprocessable content | The request failed validation | Fix the fields named in the error; retrying unchanged fails the same way |
| 429 Too many requests | Rate limited | Wait the number of milliseconds in the error, then retry with the same idempotency key |
Why a transfer failed
A transfer moves from pending to failed when funds don't reach the destination, usually within 2 business days of creation. Common causes:
- The source account (bank account or linked card) does not have sufficient funds for the amount of the transfer
- The source account or transfer recipient closed their account (bank account or linked card) so it no longer exists
- The issuer of the linked card denies the transfer attempt for a number of reasons (see the declines guide)
- A phone number or email was reused when linking a card (these must be unique to each cardholder)
Failure reasons
The retrieve a transfer response explains a failure in failureReason:
failureReason |
Description |
|---|---|
source-payment-error |
A failure occurred at the source. The failure code is provided in the rail details under the source object. American Express transactions under $1 also return this error. |
destination-payment-error |
A failure occurred at the destination. The failure code is provided in the rail details under the destination object. |
wallet-insufficient-funds |
Transfer failed due to insufficient funds in the source wallet. |
rejected-high-risk |
Transfer was flagged with potential fraud and rejected by Moov. |
processing-error |
Moov encountered an unexpected error processing the transfer. |
Why a transfer was reversed
A transfer moves from completed to reversed when funds reached the destination but have to be returned, up to 60 days after the ACH effective date. This happens when:
- A fraudulent, unauthorized, or unrecognized charge was made
- Someone used the wrong bank details to pay for goods or services
Moov returns the funds to the payer by debiting the wallet of the account that received them. If that leaves a negative balance, the recipient must fund the wallet to cover it. For ACH, see returns; to send money back yourself, see reversals.
What to do when something goes wrong
Each case below arrives as a webhook, sometimes weeks after the payment completed. Respond with a 2xx within 5 seconds and process each eventID once; see handle deliveries.
| What happened | What it means | What to do |
|---|---|---|
A card is declinedtransfer.updated · failed |
The issuer refused the charge; no money moved | Read source.cardDetails.failureCode and ask for another card. See declines. |
A cardholder disputes a paymentdispute.created, then dispute.updated |
Moov debited the merchant's wallet; the transfer stays completed |
Respond with evidence before respondBy, or accept. Don't refund a disputed payment. See disputes. |
A refund failsrefund.updated · failed |
The card network declined the refund; Moov credited the wallet back | Retry the refund for the same transfer. See refunds. |
An ACH debit is returned during the holdtransfer.updated · failed |
The bank returned it before funds were released, so the wallet never saw the money | Read achDetails.return.code and follow the required action. See return codes. |
An ACH debit is returned after funds were releasedtransfer.updated · reversed |
Moov took the amount back from the wallet, even if it was already paid out. Unauthorized returns can arrive for 60 days after the ACH effective date. | Follow the return code's required action and check the wallet balance. See how a return changes the transfer. |
An ACH payout is returnedtransfer.updated · reversed |
The receiving bank returned the credit (for example R03, no account); the amount went back to the wallet |
Ask the recipient for a new bank account. See ACH returns. |
An instant payment is rejectedtransfer.updated · failed |
The receiving bank rejected it, and the amount stayed in the wallet. Some failure codes mark the bank account errored. |
Read instantBankDetails.failureCode, then pay out with same-day ACH. See instant payouts. |
A push-to-card payout failstransfer.updated · failed |
The issuer declined it or a velocity limit was hit; the amount and payout fee went back to the wallet | Read failureReason and cardDetails.failureCode. See push to card. |
A sweep payout failssweep.updated · failed |
Payouts pause, and the sweep keeps accruing as action-required. Failed sweeps aren't retried. |
Add and verify a new bank account, then set it on the sweep. See sweeps. |
The wallet can't cover ittransfer.updated · failed |
The transfer failed with failureReason wallet-insufficient-funds: the source wallet's available balance didn't cover the amount and any fees |
Fund the wallet and send a new transfer. See wallet balance. |
Next steps
- Set up webhooks to receive these events
- Refund, reverse, or cancel a payment
- Handle ACH returns