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

# Rheon API

> One integration for stablecoin and bank rails - quotes, payment methods, statuses, limits, and errors, called from your own backend.

The API is the same set of rails the widget runs on, called from your backend, with
your own UI on top. It covers both directions money comes in - stablecoin from a
wallet, fiat from a card or a bank - behind one key and one error format.

This page is both the catalogue and the walkthrough: which products the API exposes,
then the order of calls, where the key lives, and what your backend has to do.

Two things hold across every product:

* **Non-custodial.** We never hold the funds and never sign: the transaction we
  return is unsigned and your user's wallet signs it. Nothing sits with us between
  the payer and the merchant.
* **Stateless.** There are no server-side sessions. Each call is keyed by the ids
  the previous call returned (`orderId`, `provider`, `payload`, `txHash`,
  `transactionId`, `accountId`). Your client holds the thread.

## Which products it covers

| Product | What you can call |
| - | - |
| [Crypto deposits](/products/crypto-deposits) | Quote a cross-chain deposit, get an unsigned transaction for the user's wallet to sign, track it to delivery |
| [On/off ramps with cards](/products/cards) | Price a card payment, start it, follow it to settlement; and quote, execute, and track a card payout |
| [Bank transfers](/products/ramps/on-ramp) | Verify a user, open an account with bank details, poll until money lands; and pay out to any bank account |
| [Virtual accounts](/products/virtual-accounts) | Create, read, update, and list accounts, and pay out from one |
| [Apple Pay](/products/apple-pay) | Part of on/off ramps with bank cards. Offered as a payment method on the hosted card page; native Apple Pay, where your own app presents the sheet, goes through the card calls |

Card issuing is documented separately - see [Card issuing](/products/card-issuing).

**Reference lookups** cover all of them: read the supported countries, currencies,
limits, rates, and statuses instead of hard-coding them.

Full request and response shapes are in the
[API reference](/api-reference/introduction).

## Authentication

Every call uses an API key against the `/v1` prefix. There is one kind of key: it
carries its products, corridors and rate, and works from your server or a page
alike, so keep it where only you can read it. What a key is allowed to settle -
which chains and tokens as a destination - is part of your account setup, not
something you pass per request. The header and what a refusal looks like are on
[Authentication](/api-reference/authentication).

## What your key carries

**Read your own setup rather than asking us for it.**
[`GET /v1/config`](/api-reference/configuration/what-this-key-may-use) answers it,
narrowed to your key: the `products` you may call, your `maxExecutionUsd`, and
under `crypto` the chains and tokens you may name. Call it first and build your
corridor list from it instead of keeping a copy.

| On the key | What it decides |
| - | - |
| **Products** | Which verticals the key may call: `deposits`, `cards`, `bank`, `virtual-accounts`. |
| **Source chains** | Where your users pay from. |
| **Destination chains** | Where you settle. |
| **Tokens** | Which contracts, on which chains, on either side. |
| **Rate** | Requests per second for the whole key. |
| **Execution ceiling** | The largest transfer the key may build, in USD. Quoting is never capped. |

A product not on your key is refused, never defaulted: its endpoints answer
`403 permission_denied` naming the product. To use a product that is not on
your key yet, ask us to add it - one configuration change on our side.

Source and destination are set separately on purpose: taking payment from a
chain and settling on it are different things, and you rarely want both
everywhere. A quote names both sides in full - `destination.chain` and
`destination.token` are required, and a chain your key is not enabled for is
refused with `403 chain_not_allowed`.

<Note>
  These corridors describe **your account setup, not a security boundary**. They
  keep your integration inside what we agreed and give you a clear error when a
  request falls outside it. If you need something locked down, lock it down on
  your side too - we will happily match it here, but do not rely on this as your
  only control.
</Note>

## Read the lists before you call anything

The reference lists come first in the API reference because you need them before
the first call: which countries can be onboarded, which chains, tokens and fiat
currencies exist, what every status means and which one to credit on, and the
per-rail limits. Start at
[Countries](/api-reference/reference/every-country-with-onboarding-eligibility)
and read them from the API rather than keeping a copy.

## Which environment answers

Every response starts with `environment`: `sandbox` or `production`, derived from
the upstreams this deployment is configured against. The products do not share
one: crypto deposits run on production with real money, cards and bank transfers
run on the providers' sandboxes. Each product page in this documentation and
each endpoint page in the reference says which applies to it.

## The flow

The walkthrough below is the crypto deposit path - the same three calls the widget
makes, on the same rails. The other products follow the same shape: price it,
start it, track it. Their calls are on the product pages linked above.

