Transfer statuses & webhooks

A transfer's 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 declined
transfer.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 payment
dispute.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 fails
refund.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 hold
transfer.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 released
transfer.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 returned
transfer.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 rejected
transfer.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 fails
transfer.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 fails
sweep.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 it
transfer.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