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

# Money Movement Webhooks

> The webhooks that report money movement: which events Rain sends, when each one fires, and how to track a transfer from creation to settlement without polling.

Rain sends a webhook each time money movement changes state, so you never poll
the API to find out whether a transfer arrived, is being reviewed, or settled.
This page lists the events that matter for money movement and shows how a
transfer moves through them.

## Events by product

| Product | Events | Use them to |
| :- | :- | :- |
| [Payment routes](#payment-routes) | [`paymentRoute.created`](/docs/paymentRoute#paymentroute-created), [`microDeposit.received`](/docs/paymentRoute#microdeposit-received) | Share deposit details once a route is active, and show account-verification deposits. |
| [Transfers](#transfers) | [`transactionTransfer.created`](/docs/transaction#transactiontransfer-created), [`transactionTransfer.updated`](/docs/transaction#transactiontransfer-updated), [`transactionTransfer.completed`](/docs/transaction#transactiontransfer-completed) | Track every transfer from creation to settlement. |

## Payment routes

A [payment route](/docs/payment-routes) sends two webhooks, both about the
route's deposit details.

| Event | When Rain sends it | What to do |
| :- | :- | :- |
| [`paymentRoute.created`](/docs/paymentRoute#paymentroute-created) | A payment route becomes active and can receive deposits. | Share the virtual account or deposit address with the sender. |
| [`microDeposit.received`](/docs/paymentRoute#microdeposit-received) | A deposit under \$2.00 arrives on a route with a bank account. Rain records it and creates no transfer. | Show the amounts to your customer so they can verify account ownership. |

For a Partner-Managed customer who hasn't completed KYC, Rain creates the
route as `pending` with no deposit address. Wait for `paymentRoute.created`
before you share deposit details with that customer. For a KYC-approved
Rain-Managed customer, the create response already returns the active route.

Once a sender funds the route, the deposit becomes a transfer, and the
[transfer webhooks](#transfers) take over.

## Transfers

Every [payment route](/docs/payment-routes) deposit and every
[quoted transfer](/docs/transfers) produces one `transfer` transaction, and
the three `transactionTransfer` events report its whole life.

<Info>
  `transactionTransfer` amounts are decimal strings in the currency's major
  unit, such as `"1000.00"`. Card spend amounts are integers in cents. Don't
  share one amount parser between the two.
</Info>

### Transfer lifecycle

A transfer emits one `created` event, any number of `updated` events, and at
most one `completed` event. An `updated` event can still follow `completed`: a
bank return after settlement arrives as `updated` with status `refunded`. The
`transfer.status` field tells you which stage you're in.

```mermaid theme={null}
%%{
  init: {
    'theme': 'base',
    'themeVariables': {
      'textColor': '#A6CFFF',
      'primaryColor': '#212933',
      'primaryTextColor': '#FFFFFF',
      'primaryBorderColor': '#A6CFFF',
      'secondaryColor': '#F73196',
      'noteBkgColor': '#F4F3FF',
      'noteBorderColor': '#F4F3FF',
      'noteTextColor': '#6938EF'
    },
    'sequence': {
      'actorFontWeight': 'bold'
    }
  }
}%%

sequenceDiagram
    participant Sender
    participant Rain
    participant You as Your backend
    Sender->>Rain: Sends funds to the route or deposit address
    Rain->>You: transactionTransfer.created (pending)
    You-->>Rain: 2xx
    Rain->>Rain: Validates, converts, and sends funds
    Rain->>You: transactionTransfer.updated (processing)
    You-->>Rain: 2xx
    Rain->>Sender: Delivers funds to the destination
    Rain->>You: transactionTransfer.completed (settled)
    You-->>Rain: 2xx
```

The diagram shows a payment route flow. For a quoted transfer, `created` fires
when you call `POST /transfers`, before the sender's funds arrive.

#### Status and event map

Each status arrives with a specific event, so you can branch on the event
first and the status second.

| Status | Event | Meaning | What to do |
| :- | :- | :- | :- |
| `pending` | `created` | Rain created the transfer. | Record it. |
| `awaiting_transfer` | `created` | Rain is waiting for funds at the deposit address. | Record it and show the deposit instructions. |
| `processing` | `updated` | Funds arrived, and Rain is converting and sending them. | Show the transfer as in progress. |
| `pending_review` | `updated` | Rain is holding the transfer for review. | Tell your user the transfer is delayed. A later `updated` event reports the outcome. |
| `settled` | `completed` | The destination received the funds. | Mark the transfer successful. |
| `failed` | `updated` | The transfer failed. | Show a failure and let your user retry. |
| `cancelled` | `updated` | The transfer was cancelled before completion. | Show it as cancelled. |
| `expired` | `updated` | No deposit arrived before `expiresAt`. | Prompt your user to create a new transfer. |
| `refunded` | `updated` | Rain returned the funds to the sender. | Read `transfer.refundReason` and tell your user why. See [Refund reasons](/docs/refund-reasons). |

```mermaid theme={null}
%%{
  init: {
    'theme': 'base',
    'themeVariables': {
      'textColor': '#A6CFFF',
      'primaryColor': '#212933',
      'primaryTextColor': '#FFFFFF',
      'primaryBorderColor': '#A6CFFF',
      'secondaryColor': '#F73196'
    }
  }
}%%

stateDiagram-v2
    direction LR
    [*] --> pending: created
    [*] --> awaiting_transfer: created
    pending --> processing: updated
    awaiting_transfer --> processing: updated
    awaiting_transfer --> expired: updated
    processing --> pending_review: updated
    pending_review --> processing: updated
    processing --> settled: completed
    processing --> failed: updated
    processing --> refunded: updated
    pending_review --> refunded: updated
    pending --> cancelled: updated
    settled --> refunded: updated
    settled --> [*]
    failed --> [*]
    refunded --> [*]
    expired --> [*]
    cancelled --> [*]
```

Not every transfer passes through every status. Only a transfer that is still
waiting for funds can expire, and only some transfers pass through
`pending_review`.

<Warning>
  `settled` is the only success status, and it never arrives on an `updated`
  event. Watch for `transactionTransfer.completed` to confirm a transfer
  succeeded. `updated` events cover every other status change.
</Warning>

### Webhooks by flow

The same three events cover each money movement flow. What differs is the
trigger for `created`.

| Flow | `created` fires when | Read more |
| :- | :- | :- |
| Onramp | Rain receives the sender's fiat deposit at the virtual account. | [Onramps](/docs/onramps) |
| Offramp | Rain detects the sender's stablecoin at the deposit address. | [Offramps](/docs/offramps) |
| Quoted transfer | You create a transfer from a quote with `POST /transfers`. | [Transfers](/docs/transfers) |

### Handle transfer webhooks

<Steps>
  <Step title="Subscribe to the events">
    Add your endpoint in the developer dashboard and subscribe to
    `transactionTransfer`. See [Set up webhooks](/docs/set-up-webhooks).
  </Step>

  <Step title="Key your records on the transaction ID">
    Use `body.id` as the transfer's identifier. Every event for one transfer
    carries the same `id`, and the `transfer` object is the full current state.
  </Step>

  <Step title="Branch on status">
    Update your record from `transfer.status`, using the
    [status and event map](#status-and-event-map) above.
  </Step>

  <Step title="Make the handler idempotent">
    Rain can retry or reorder events. Ignore an event whose status is older than
    the one you stored, and use `transfer.updatedAt` to compare. See
    [Handle event ordering](/docs/webhook-delivery#handle-event-ordering).
  </Step>
</Steps>

If you miss an event, call
[Get all transactions](/reference/transactions/get-all-transactions) with
`type=transfer` to read the current state.

## What's next

<Columns cols={2}>
  <Card title="Transaction Events" icon="money-bill-transfer" href="/docs/transaction">
    Every field and payload for the `transactionTransfer` events.
  </Card>

  <Card title="Webhook Delivery" icon="paper-plane" href="/docs/webhook-delivery">
    Signatures, retries, idempotency, and ordering for every webhook.
  </Card>

  <Card title="Refund Reasons" icon="rotate-left" href="/docs/refund-reasons">
    What each `refundReason` means and how to respond to it.
  </Card>

  <Card title="Transfers" icon="arrow-right-arrow-left" href="/docs/transfers">
    Create quoted transfers and see the statuses they pass through.
  </Card>
</Columns>
