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

# Bank transfers

> POST /fiat/onboard, /fiat/account, /fiat/status - a bank transfer that converts on arrival.

A buyer gets real bank details, sends a normal transfer, and stablecoins land in
their wallet. Three calls, in order.

<Warning>
  **Not live yet.** The flow is built and tested, but the commercial agreement with
  the banking partner is not signed, so there is no production account behind it. The
  contract below is what runs today on sandbox and is not expected to change.
</Warning>

## The order

<Steps>
  <Step title="Onboard the buyer">
    `POST /fiat/onboard` - register them and link the wallet the stablecoins go to.
    Returns ids you hold for the rest of the flow.
  </Step>

  <Step title="Open a virtual account">
    `POST /fiat/account` - returns the bank details to display (IBAN or SWIFT), plus
    the fee that applies.
  </Step>

  <Step title="Wait for the money">
    `POST /fiat/status` - poll until funded. Bank transfers settle in hours or days,
    not seconds.
  </Step>
</Steps>

## Identity checks

We do not run our own identity flow. The buyer verifies once with an identity
provider, and that result is shared with the banking partner - so a returning buyer
is not asked twice. `/fiat/onboard` takes the authorization code from that flow.

***

## POST /fiat/onboard

<ParamField body="authCode" type="string" required>
  One-time authorization code from the identity flow. Single use - a stale or reused
  code is rejected.
</ParamField>

<ParamField body="applicantInfo" type="object" required>
  <Expandable title="applicantInfo">
    <ParamField body="nationality" type="string" required>
      ISO 3166-1 alpha-2 country code.
    </ParamField>

    <ParamField body="phone" type="string" required>
      E.164 format, e.g. `+14155551234`.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="individual" type="object" required>
  <Expandable title="individual">
    <ParamField body="name" type="string" required />

    <ParamField body="email" type="string" required />

    <ParamField body="country" type="string" required>
      ISO 3166-1 alpha-2 country code.
    </ParamField>

    <ParamField body="category" type="string">
      Defaults to `self_employed` when omitted.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="wallet" type="string" required>
  The EVM address the stablecoins are delivered to.
</ParamField>

**Returns** `accountId`, `walletId` and `kycStatus`. Hold the first two.

***

## POST /fiat/account

<ParamField body="accountId" type="string" required />

<ParamField body="walletId" type="string" required />

<ResponseField name="id" type="string">
  Virtual account id. Pass it to `/fiat/status`.
</ResponseField>

<ResponseField name="details" type="object">
  The bank details to show the buyer - IBAN or SWIFT coordinates, and the reference
  that ties their transfer to this account.
</ResponseField>

<ResponseField name="applicationFeeBps" type="number">
  The fee applied to this account, in basis points (100 bps = 1%).
</ResponseField>

<Note>
  Show the reference prominently. A transfer that arrives without it takes manual
  work to attribute.
</Note>

***

## POST /fiat/status

<ParamField body="accountId" type="string" required />

<ParamField body="virtualAccountId" type="string" required />

<ResponseField name="status" type="string">
  `awaiting_deposit` or `funded`. Poll on the first; the second is terminal.
</ResponseField>

<ResponseField name="deliveredAmount" type="string">
  Once funded: what actually landed, as a decimal string in the currency's major
  unit. **Credit this**, not the amount the buyer said they would send.
</ResponseField>

## Errors

| HTTP | `code`            | When                                                                                                        |
| ---- | ----------------- | ----------------------------------------------------------------------------------------------------------- |
| 400  | `invalid_request` | A field is missing or malformed - nationality not two letters, phone not E.164, wallet not a valid address. |
| 400  | *provider code*   | The banking partner rejected the request; its own code is passed through unchanged.                         |
| 429  | `rate_limited`    | Over the rate limit (5 requests / 10s / IP).                                                                |
| 502  | `upstream_error`  | The banking partner is unavailable.                                                                         |
| 500  | `internal`        | Unexpected server error.                                                                                    |
