Skip to main content

What happened

An inbound transfer was sent back before Conduit could credit it to the customer. The transaction is in a terminal failed state. One code covers two situations, and they do not look the same on the wire. What decides it is where the money was headed, not which rail it arrived on: Read the case that matches where the funds were going. Branching on failureCode alone works for the first and never fires for the second — on either rail.

Case 1: the deposit was sent back before it was credited

A deposit headed for your customer’s own virtual account or wallet was sent back to where it came from before Conduit credited it — either because the sending institution reversed it, or because it was returned during review.

Common causes

  • Insufficient funds at the originating institution — the sender’s account did not have sufficient funds when the transfer was processed
  • Account closed or invalid — the originating account was closed or the transfer details were invalid
  • Sender-initiated reversal — the sender requested a recall or reversal of the transfer before it cleared

Recovery

This is a terminal state. No funds were credited to the customer. The customer should contact the sender or their own financial institution for details on the return.
1. Confirm the terminal state
The response shows status: "failed" and failureCode: "returned_by_sender". 2. Notify the customer The inbound transfer was not credited. The customer should be informed that the transfer was returned and that they should contact the sender for the return reason and next steps. 3. Do not resubmit on behalf of the sender The original transfer is gone: it went back to where it came from, and neither Conduit nor the customer can recall it. A new transfer from the sender is required.

Case 2: a funding transfer was sent back

A transfer arrived at a funding address — the address a deposit-funded order publishes — and was sent back to the address it came from. The deposit ends in status: "failed" with a neutral failureMessage and no failureCode:
Conduit reports every terminal at a funding address the same way, whichever direction it happened in and whatever caused it. The absence of a failureCode is not itself a signal, and no field distinguishes one cause from another. Do not write code that reads meaning into which fields are present.
On a failed deposit, funded, returned and available are all absent too — so the deposit alone does not tell you where the money went.

Common causes

  • The sending address was not registered — the transfer came from an address that is not a registered address on the customer, so it was not accepted
  • No order claimed the transfer — nothing was waiting for the funds, or the order it was meant to fund had already expired
  • The transfer could not be accepted — it was not eligible to be credited

How to reconcile

Do not branch on failureCode. Reconcile against the order and against the return transaction instead. 1. Read the order the transfer was meant to fund The order reports its own outcome. A transfer that is not accepted never funds anything, so the order cannot reach its total and expires at its deadline. 2. Find the return transaction Money sent back is its own transaction, type: "deposit_return", carrying returnOf — the id of the deposit it returns:
Match returnOf to your deposit’s id. Once the return is completed, destination.txHash is the on-chain hash of the refund, so you can verify it on chain and tie it to your own records. returnOf is present whenever Conduit can still resolve the deposit a return came from, so a return with no returnOf is not evidence about your deposit either way. If you find no return naming your deposit, match on the sending address and amount instead, and contact support if it stays unclear — do not read the absence as proof that nothing was sent back. 3. Tell the customer what to do next If the sending address was not registered, register it and have the customer send again. Contact support if the deposit keeps failing.

Prevention

  • Handle transaction.failed by where the deposit was headed — for a deposit into your customer’s own virtual account or wallet, branch on failureCode === 'returned_by_sender'. For a transfer into a funding address that branch never runs on either rail: key off type and status, then look for the paired deposit_return
  • Register sending addresses before the customer sends — see registered addresses
  • Do not retry automatically — neither case is recoverable by retrying the original transfer; a new transfer from the sender is required
transaction.failed fires when the return is recorded. On a deposit into your customer’s own account it carries the code:
On a funding-address transfer it does not, on either rail:
The return itself emits its own transaction.created and transaction.completed, and the completed event carries the same destination.txHash as the read.