> ## Documentation Index
> Fetch the complete documentation index at: https://rain-sandbox-trial.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Handling Refunds

> How refunds flow through the card network, how funds are credited back, and how on-chain refunds return value to a user's wallet or contract.

When a cardholder requests a refund from a merchant, the refund flows through the card network before reaching Rain. How funds are credited back depends on your program type.

## How refunds work

A refund occurs when a merchant agrees to return funds to a cardholder after a completed transaction. Unlike reversals, which cancel pending authorizations, refunds apply to transactions that have already settled.

The refund process follows these steps:

1. The cardholder requests a refund from the merchant.
2. The merchant settles the refund with Visa.
3. Visa subtracts the refund amount from the merchant's Net Settlement Balance.
4. Rain receives the refund notification and issues a Credit Voucher.
5. The Credit Voucher is applied to the appropriate ledger balance.

### Refund timing

Refunds generally complete within **30 business days** of the merchant processing them, and refunds for canceled orders can take up to 30 business days after the pending charge clears. A merchant refund that stays pending for more than 10 days may have failed; if a refund exceeds 30 business days, escalate to Rain support with the transaction ID and the card's last 4 digits.

Rain never credits a refund the merchant declined. The user must ask the merchant to retry the refund.

## Credit Voucher distribution

When we receive a refund from the card network, we issue a Credit Voucher to restore the funds. Where the credit is applied depends on your program type.

### Rain-managed programs

For Rain-managed programs, we handle the ledger on behalf of your users. When a refund is processed, we issue the Credit Voucher directly to the **user's ledger balance**. The user's available balance increases by the refund amount, and you receive a `transaction.completed` webhook with a negative amount indicating the credit.

For example, if a user receives a \$50 refund, their ledger balance increases by \$50 and you receive a webhook showing `-5000` (in cents).

### Partner-managed programs

For Partner-managed programs, you manage your own ledger and authorization decisions. When a refund is processed, we issue the Credit Voucher to your **tenant's ledger balance** rather than to individual user balances. You are responsible for crediting the appropriate user on your own ledger after receiving the `transaction.completed` webhook.

For example, if one of your users receives a \$50 refund, your tenant balance increases by \$50. You then post the refund to your internal ledger and credit the user accordingly.

<Warning>
  Do not credit refunds to users until you receive the `transaction.completed` webhook. Refunds may take several days to process through the card network.
</Warning>

## Identifying refunds

Refunds appear as transactions with **negative amounts**. You can identify a refund by checking for:

* A negative `amount` value in the webhook payload.
* The `spend` transaction type.

Refunds may not always reference the original transaction ID, as merchants can process refunds independently. Use the merchant name and amount to match refunds to their original transactions when needed.

## On-chain refunds

With **onchain refunds** enabled, in most cases your users receive refunds as on-chain stablecoin transfers instead of **spending credit** — the default, where an instant ledger credit grows a user's spending power. Onchain refunds return stablecoins from a Rain-operated refund wallet to the user on-chain, so the refunded amount is withdrawable like their original funds.

### How on-chain refunds work

You don't need to take any action once onchain refunds are enabled for your tenant — qualifying refunds settle on-chain automatically. Three events trigger an onchain refund:

* **Processor refunds** — a merchant-initiated refund that settles after the original transaction.
* **Real Time Funding reversals** — an authorization reversal on a tenant using [Real Time Funding](/docs/real-time-funding), where the excess collateral must return to the user's source wallet.
* **Accepted dispute reimbursements** — the reimbursement for an accepted dispute, returned to the user on-chain instead of the account credit Rain would otherwise issue.

Once the transfer settles on-chain, you can track it through the transaction record and a webhook. Rain funds the transfer from a dedicated refund wallet.

### Refund amount limits

An onchain refund can never exceed the amount of the original transaction it refunds. Rain caps each refund at the transaction's **remaining refundable amount** — the original purchase amount minus any refunds already issued or still processing against that transaction.

When a refund request would exceed the remaining refundable amount, Rain reduces it to that amount and settles the reduced amount on-chain. The refund `amount` shown on the transaction record and in the `onchainRefund.created` and `onchainRefund.completed` webhooks reflects this reduced amount, so it may be smaller than the amount originally requested. For example, on a $100 purchase that has already been refunded $70, a later $50 request settles as a $30 refund — the amount still remaining.

When a transaction has already been fully refunded, it has no remaining refundable amount, and Rain does not issue an onchain refund for it. Because no refund is created, you receive no `onchainRefund.created` or `onchainRefund.completed` webhook for that request.

