> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useroutr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Refunds

> How payments that cannot fund an intent go back to your users, and when you need to step in.

Every payment lands in the intent's own deposit account, so a payment that does not fund the
intent stays attributed to it and can always be sent back. Refunds are paid from that deposit
account by a Useroutr worker.

## Refunds that happen on their own

You do not need to do anything for these. Each fires `refund.created`, then `refund.completed`
or `refund.failed`.

| Reason | When |
| - | - |
| `OVERPAYMENT` | Your user sent more than the intent asked for. The excess goes back. |
| `WRONG_ASSET` | Your user paid in an asset the intent does not accept, for example XLM to a USDC intent |
| `EXPIRED_INTENT` | The payment's ledger closed after `expires_at` |
| `DUPLICATE_PAYMENT` | The intent was already fully funded when the payment arrived |
| `UNDERPAYMENT` | The intent expired partly funded. Every partial payment goes back. |
| `SETTLEMENT_FAILED` | The intent failed and was not recovered within 24 hours. What remains of each payment goes back. |
| `ROUTE_REMAINDER` | An exact-output quote used less of your user's asset than the maximum they sent |
| `ROUTE_SURPLUS` | An exact-input quote delivered more than your amount |

Each payment is refunded at most once, and never for more than it brought in or than its deposit
account still holds. A payment Useroutr cannot refund safely on its own, such as one whose funds
have already moved or an amount too small to be worth sending, is left for you to refund by
request.

## Where a refund goes, and when it waits for you

A refund goes back to the account the payment came from, but only when that is safe. If it is
not, the refund waits in `PENDING` with no `destination.address`, its `failure.code` says why, and
`refund.destination_required` fires when a refund that was about to pay out is stopped.

| `failure.code` | Why it waits |
| - | - |
| `NO_DESTINATION` | The payment arrived through a bridge, so there is no Stellar account to return it to |
| `DESTINATION_UNVERIFIED` | The payment carried a memo, so it most likely came from an exchange's shared account |
| `DESTINATION_REQUIRES_MEMO` | The account is a shared account that credits customers by memo |
| `DESTINATION_NOT_FOUND` | The account no longer exists on Stellar |
| `DESTINATION_NO_TRUSTLINE` | The account can no longer hold the refunded asset |

Sending an exchange's shared account a refund without the customer's memo would credit nobody, so
Useroutr never does. Ask your user where they want the refund, then give it a destination, with
the memo their exchange showed them if there is one:

```ts theme={null}
await useroutr.refunds.update("ref_6c2e9d41", {
  destination_address: "GBVYOXQQZO2JYMG3UODZI5BSAXP3LKNNWJ7C5JCWUEGRZKXFG4NJITTL",
  destination_memo: { type: "id", value: "3810274423" },
});
```

A memo is `text` (at most 28 bytes), `id` (an unsigned 64-bit integer in decimal) or `hash` (32
bytes in hex). The destination is checked when you set it: an account that does not exist, cannot
hold the asset, or requires a memo you did not give is refused with `INVALID_DESTINATION`.

## Payments made on Base, Arbitrum or Ethereum

A payment your user made to a deposit address on an EVM network is refunded on that network, in
the asset they sent, with the refund's `destination.network` set to that network. Useroutr
refunds on its own:

* what is left at the address after the payment went through, as `OVERPAYMENT` or
  `ROUTE_REMAINDER`;
* a payment that could not be converted or delivered, once its deposit address allows it to be
  taken back (seven days after the address was handed out), as `SETTLEMENT_FAILED`, `EXPIRED_INTENT`,
  `UNDERPAYMENT` or `DUPLICATE_PAYMENT`. The payment is recorded as rejected, so the refund has a
  payment to belong to.

The refund goes to the address that sent the tokens. A payment in the network's native currency,
or a deposit that more than one address paid, names no single sender, so the refund waits with
`NO_DESTINATION` for you to give it an address on that network (no memo):

```ts theme={null}
await useroutr.refunds.update("ref_91a0c7e3", {
  destination_address: "0x4b20993Bc481177ec7E8f571ceCaE8A9e22C02db",
});
```

The refunded amount is what the deposit address actually held when it was taken back, which is
what the refund reports once it completes.

## Refund a payment yourself

Refund a rejected payment, or the confirmed payments of an intent that will not complete, by
naming the payment:

```ts theme={null}
const refund = await useroutr.refunds.create(
  "fi_2d6a91c4",
  "pay_4f7b0d12",
  { reason: "WRONG_ASSET" },
  { idempotencyKey: "refund-pay_4f7b0d12" },
);
```

The refund returns whatever of the payment has not been refunded already. Pass
`destination_address`, and `destination_memo` if it needs one, to send it somewhere other than
where it came from. One refund can be in progress per payment and asset at a time.

## Lifecycle

`PENDING` → `PROCESSING` → `COMPLETED` or `FAILED`. A completed refund carries the payout's
`transaction_hash`; a failed one carries its `failure`.

```ts theme={null}
const refund = await useroutr.refunds.retrieve("ref_6c2e9d41");
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.