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

# Payment Routes

> Set up a reusable onramp or offramp pathway and get the virtual account or deposit address a sender uses to fund it.

A payment route is a persistent pathway between a fiat source and a crypto
destination (onramp), or a crypto source and a fiat destination (offramp).
Creating a payment route doesn't move any money. Rain returns the details a
sender uses to fund the route, and money moves only when the sender sends
funds to it.

## What a payment route is

A payment route runs in one direction:

* **Onramp:** The source is fiat (ACH or wire) and the destination is an
  onchain address. Rain returns a virtual account, converts any fiat sent to
  it to stablecoin (`usdc` or `rusd`), and delivers it to the destination
  address.
* **Offramp:** The source is crypto (a stablecoin and chain) and the
  destination is a [payment account](/docs/payment-accounts). Rain returns a
  deposit address, converts any stablecoin sent to it to fiat, and delivers
  it to the destination account.

<div className="wf-diagram">
  <div className="legend">
    <span className="lg"><span className="swatch ext" />Partner / response</span>
    <span className="lg"><span className="swatch action" />Rain step</span>
    <span className="lg"><span className="swatch cond" />Direction</span>
  </div>

  <div className="diagram-shell borderless">
    <svg id="payment-route-create" role="img" aria-label="Creating a payment route: a POST request returns either a virtual account for onramps or an onchain deposit address for offramps, depending on the route's direction." viewBox="0 0 888 320" width="888" height="320" style={{width: "100%", height: "auto"}}><defs><marker id="arrow" 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></defs><path d="M 196 130 L 236 130" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><path d="M 412 130 L 476 130" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><text x="444" y="118" text-anchor="middle" className="phase-label">onramp</text><path d="M 652 130 L 692 130" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><path d="M 324 164 L 324 238" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><text x="338" y="220" text-anchor="start" className="phase-label">offramp</text><path d="M 412 270 L 476 270" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><foreignObject x="20" y="96" width="176" height="68"><div className="card ext"><span className="ct"><span className="tag">Partner</span><span className="lab mono">POST /payment-routes</span></span></div></foreignObject><foreignObject x="236" y="96" width="176" height="68"><div className="card cond"><span className="ct"><span className="tag">Direction</span><span className="lab">Onramp or offramp?</span></span></div></foreignObject><foreignObject x="476" y="96" width="176" height="68"><div className="card action"><span className="ct"><span className="tag rain">Rain · onramp</span><span className="lab">Converts to stablecoin</span></span></div></foreignObject><foreignObject x="692" y="96" width="176" height="68"><div className="card ext"><span className="ct"><span className="tag">Response</span><span className="lab">Virtual account (ACH/wire)</span></span></div></foreignObject><foreignObject x="236" y="238" width="176" height="64"><div className="card action"><span className="ct"><span className="tag rain">Rain · offramp</span><span className="lab">Converts to fiat</span></span></div></foreignObject><foreignObject x="476" y="238" width="176" height="64"><div className="card ext"><span className="ct"><span className="tag">Response</span><span className="lab">Onchain deposit address</span></span></div></foreignObject></svg>
  </div>
</div>

* **POST /payment-routes:** the partner calls the endpoint with a `source`
  and `destination`.
* **Onramp or offramp?:** determined by whether the source is fiat or
  crypto.
* **Onramp:** Rain converts incoming fiat to stablecoin and returns a
  virtual account (ACH/wire details).
* **Offramp:** Rain converts incoming stablecoin to fiat and returns an
  onchain deposit address.

The sender or receiver doesn't have to be the customer. Anyone can fund a
route on the customer's behalf.

## API flow

Creating a route is a single call. Everything after that happens when the
sender funds it:

<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 / sender</span>
    <span className="lg"><span className="swatch send" />Webhook Rain sends you</span>
  </div>

  <div className="diagram-shell borderless">
    <svg id="payment-route-flow" role="img" aria-label="Creating a payment route: the partner calls the API, shares the returned account or deposit address with the sender, the sender funds the route, and Rain converts, settles, and sends a transactionTransfer webhook." viewBox="0 0 660 360" width="660" height="360" style={{width: "100%", height: "auto"}}><defs><marker id="arrow-payment-route-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-payment-route-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 202 136 L 242 136" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-payment-route-flow)" opacity="0.92" /><path d="M 418 136 L 458 136" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-payment-route-flow)" opacity="0.92" /><path d="M 546 180 L 546 246" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-payment-route-flow)" opacity="0.92" /><path d="M 458 290 L 418 290" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow-payment-route-flow)" opacity="0.92" /><path d="M 242 290 L 202 290" fill="none" className="conn-send" stroke-width="1.7" marker-end="url(#arrowSend-payment-route-flow)" opacity="0.92" /><foreignObject x="26" y="92" width="176" height="88"><div className="card action"><span className="bn">1</span><span className="ct"><span className="tag">Partner</span><span className="lab mono">POST /payment-routes</span></span></div></foreignObject><foreignObject x="242" y="92" width="176" height="88"><div className="card action"><span className="bn">2</span><span className="ct"><span className="tag rain">Rain</span><span className="lab">Returns the route</span></span></div></foreignObject><foreignObject x="458" y="92" width="176" height="88"><div className="card action"><span className="bn">3</span><span className="ct"><span className="tag">Partner</span><span className="lab">Shares with sender</span></span></div></foreignObject><foreignObject x="458" y="246" width="176" height="88"><div className="card ext"><span className="bn">4</span><span className="ct"><span className="tag">Sender</span><span className="lab">Funds the route</span></span></div></foreignObject><foreignObject x="242" y="246" width="176" height="88"><div className="card action"><span className="bn">5</span><span className="ct"><span className="tag rain">Rain</span><span className="lab">Converts and settles</span></span></div></foreignObject><foreignObject x="26" y="246" width="176" height="88"><div className="card send"><span className="bn">6</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                                                                                     |