A reduced `amount` or a missing webhook is expected when a transaction is partially or fully refunded, not an error — see [Webhook notifications](#webhook-notifications) or [Identifying onchain refunds](#identifying-onchain-refunds) to confirm what settled.

### Refund destinations

Where the funds land depends on how your tenant sources collateral:

| Tenant model                                 | Refund destination                                 |
| -------------------------------------------- | -------------------------------------------------- |
| Standard (collateral)                        | The user's collateral contract on the refund chain |
| [Real Time Funding](/docs/real-time-funding) | The wallet the funds were originally pulled from   |

### Enabling onchain refunds

You don't toggle onchain refunds yourself — Rain enables them per tenant. If you use Real Time Funding, you get onchain refunds by default, since those users expect funds back in their own wallet.

<Info>Contact your Rain representative to enable onchain refunds for your tenant.</Info>

### Supported chains and assets

Onchain refunds are paid in **USDC** on every chain except Plasma, where they are paid in **USDT0** (Plasma has no USDC deployment).

### Collateral refunds

Refunds to a collateral contract can settle on any of the chains below. The chain used for a given refund depends on the refund routing available to your tenant at the time.

| Chain     | Sandbox                                    | Production                             |
| --------- | ------------------------------------------ | -------------------------------------- |
| Ethereum  | Ethereum Sepolia (`11155111` / `0xaa36a7`) | Ethereum Mainnet (`1` / `0x1`)         |
| Arbitrum  | Arbitrum Sepolia (`421614` / `0x66eee`)    | Arbitrum Mainnet (`42161` / `0xa4b1`)  |
| Base      | Base Sepolia (`84532` / `0x14a34`)         | Base Mainnet (`8453` / `0x2105`)       |
| Optimism  | Optimism Sepolia (`11155420` / `0xaa37dc`) | Optimism Mainnet (`10` / `0xa`)        |
| Polygon   | Polygon Amoy (`80002` / `0x13882`)         | Polygon Mainnet (`137` / `0x89`)       |
| Avalanche | Avalanche Fuji (`43113` / `0xa869`)        | Avalanche Mainnet (`43114` / `0xa86a`) |
| Plasma    | Plasma Testnet (`9746` / `0x2612`)         | Plasma Mainnet (`9745` / `0x2611`)     |

### Real Time Funding refunds

Real Time Funding refunds return funds to the wallet they were pulled from, so they settle on the chains [Real Time Funding](/docs/real-time-funding) supports and require the user to have a wallet address on that chain.

| Chain    | Sandbox                                 | Production                            |
| -------- | --------------------------------------- | ------------------------------------- |
| Arbitrum | Arbitrum Sepolia (`421614` / `0x66eee`) | Arbitrum Mainnet (`42161` / `0xa4b1`) |
| Base     | Base Sepolia (`84532` / `0x14a34`)      | Base Mainnet (`8453` / `0x2105`)      |
| Plasma   | Plasma Testnet (`9746` / `0x2612`)      | Plasma Mainnet (`9745` / `0x2611`)    |

For USDC and USDT0 token addresses, see [Real Time Funding → Supported Assets](/docs/real-time-funding#supported-assets).

### Identifying onchain refunds

When you [fetch transactions](/reference/transactions/get-all-transactions), the response includes two fields that tell you how a refund was processed:

| Field           | Description                                                                                             |
| --------------- | ------------------------------------------------------------------------------------------------------- |
| `refundMethod`  | `onchain_refund` for an on-chain transfer, or `spending_credit` for a ledger credit                     |
| `referenceInfo` | Present once the on-chain transfer settles: `reference` is the transaction hash, `rail` is the chain ID |

```json theme={null}
{
  "id": "9b1c3e44-2f0a-4c7e-8a1d-5e6f7a8b9c0d",
  "refundMethod": "onchain_refund",
  "referenceInfo": {
    "reference": "0x4f8a1c2b3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8",
    "rail": "0x2105"
  }
}
```

<Info>`referenceInfo` appears only after the on-chain transfer settles. Until then, the transaction shows `refundMethod: onchain_refund` without a reference.</Info>

### Webhook notifications

To track a refund through its lifecycle, listen for the dedicated `onchainRefund` webhooks. You receive these events if you have onchain refunds or [Real Time Funding](/docs/real-time-funding) enabled.

| Webhook                                                                     | When it's sent                                                                      |
| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| [`onchainRefund.created`](/changelog/webhooks/v1/onchainRefund/created)     | The refund is created and processing begins. The refund starts in `PENDING` status. |
| [`onchainRefund.completed`](/changelog/webhooks/v1/onchainRefund/completed) | The on-chain transfer settles and the funds reach their destination.                |

Each event includes the refund `amount`, `asset`, `chainId`, and `destinationKind`, along with the `transactionId` of the refund transaction. Use `destinationKind` to tell where the funds land: `AUTHPULL_SOURCE` returns funds to the cardholder's source wallet, and `COLLATERAL_CONTRACT` returns them to the collateral contract.

You can also confirm a refund from the transaction record itself — see [Identifying onchain refunds](#identifying-onchain-refunds).

## What's next

<CardGroup cols={3}>
  <Card title="Refund transaction" icon="webhook" href="/docs/sample-webhooks#refund">
    Sample webhook payload for a refund transaction.
  </Card>

  <Card title="Settlement (Rain-managed)" icon="scale-balanced" href="/docs/settlement-rain-managed#refunds">
    How refunds are settled in Rain-managed programs.
  </Card>

  <Card title="Settlement (Partner-managed)" icon="scale-balanced" href="/docs/settlement-partner-managed#refunds">
    How refunds are settled in Partner-managed programs.
  </Card>
</CardGroup>
