> ## 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.

# Offramps

> Enable users to offramp crypto to fiat using payment routes with payment accounts for ACH and wire transfers.

## Overview

Offramps let your users convert stablecoin to fiat through a persistent payment route. The process involves two steps:

1. **Create a payment account:** register the user's bank account details as a payment account.
2. **Create an offramp payment route:** set up the route that converts crypto to fiat and sends it to the payment account.

When a user sends stablecoin to the route's deposit address, funds are automatically converted to fiat and transferred to their registered bank account.

## Before you begin

Make sure you have:

* **API access** to the payment accounts and payment routes endpoints.
* **User bank account details:** the destination bank account information (account number, routing number, beneficiary details).
* **A stablecoin source:** users need stablecoin on a supported chain to offramp.

## Restrictions

Offramp payment routes are subject to the same [restrictions &
availability](/docs/restrictions-and-availability) rules as any other payment
route, plus Rain's [Payments compliance](/docs/payments-compliance) checks.

## Key concepts

### Payment accounts

A payment account is a stored representation of a user's bank account or other fiat destination. Payment accounts let you:

* Pre-validate bank account details before creating transfers.
* Reuse the same destination across multiple payment routes or transfers.
* Track payments associated with specific accounts.

For offramps, you create an `externalFiatAccount` type payment account containing the user's bank details.

### Payment routes

An offramp payment route creates a persistent pipe from crypto to fiat:

* **Source:** stablecoin on a supported chain.
* **Destination:** a payment account, the user's bank account.

When you create an offramp payment route, Rain generates a `depositAddress` containing an onchain wallet address. Any stablecoin sent to this address is automatically converted to fiat and transferred to the payment account.

## API flow

<div className="wf-diagram">
  <div className="legend">
    <span className="lg"><span className="swatch action" />Action / API call</span>
    <span className="lg"><span className="swatch ext" />External / network</span>
    <span className="lg"><span className="swatch send" />Webhook Rain sends you</span>
  </div>

  <div className="diagram-shell borderless">
    <svg id="offramp-api-flow" role="img" aria-label="Offramp: the user provides bank details, the partner registers a payment account and creates a payment route, the user sends stablecoin to the deposit address, Rain converts it to fiat and transfers it to the user's bank, then sends a transactionTransfer webhook." viewBox="0 0 1080 1192" width="1080" height="1192" style={{width: "100%", height: "auto"}}><defs><marker id="arrow-offramp-api-flow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" className="marker-fill-default" /></marker><marker id="arrowSend-offramp-api-flow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" className="marker-fill-send" /></marker></defs><path d="M 540 164 L 540 204" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-offramp-api-flow)" opacity="0.92" /><path d="M 540 272 L 540 312" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-offramp-api-flow)" opacity="0.92" /><path d="M 540 380 L 540 420" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-offramp-api-flow)" opacity="0.92" /><path d="M 540 488 L 540 528" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-offramp-api-flow)" opacity="0.92" /><path d="M 540 596 L 540 636" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-offramp-api-flow)" opacity="0.92" /><path d="M 540 704 L 540 744" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-offramp-api-flow)" opacity="0.92" /><path d="M 540 812 L 540 852" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-offramp-api-flow)" opacity="0.92" /><path d="M 540 920 L 540 960" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-offramp-api-flow)" opacity="0.92" /><path d="M 540 1028 L 540 1068" fill="none" className="conn-send" stroke-width="1.7" marker-end="url(#arrowSend-offramp-api-flow)" opacity="0.92" /><foreignObject x="320" y="96" width="440" height="68"><div className="card action"><span className="ct"><span className="tag">User</span><span className="lab">Provides bank details</span></span></div></foreignObject><foreignObject x="320" y="204" width="440" height="68"><div className="card action"><span className="bn">1</span><span className="ct"><span className="tag">Partner</span><span className="lab mono">POST /payment-accounts</span></span></div></foreignObject><foreignObject x="320" y="312" width="440" height="68"><div className="card action"><span className="bn">2</span><span className="ct"><span className="tag rain">Rain</span><span className="lab">Returns payment account</span></span></div></foreignObject><foreignObject x="320" y="420" width="440" height="68"><div className="card action"><span className="bn">3</span><span className="ct"><span className="tag">Partner</span><span className="lab mono">POST /payment-routes</span></span></div></foreignObject><foreignObject x="320" y="528" width="440" height="68"><div className="card action"><span className="bn">4</span><span className="ct"><span className="tag rain">Rain</span><span className="lab">Returns route with depositAddress</span></span></div></foreignObject><foreignObject x="320" y="636" width="440" height="68"><div className="card action"><span className="bn">5</span><span className="ct"><span className="tag">Partner</span><span className="lab">Provides deposit address</span></span></div></foreignObject><foreignObject x="320" y="744" width="440" height="68"><div className="card ext"><span className="bn">6</span><span className="ct"><span className="tag">User</span><span className="lab">Sends stablecoin to deposit address</span></span></div></foreignObject><foreignObject x="320" y="852" width="440" height="68"><div className="card action"><span className="bn">7</span><span className="ct"><span className="tag rain">Rain</span><span className="lab">Converts to fiat</span></span></div></foreignObject><foreignObject x="320" y="960" width="440" height="68"><div className="card ext"><span className="bn">8</span><span className="ct"><span className="tag">Bank</span><span className="lab">Receives fiat transfer</span></span></div></foreignObject><foreignObject x="320" y="1068" width="440" height="68"><div className="card send"><span className="bn">9</span><span className="ct"><span className="tag">Webhook</span><span className="lab mono">transactionTransfer</span></span></div></foreignObject></svg>
  </div>
