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

# Create an onramp checkout

> Create a Swapped checkout for card, Apple Pay, bank transfer, and other fiat payment methods.

Create a signed Swapped checkout URL for a registered account, then show Swapped's hosted UI in your app. Headless means you do not use the Rhinestone widget; it does not remove the provider's checkout UI.

## How it works

1. Your backend requests a signed checkout URL for the user's account.
2. Your app shows the URL in an iframe or in-app browser.
3. The user completes payment and any required KYC with Swapped.
4. Swapped sends provider-order updates as the payment progresses.
5. Swapped sends the purchased crypto, currently USDC on Base, to the account; the standard deposit pipeline then routes it to the account's target.

## Prerequisites

* The account is [registered](/deposits/headless/setup/account-registration). Minting a checkout URL for an account that is not registered to your project returns `403 Unauthorized`.
* A [webhook URL](/deposits/headless/processing-and-tracking/webhooks#configure-webhooks) is configured if you want order updates pushed rather than polled.
* Calls are made from your backend. The endpoints require your API key, which never ships in client-side code.

## Mint a checkout URL

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

const response = await fetch(`${DEPOSIT_SERVICE_URL}/onramp/swapped/widget-url`, {
    method: "POST",
    headers: { "Content-Type": "application/json", "x-api-key": API_KEY },
    body: JSON.stringify({
        smartAccount: "0xUSER_ACCOUNT_ADDRESS",
        baseCurrencyCode: "EUR",
        baseCurrencyAmount: 100,
        method: "apple-pay", // optional — omit to let Swapped choose the best method
    }),
});

const { url, externalCustomerId, expiresAt } = await response.json();
```

Only `smartAccount` is required — every other field, including `method`, is optional and simply prefills the widget. If you omit `method`, Swapped auto-selects the best payment method for the user based on their location and other signals:

| Field                | Type     | Description                                                                                                                                                            |
| -------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `smartAccount`       | `string` | The registered account that receives the crypto                                                                                                                        |
| `email`              | `string` | Prefills the user's email                                                                                                                                              |
| `baseCountry`        | `string` | User's country (ISO 3166-1 alpha-2, e.g. `"DE"`)                                                                                                                       |
| `baseCurrencyCode`   | `string` | Fiat currency to charge in (e.g. `"EUR"`)                                                                                                                              |
| `baseCurrencyAmount` | `number` | Prefilled purchase amount in the fiat currency                                                                                                                         |
| `locale`             | `string` | Widget language                                                                                                                                                        |
| `method`             | `string` | **Optional.** Preselects a payment method — accepts any method Swapped supports (see the list below). Omit it to let Swapped auto-select the best method for the user. |

`method` takes a Swapped **payment group**. Swapped offers 40+ methods and the set available depends on the user's region — common values include `"creditcard"`, `"apple-pay"`, `"bank-transfer"`, `"skrill"`, `"pix"`, and `"sepa-bank-transfer"`. Pass a method's `payment_group`; the authoritative, up-to-date list for your account is Swapped's [Get Payment Methods](https://docs.swapped.com/swapped-ramp/endpoints/onramp-endpoints/get-payment-methods) endpoint. A value Swapped doesn't support for the user is ignored rather than rejected — the widget falls back to the best available method, so an unrecognized `method` never blocks checkout.

The response carries the signed URL:

| Field                | Type      | Description                                                                 |
| -------------------- | --------- | --------------------------------------------------------------------------- |
| `url`                | `string`  | The checkout URL to embed                                                   |
| `currencyCode`       | `string`  | Asset the purchase settles in, as `ASSET_NETWORK` (currently `"USDC_BASE"`) |
| `sandbox`            | `boolean` | `true` when the service runs against Swapped's sandbox                      |
| `externalCustomerId` | `string`  | `<account>:<orderUuid>` — correlates the checkout with its webhooks         |
| `expiresAt`          | `string`  | End of the order-tracking window (ISO 8601)                                 |

The URL is signed by the service, so its parameters — destination wallet and asset — can't be modified client-side. Mint a fresh URL for each checkout session. The purchase always settles in the asset reported by `currencyCode`; when the account's target differs, the bridge hop happens automatically.

Full request and response schemas: [`POST /onramp/swapped/widget-url`](/api-reference/deposit-service/onramp/create-a-fiat-funding-url).

## Show the hosted checkout

Embed the URL in an iframe with payment and camera permissions — Apple Pay and camera-based KYC need them:

```html theme={null}
<iframe src={url} allow="payment; camera; microphone; clipboard-write" />
```

In a mobile app, open the URL in an in-app browser (`SFSafariViewController` on iOS, Chrome Custom Tabs on Android) rather than a plain WebView — Apple Pay and camera access are restricted in bare WebViews.

The URL carries no redirect or callback parameter. Detect completion through the [`onramp-order`](/deposits/headless/processing-and-tracking/webhooks#onramp-order) webhook or by [polling order status](/deposits/headless/processing-and-tracking/track-onramp-and-exchange-orders#poll-the-latest-order), then dismiss the hosted checkout from your own UI.

<Warning>
  A user who abandons checkout produces no terminal event — the order simply
  never progresses. Apply your own timeout when waiting on an order.
</Warning>

KYC, identity verification, and purchase limits are handled by Swapped inside the hosted UI. Track provider progress and final deposit settlement separately in [Track onramp and exchange orders](/deposits/headless/processing-and-tracking/track-onramp-and-exchange-orders).