| - | ------- | ---------------------------------------------------------------------------------------- |
| 1 | Partner | Calls `POST /payment-routes`                                                             |
| 2 | Rain    | Returns the route with a `depositAddress`                                                |
| 3 | Partner | Shares the virtual account or deposit address with the sender                            |
| 4 | Sender  | Sends fiat (onramp) or stablecoin (offramp) to fund the route                            |
| 5 | Rain    | Converts and settles the funds                                                           |
| 6 | Rain    | Sends a [`transactionTransfer`](/docs/transaction#transactiontransfer-completed) webhook |

## Before you begin

Make sure you have:

* **API access** to the payment routes endpoints.
* **A destination address** for onramps: an onchain wallet or a Rain smart
  contract that receives stablecoin.
* **A registered [payment account](/docs/payment-accounts)** for offramps,
  as the destination bank account.

Rain also subjects payment routes to regional and industry
[restrictions](/docs/restrictions-and-availability). Check those before you
create one.

## Create an onramp payment route

Call `POST /payment-routes` with a fiat `source` and an onchain `destination`.

```bash theme={null}
curl -X POST https://api.rain.xyz/v1/payment-routes \
  -H "Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "11111111-1111-1111-1111-111111111111",
    "source": {
      "currency": "usd",
      "rail": "ach"
    },
    "destination": {
      "currency": "usdc",
      "rail": "base",
      "address": {
        "type": "onchain",
        "address": "0x1234567890abcdef1234567890abcdef12345678"
      }
    }
  }'
```

`source.rail` can be `ach` or `wire`. The generated virtual account supports
both rails regardless of which one you specify. Setting the primary rail
only helps with routing optimization.

The response includes a `depositAddress` with the virtual account's beneficiary
and banking details. The virtual account is a **named** account: `beneficiaryName`
carries your customer's own name, so incoming transfers are addressed to them,
not to Rain. Share these details with the sender so they can wire or ACH funds
to the route.

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "userId": "11111111-1111-1111-1111-111111111111",
  "status": "active",
  "source": {
    "currency": "usd",
    "rail": "ach"
  },
  "destination": {
    "currency": "usdc",
    "rail": "base",
    "address": {
      "type": "onchain",
      "address": "0x1234567890abcdef1234567890abcdef12345678"
    }
  },
  "depositAddress": {
    "type": "fiat",
    "beneficiaryName": "JOHN DOE",
    "beneficiaryAddress": "123 Main St, Austin, TX 78701, US",
    "beneficiaryBankName": "Partner Bank, N.A.",
    "beneficiaryBankAddress": "456 Bank Ave, New York, NY 10002, US",
    "accountNumber": "9876543210",
    "routingNumber": "021000021"
  },
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-15T10:00:00Z"
}
```

## Create an offramp payment route

Call `POST /payment-routes` with a crypto `source` and a fiat `destination`
that references a [payment account](/docs/payment-accounts) `id`.

```bash theme={null}
curl -X POST https://api.rain.xyz/v1/payment-routes \
  -H "Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "11111111-1111-1111-1111-111111111111",
    "source": {
      "currency": "usdc",
      "rail": "base"
    },
    "destination": {
      "currency": "usd",
      "rail": "ach",
      "address": {
        "type": "paymentAccount",
        "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
      }
    },
    "refundAddress": "0x9876543210fedcba9876543210fedcba98765432"
  }'