</div>

The steps above, in text:

| # | Actor   | Step                                                                                     |
| - | ------- | ---------------------------------------------------------------------------------------- |
| – | User    | Provides bank details to the partner                                                     |
| 1 | Partner | Calls `POST /payment-accounts`                                                           |
| 2 | Rain    | Returns the payment account                                                              |
| 3 | Partner | Calls `POST /payment-routes`                                                             |
| 4 | Rain    | Returns the route with a `depositAddress`                                                |
| 5 | Partner | Provides the deposit address to the user                                                 |
| 6 | User    | Sends stablecoin to the deposit address                                                  |
| 7 | Rain    | Converts the stablecoin to fiat                                                          |
| 8 | Bank    | Receives the fiat transfer                                                               |
| 9 | Rain    | Sends a [`transactionTransfer`](/docs/transaction#transactiontransfer-completed) webhook |

## Step 1: create a payment account

Before creating an offramp payment route, you must register the user's bank
account as a payment account. Call `POST /payment-accounts` with the
`externalFiatAccount` type. See [Register a bank
account](/docs/payment-accounts#register-a-bank-account) for the full
request, response, supported fields, and the first-party/third-party
distinction for the account owner.

## Step 2: create an offramp payment route

Once you have a payment account, create an offramp payment route by calling
`POST /payment-routes`.

See [Create an offramp payment route](/docs/payment-routes#create-an-offramp-payment-route)
for the full request, response, and field reference.

<Warning>
  **Refund address required**

  The `refundAddress` field is mandatory when creating an offramp payment route. Set this to a valid onchain address where stablecoin can be returned if a transaction cannot be completed. Funds may be returned due to:

  * Destination bank account issues (closed account, invalid details, account restrictions).
  * Transaction limits being exceeded.
  * Compliance or regulatory holds.
  * Failed fiat transfers rejected by the receiving bank.

  If you don't provide `refundAddress`, Rain rejects the payment route creation request. Make sure the refund address is a wallet you control and can receive the source stablecoin on the specified chain.
</Warning>

<Info>
  **Address format requirements**

  The refund address must match the expected format for the source rail:

  * **EVM chains** (Ethereum, Base, Polygon, Arbitrum, Optimism, Avalanche, Celo, ZKSync, Binance): must be a valid EVM address starting with `0x` followed by 40 hexadecimal characters (for example, `0x1234567890abcdef1234567890abcdef12345678`).
  * **Solana:** must be a valid Solana address in base58 format (32-44 characters).

  If the address doesn't match the source rail format, the request fails.
</Info>

<Warning>
  The response's `depositAddress` is unique to this payment route. Only send
  the specified source currency (for example, USDC on Base) to this address.
  Sending other tokens may result in loss of funds.
</Warning>

## Manage payment accounts

Use `GET /payment-accounts`, `GET /payment-accounts/{paymentAccountId}`, and
`DELETE /payment-accounts/{paymentAccountId}` to list, retrieve, and remove
payment accounts. See [Manage payment
accounts](/docs/payment-accounts#manage-payment-accounts) for the full
request and response examples.

<Warning>
  You can't delete a payment account that an active payment route references.
  Delete the payment route first, then delete the payment account.
</Warning>

## Manage payment routes

Use `GET /payment-routes`, `GET /payment-routes/{paymentRouteId}`, and
`DELETE /payment-routes/{paymentRouteId}` to list, retrieve, and remove
offramp payment routes. See [Manage payment
routes](/docs/payment-routes#manage-payment-routes) for the full request and
response examples.

## What happens when crypto is deposited

When a user sends stablecoin to the deposit address:

1. **Crypto received:** Rain detects the incoming stablecoin transfer.
2. **Transfer created:** Rain creates a transaction of type `transfer` and sends a `transactionTransfer` webhook with action `created`.
3. **Conversion:** Rain converts stablecoin to fiat.
4. **Fiat transfer:** Rain sends funds to the user's bank account via the specified rail.
5. **Transfer completed:** the transfer settles, and Rain sends a `transactionTransfer` webhook with action `completed`.

### Webhooks

Rain sends webhooks through the transfer lifecycle:

| Resource              | Action      | Description                                                  |
| --------------------- | ----------- | ------------------------------------------------------------ |
| `transactionTransfer` | `created`   | Sent when the transfer is initiated after crypto is received |
| `transactionTransfer` | `updated`   | Sent when the transfer's status changes during processing    |
| `transactionTransfer` | `completed` | Sent when the fiat transfer settles at the destination bank  |

See the [transfer object reference](/docs/transaction#transfer-object-reference) for the full webhook payload schema.

### Transfer transaction

Each successful offramp creates a `transfer` transaction that you can query via
the [Transactions API](/reference/transactions/get-all-transactions). Filter
by `type=transfer` to see all transfer transactions:

```bash theme={null}
curl -X GET "https://api.rain.xyz/v1/issuing/transactions?type=transfer" \
  -H "Api-Key: YOUR_API_KEY"
```

Example transfer transaction response:

```json theme={null}
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "type": "transfer",
  "transfer": {
    "source": {
      "amount": "100.00",
      "currency": "usdc",
      "rail": "base"
    },
    "destination": {
      "amount": "99.50",
      "currency": "usd",
      "rail": "ach",
      "address": {
        "type": "paymentAccount",
        "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
      }
    },
    "depositAddress": {
      "type": "onchain",
      "address": "0xabcdef1234567890abcdef1234567890abcdef12"
    },
    "exchangeRate": 1.0,
    "status": "settled",
    "createdAt": "2025-01-15T10:35:00Z",
    "updatedAt": "2025-01-15T10:40:00Z"
  }
}
```

### Settlement times

After crypto is received, fiat transfer times vary by rail:

| Rail | Typical settlement |
| ---- | ------------------ |
| ACH  | 1-3 business days  |
| Wire | Same business day  |

### Cutoff times

Fiat transfer processing is subject to banking cutoff times. Rain processes transfers initiated after the cutoff on the next business day.

| Rail           | Cutoff Time | Notes                                                                     |
| -------------- | ----------- | ------------------------------------------------------------------------- |
| ACH (Same-Day) | 4:00 PM ET  | Transfers submitted after this cutoff are processed the next business day |
| Wire (Fedwire) | 5:45 PM ET  | Transfers submitted after this cutoff are processed the next business day |

<Info>
  Cutoff times apply on US business days only. Transfers initiated on weekends
  or US federal holidays are processed on the next business day.
</Info>

## Supported configurations

### Source (crypto)

| Currency | Rails (Chains)                                                       |
| -------- | -------------------------------------------------------------------- |
| USDC     | Ethereum, Base, Polygon, Arbitrum, Optimism, Avalanche, Celo, Solana |
| RUSD     | Ethereum, Base, Polygon, Arbitrum, Optimism, Avalanche, Celo, Solana |

### Destination (fiat)

| Currency | Rails     |
| -------- | --------- |
| USD      | ACH, Wire |

<Info>
  Rain regularly adds additional currencies and rails. Contact your Rain
  representative for the latest supported configurations.
</Info>

## Error handling

### Payment account errors

| Error                    | Description                                 | Resolution                                        |
| ------------------------ | ------------------------------------------- | ------------------------------------------------- |
| `invalid_account_number` | The account number format is invalid        | Verify the account number with the user           |
| `invalid_routing_number` | The routing number is invalid               | Verify the routing number is correct for the bank |
| `missing_beneficiary`    | Required beneficiary information is missing | Include all required beneficiary fields           |

### Payment route errors

| Error                         | Description                                                  | Resolution                                              |
| ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------------- |
| `invalid_refund_address`      | The refund address format doesn't match the source rail      | Use an EVM address for EVM rails or Solana for Solana   |
| `invalid_wire_routing_number` | The routing number for the wire payment account is invalid   | Verify the routing number is correct for wire transfers |
| `payment_account_not_found`   | The specified payment account doesn't exist                  | Verify the payment account ID                           |
| `unsupported_currency_pair`   | The source/destination currency combination is not supported | Check supported configurations above                    |
| `unsupported_rail`            | The specified rail is not available                          | Use a supported rail for the currency                   |

## Best practices

1. **Validate bank details early:** create payment accounts during user onboarding to catch errors before the user attempts to offramp.
2. **Use nicknames:** assign meaningful nicknames to payment accounts for easy identification.
3. **Monitor webhooks:** set up webhook handlers to track transfer status in real time.
4. **Handle failures gracefully:** fiat transfers can fail due to bank issues. Implement retry logic and user notifications.

## What's next

<Columns cols={2}>
  <Card title="Payment accounts" icon="building-columns" href="/docs/payment-accounts">
    See the full request, response, and field reference for registering a bank account.
  </Card>

  <Card title="Payment routes" icon="route" href="/docs/payment-routes">
    See the full request, response, and field reference for creating a payment route.
  </Card>

  <Card title="Set up onramps" icon="arrow-down-to-line" href="/docs/onramps">
    Enable fiat deposits into crypto.
  </Card>

  <Card title="Set up webhooks" icon="bell" href="/docs/webhooks">
    Receive transfer notifications as they happen.
  </Card>
</Columns>