<Steps>
  <Step title="Price it">
    `POST /v1/deposit/quote` with where the money comes from, where it should
    land, and the amount.

    Decide which side the amount pins down. `exact-in` means the payer spends
    exactly that and whatever arrives, arrives. `target-out` (exact out) means a
    fixed figure must land and the payer's side flexes to cover it - this is the
    one you want when you are collecting a set price.

    See [Quote a deposit](/api-reference/crypto-deposits/quote-a-cross-chain-deposit).
  </Step>

  <Step title="Build the transaction">
    `POST /v1/deposit/transaction` with the quote you got back. You receive an
    unsigned transaction, and an approval transaction before it when the token
    allowance is not enough.

    See [Build the transaction](/api-reference/crypto-deposits/build-the-unsigned-transaction-for-a-quote).
  </Step>

  <Step title="Let the user sign">
    Your frontend submits it from the user's wallet. Nothing reaches us here.
  </Step>

  <Step title="Track it">
    `POST /v1/deposit/status` with the receipt from the submitted transaction.
    Poll it until it is done, or take the [webhook](/webhooks).

    See [Check status](/api-reference/crypto-deposits/where-a-submitted-deposit-is-by-receipt).
  </Step>
</Steps>

## Quotes

A quote prices the route and reserves liquidity, so it is only good for a short
window and the window is short on purpose. Two things follow for your UI:

* Show the user how long is left, and give them a way to ask for a fresh quote.
* Do not build a transaction from a quote you have been sitting on. Re-quote and
  build from the new one.

Quotes work in both directions. Fix what the payer spends and whatever arrives
arrives, or fix what has to land and let the payer's side flex to cover it - the
second is what you want when collecting a set price. How amounts are expressed on
either side is on [Amounts and currencies](/concepts/amounts-and-currencies).

## Naming the destination

Name both `destination.chain` and `destination.token` on the quote - a chain
without its token address is refused rather than guessed. Read the chains and
tokens your key may use from
[`GET /v1/config`](/api-reference/configuration/what-this-key-may-use).

Your key has to be enabled for that chain as a destination. If it is not, you get
`403 chain_not_allowed` rather than a quote you could not have used. That is your
account setup talking, not a security control - see
[What your key carries](#what-your-key-carries).

## Payment methods

What a user can pay with, per product:

* **Stablecoins** from a connected wallet, on any supported network - see
  [Coverage](/coverage).
* **Cards**, priced before the user commits to anything.
* **Bank transfers** into a virtual account: local rails and international wires,
  depending on the currency. The per-currency list is on [Coverage](/coverage) and
  served by [`GET /v1/currencies`](/api-reference/reference/chains-funding-assets-and-fiat-currencies).

## Statuses

Each product has its own small status set: deposits report `pending`, `done`,
`failed`, or `expired`; cards report `pending`, `processing`, `completed`, `failed`,
or `unknown`; bank transfers report `awaiting_deposit` or `funded`. In every set
there is exactly one state that means "credit the user" - `done`, `completed`,
`funded` - and you credit on that state only. A partner state we do not recognise is
reported as unknown and flagged, never quietly shown as "in progress". See
[Transaction statuses](/transactions/statuses).

## Rate limits

Your key carries a request ceiling, agreed when it is issued and counted per key,
never per IP: every request from you reaches us from your servers, so we see one
caller, not your users. Over the limit returns `429 rate_limited`. Design polling
and retries to stay under it - for status polling, a few seconds between calls is
plenty - and handle `429` by backing off rather than retrying immediately.

**Limiting your own users is yours to do.** You know who they are - they are
logged in to your product - and we do not. If one of them hammers your
integration, they will spend your ceiling and your other users will feel it.

If you are onboarding in bursts, tell us and we will raise your ceiling rather
than let you discover it in production.

## Amount limits

Amount limits are per rail and per provider. The stablecoin path is bounded by
live liquidity on the route, which is why a quote can come back as no route
available - that is a normal, temporary answer, not an error to retry in a loop.
Fiat minimums and maximums are per currency and rail - read them from
[`GET /v1/limits`](/api-reference/reference/per-transfer-ceilings-by-currency-and-rail).

## Errors

Every error comes back in the same envelope, with a `code` to branch on and a
`message` for your logs. The envelope, the full code table, and the one exception
(bank transfer and virtual account endpoints pass the banking partner's own codes
through unchanged) are on [Errors](/concepts/errors).

## Before you go live

<Check>Handle `403 chain_not_allowed` - it means the corridor was never yours, so retrying will not help.</Check>
<Check>Handle `429` by backing off, not by retrying immediately.</Check>
<Check>Treat `no_route` as a normal, temporary answer - liquidity moves.</Check>
<Check>Keep the key on your server and out of anything a browser can read.</Check>
