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

# Track onramp and exchange orders

> Track fiat and exchange orders stage by stage, from payment to the on-chain deposit.

```ts theme={null}
const DEPOSIT_SERVICE_URL =
  "https://v1.orchestrator.rhinestone.dev/deposit-processor";
const API_KEY = "YOUR_RHINESTONE_API_KEY";
```

Fiat checkouts and exchange connections share one order model. An order is `completed` only once the purchased crypto has landed on-chain as a deposit, not merely when the provider reports sending it. After that, the deposit follows the [standard pipeline](/deposits/headless/processing-and-tracking/track-deposits) to the account's target.

## Order stages

Every order moves money through four stages:

| Stage | Tracks | Statuses |
| - | - | - |
| `receipt` | The user's fiat payment | `not_started`, `pending`, `on_hold`, `processing`, `completed`, `failed` |
| `conversion` | Fiat converted to crypto | `not_started`, `processing`, `on_hold`, `completed`, `failed` |
| `delivery` | Crypto sent to the account | `not_started`, `pending`, `on_hold`, `submitted`, `completed`, `failed` |
| `return` | Money sent back to the user, if any | `none`, `pending`, `processing`, `completed`, `failed` |

* `delivery` is `submitted` with a `txHash` once the provider reports the transfer, and `completed` with a `depositId` only once that transfer landed as a deposit on the account.
* `on_hold` and `failed` carry a `reason`: for example `kyc_required` while the user still has to verify, or `cancelled` and `declined` when a payment fails.
* `return` stays `none` unless money goes back; a `completed` return carries an `outcome` (`full_refund`, `adjustment`, or `unresolved`).

Each order also has a `status` derived from its stages, and `terminal` once no stage will change again:

| Status | Meaning | Terminal |
| - | - | - |
| `pending` | Order created; awaiting payment | no |
| `processing` | Payment or delivery under way | no |
| `completed` | Crypto landed on-chain as a deposit | yes |
| `failed` | A stage failed, e.g. the payment was cancelled | yes |
| `refunded` | The user was fully refunded | yes |

Exchange orders reach `completed` the same way as fiat orders, once the transfer lands.

## Get an order

```ts theme={null}
const response = await fetch(`${DEPOSIT_SERVICE_URL}/onramp/orders/${orderId}`, {
    headers: { "x-api-key": API_KEY },
});
const order = await response.json();
// {
//     id: "063b7aa7-…",
//     provider: "swapped",
//     kind: "fiat",
//     status: "completed",
//     terminal: true,
//     stages: {
//         receipt: { status: "completed" },
//         conversion: { status: "completed" },
//         delivery: { status: "completed", txHash: "0x23ea…", depositId: "3018" },
//         return: { status: "none" }
//     },
//     rail: { kind: "fiat", method: "creditcard" },
//     fiat: {
//         charged: { currency: "GBP", total: "40.00", net: null },
//         eur: { total: "46.21", net: null },
//         usd: { total: "52.50", net: "50.00" }
//     },
//     crypto: { asset: "USDC", network: "base", amount: "49.87" },
//     account: "0x1234…",
//     deliveryAddress: "0x1234…",
//     providerStatus: "order_broadcasted",
//     createdAt: "2026-01-15T12:00:00.000Z",
//     updatedAt: "2026-01-15T12:03:00.000Z"
// }
```

`id` accepts either the order's `id` or the `orderId` returned when you [started it](/deposits/headless/funding/create-an-onramp-checkout#start-an-order). It returns `404` until the provider first reports the order, which happens when the user starts paying, and for another project's order.

* **Fiat figures:** `charged` is what the user paid in their own currency; `eur` is comparable across every order; `usd` is present when the provider reports it. Each has a `total` including fees and a `net` before fees, and any of them is `null` when the provider didn't state it.
* **`rail`:** the payment method or exchange, or `provider_selected` when the provider didn't say.
* **`providerStatus`:** the provider's own status, for support; don't branch on it.

Full schema: [`GET /onramp/orders/{id}`](/api-reference/deposit-service/onramp/get-an-onramp-order).

## List orders

List your project's orders, newest first by when each began, optionally for one account:

```ts theme={null}
const response = await fetch(
    `${DEPOSIT_SERVICE_URL}/onramp/orders?account=0xUSER_ACCOUNT_ADDRESS&limit=20`,
    { headers: { "x-api-key": API_KEY } },
);
const { items, nextCursor } = await response.json();
```

Pass `nextCursor` as `cursor` for the next page; it is `null` on the last one. Orders are kept for good, including pending and cancelled ones. Full schema: [`GET /onramp/orders`](/api-reference/deposit-service/onramp/list-onramp-orders).

## Push updates

Each stage move sends a [`ramp-order`](/deposits/headless/processing-and-tracking/webhooks#ramp-order) webhook carrying the whole order in the shape above, so you can store the latest one rather than fetch after each event. The delivery's `txHash` reappears as the `transactionHash` on the [`deposit-received`](/deposits/headless/processing-and-tracking/webhooks#deposit-received) event, followed by the usual bridge events. Card and Apple Pay orders typically complete within minutes; bank transfers can take days. Exchange timing depends on the provider flow.

## Processing caveats

* **Session coverage** — on-ramp purchases land on Base, so the account's session set must include Base. The default [registration flow](/deposits/headless/setup/account-registration) covers every supported chain; if you restrict `sessionChainIds`, include Base or landed funds can't be bridged.
* **Deposit whitelist** — if you [restrict accepted deposits](/deposits/headless/setup/project-configuration#restrict-accepted-deposits), allow USDC on Base above your minimum. Otherwise every on-ramp purchase is rejected with [`deposit-rejected`](/deposits/headless/processing-and-tracking/webhooks#deposit-rejected).
* **Same-chain target** — when the account's target is USDC on Base paid to the account itself, the purchase is already at its destination: no bridge events fire, and the order's `completed` status is your terminal signal.
* **KYC and limits** — identity verification and purchase limits are handled by Swapped inside the hosted UI.

## Migrate from the legacy route and webhook

`GET /onramp/swapped/status/{smartAccount}` has been removed and returns `404`; read orders from `GET /onramp/orders` instead. The [`onramp-order`](/deposits/headless/processing-and-tracking/webhooks#onramp-order) webhook keeps working unchanged until its retirement is announced. It reports Swapped's own statuses, and exchange orders never leave `processing` there. Move to `ramp-order`, which reports each order stage by stage.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.