```

<Info>
  `refundAddress` is required whenever `source` is a crypto rail. If the
  transaction can't be completed, Rain returns the crypto to this address.
</Info>

The response includes an onchain `depositAddress`. Share this with the sender
so they can send stablecoin to the route.

```json theme={null}
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "userId": "11111111-1111-1111-1111-111111111111",
  "status": "active",
  "source": {
    "currency": "usdc",
    "rail": "base"
  },
  "destination": {
    "currency": "usd",
    "rail": "ach",
    "address": {
      "type": "paymentAccount",
      "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
    }
  },
  "refundAddress": "0x9876543210fedcba9876543210fedcba98765432",
  "depositAddress": {
    "type": "onchain",
    "address": "0xabcdef1234567890abcdef1234567890abcdef12"
  },
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-15T10:00:00Z"
}
```

<Warning>
  Only send the exact source currency to a `depositAddress`. Sending other
  tokens or currencies may result in failed conversions or loss of funds.
</Warning>

### Response fields

Both the onramp and offramp responses above share the same shape:

| Field                                      | Description                                                                                                                                                                                                                                                  |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                                       | Unique identifier for the payment route.                                                                                                                                                                                                                     |
| `userId`                                   | ID of the individual user this route belongs to. Omitted for company teams, which use `companyId` instead.                                                                                                                                                   |
| `status`                                   | Current state of the route: `active`, `pending`, `frozen`, or `deleted`. A `pending` route is awaiting the customer's verification and has no `depositAddress` yet; the [`paymentRoute.created`](/docs/paymentRoute) webhook fires when it becomes `active`. |
| `source.currency`, `source.rail`           | The currency and rail funds arrive on.                                                                                                                                                                                                                       |
| `destination.currency`, `destination.rail` | The currency and rail funds are delivered on.                                                                                                                                                                                                                |
| `destination.address`                      | For offramps, the referenced payment account. For onramps, the onchain address funds are delivered to.                                                                                                                                                       |
| `depositAddress`                           | The banking credentials a sender wires or ACHs to (onramp) or the onchain address a sender sends stablecoin to (offramp).                                                                                                                                    |
| `refundAddress`                            | Present only when `source` is a crypto rail (offramps). The onchain address Rain returns funds to if the transaction can't complete.                                                                                                                         |
| `createdAt`, `updatedAt`                   | Timestamps for when the route was created and last updated.                                                                                                                                                                                                  |

## Optional fields

Two more fields are accepted when you create (or later update) a route:

* **`transferMessage`**: a memo of up to 23 ASCII letters, digits, and spaces.
  It surfaces as the wire memo on USD offramps and as the SPEI *concepto* on
  MXN offramps.
* **`senderFees`**: an array of fees you charge the sender on every transfer
  the route processes, each `{ "type": "flat" | "variable", "amount": "..." }`.
  A `flat` amount is in the source currency; a `variable` amount is a
  percentage below 100. Sender fees must be enabled for your program.

## Supported rails

The following table lists the supported rails for each direction:

| Direction | Fiat rail     | Crypto rail                                                                          | Stablecoin currency |
| --------- | ------------- | ------------------------------------------------------------------------------------ | ------------------- |
| Onramp    | `ach`, `wire` | `ethereum`, `polygon`, `optimism`, `arbitrum`, `avalanche`, `base`, `celo`, `solana` | `usdc`, `rusd`      |
| Offramp   | `ach`, `wire` | `ethereum`, `polygon`, `optimism`, `arbitrum`, `avalanche`, `base`, `celo`, `solana` | `usdc`, `rusd`      |

MXN routes pair the `mx_spei` rail and `mxn` currency with `usdc` in either
direction. See [MXN onramps](/docs/mxn-onramps) and
[MXN offramps](/docs/mxn-offramps) for the differences.

## Manage payment routes

To retrieve all payment routes for your team, call `GET /payment-routes`. The
response carries them in a `paymentRoutes` array. Filter with `userId` or
`companyId`, and page with `limit` (default 20, max 100) and `cursor` (the last
route's `id` from the previous page).

```bash theme={null}
curl -X GET https://api.rain.xyz/v1/payment-routes \
  -H "Api-Key: YOUR_API_KEY"
```

To retrieve a single payment route, call
`GET /payment-routes/{paymentRouteId}`.

```bash theme={null}
curl -X GET https://api.rain.xyz/v1/payment-routes/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "Api-Key: YOUR_API_KEY"
```

To update a payment route, call `PATCH /payment-routes/{paymentRouteId}`. Only
`transferMessage`, `refundAddress` (offramp routes only), and `senderFees` can
change; the route's source, destination, and deposit address are immutable.
MXN routes can't be updated: delete the route and create a new one instead.

```bash theme={null}
curl -X PATCH https://api.rain.xyz/v1/payment-routes/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "transferMessage": "INVOICE 1042" }'
```

To remove a payment route, call
`DELETE /payment-routes/{paymentRouteId}`. A successful delete returns `204`
with no body, and the route no longer appears in list or get responses.

```bash theme={null}
curl -X DELETE https://api.rain.xyz/v1/payment-routes/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "Api-Key: YOUR_API_KEY"
```

## What's next

<Card title="Payment Accounts" href="/docs/payment-accounts">
  Register the external bank account an offramp payment route pays out to.
</Card>

<Card title="Onramps" href="/docs/onramps">
  Learn more about converting fiat to crypto through a payment route.
</Card>

<Card title="Offramps" href="/docs/offramps">
  Learn more about converting crypto to fiat through a payment route.
</Card>

<Card title="Restrictions" href="/docs/restrictions-and-availability">
  Review the regional and industry restrictions that apply to payment routes.
</Card>
