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

# On-Ramp

> Buy tokenized assets / RWA with a credit card. A fiat on-ramp powered by Halliday that delivers USDC on Ethereum straight to your user's wallet — ready to deposit into a Product Account and buy tokenized equities or RWA yield tokens.

## What It Does

Let your users **buy tokenized stocks and RWA with a card**. The on-ramp takes
fiat from a credit/debit card (or bank), runs the regulated payment + KYC, and
delivers **USDC on Ethereum** directly to the user's own wallet — the first leg
of the hero flow:

```
card + KYC  →  USDC on Ethereum  →  user's wallet  →  Product Account  →  tokenized buy
   (Halliday hosted checkout)        (delivered)        (deposit)         (Tokenized Assets)
```

The second leg (deposit USDC into the [Tokenized Assets Account](/v2/Products/Accounts)
then [buy a tokenized equity or RWA yield token](/v2/Products/Tokenized-Assets))
already exists — this product wires up the missing fiat entry point so the whole
"buy real-world assets with a card" journey works end to end.

Under the hood the on-ramp is **[Halliday](https://halliday.xyz)** — a
non-custodial on-ramp aggregator that sits above MoonPay / Transak / Stripe /
Coinbase Pay, accepts any payment method, and bridges + swaps the proceeds into
the exact token you ask for. Compass exposes it as three thin endpoints plus a
hosted checkout page; the regulated fiat + identity work happens inside
Halliday's checkout.

<Info>
  **Compass is a stateless proxy here.** Unlike [CCTP bridging](/v2/Products/Bridging),
  where Compass is the orchestrator and tracks each bridge across burn → mint, the
  on-ramp holds **no server-side state** — no Redis store, no attestation poller,
  no webhooks. **Halliday owns every piece of order state** (quote, deposit
  address, payment status, delivery tx) and Compass re-reads it on demand. The
  `payment_id` you receive is Halliday's id, passed straight through.
</Info>

## The Three Endpoints

| Method + path                        | What it does                                                                                                                               |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `POST /v2/onramp/quote`              | Indicative fiat → USDC quote: rate, fees, estimated output, min/max.                                                                       |
| `POST /v2/onramp/create`             | Starts a payment. Returns `checkout_url` + `payment_id` + `user_instructions` (plus the one-time deposit address and an initial `status`). |
| `GET /v2/onramp/status?payment_id=…` | Current order status (`pending` / `processing` / `delivered` / `failed`) and delivery details.                                             |

Output is fixed to **USDC on Ethereum**, delivered to the `destination_address`
you pass in. (Halliday's any-token / any-chain capability is intentionally not
exposed.)

## End-to-End Flow

<Steps>
  <Step title="Quote">
    `POST /v2/onramp/quote` with the fiat amount and the destination address.
    Preview the USDC the user will receive, the fees (`business_fees` is `0`
    today — no Compass markup), and the min/max bounds.
  </Step>

  <Step title="Create">
    `POST /v2/onramp/create` to start the payment. The response carries a
    `checkout_url` (a Compass-hosted page that renders Halliday's card + KYC
    checkout), a `payment_id`, and a `user_instructions` string describing the
    browser handoff.
  </Step>

  <Step title="Open the checkout">
    Send the user to `checkout_url` in a browser. Halliday collects the card
    details and runs identity verification. The user never leaves your control
    of the URL — it points at a page **you** host.
  </Step>

  <Step title="Poll status">
    Poll `GET /v2/onramp/status?payment_id=…` until `status` is `delivered`
    (or a terminal `failed`). USDC lands at the `destination_address` on
    Ethereum.
  </Step>

  <Step title="Deposit & buy">
    Move the delivered USDC into the user's [Tokenized Assets Account](/v2/Products/Accounts)
    and [place a tokenized order](/v2/Products/Tokenized-Assets). This leg is
    unchanged by the on-ramp.
  </Step>
</Steps>

## Quote

`POST /v2/onramp/quote` returns an indicative fiat → USDC quote.

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X POST https://api.compasslabs.ai/v2/onramp/quote \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "fiat_amount":         "100",
      "fiat_currency":       "USD",
      "destination_address": "0xYourUserWalletAddress"
    }'
  ```

  ```python Python theme={"system"}
  import httpx

  quote = httpx.post(
      "https://api.compasslabs.ai/v2/onramp/quote",
      json={
          "fiat_amount":         "100",
          "fiat_currency":       "USD",
          "destination_address": "0xYourUserWalletAddress",
      },
      headers={"x-api-key": "YOUR_API_KEY"},
  ).json()

  print(quote["output_amount"], quote["output_asset"], quote["output_chain"])
  # e.g. "99.4" "USDC" "ethereum"
  ```

  ```typescript TypeScript theme={"system"}
  const quote = await fetch(
    "https://api.compasslabs.ai/v2/onramp/quote",
    {
      method: "POST",
      headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" },
      body: JSON.stringify({
        fiat_amount:         "100",
        fiat_currency:       "USD",
        destination_address: userWalletAddress,
      }),
    },
  ).then(r => r.json());
  ```
</CodeGroup>

The quote echoes `output_asset: "USDC"`, `output_chain: "ethereum"`, the
`exchange_rate`, a `fees` block (`business_fees` fixed at `"0"`), `min_amount`,
`max_amount`, and `expires_at`.

## Create

`POST /v2/onramp/create` starts the payment and returns the browser-handoff
fields.

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X POST https://api.compasslabs.ai/v2/onramp/create \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "fiat_amount":         "100",
      "fiat_currency":       "USD",
      "destination_address": "0xYourUserWalletAddress"
    }'
  ```

  ```python Python theme={"system"}
  create = httpx.post(
      "https://api.compasslabs.ai/v2/onramp/create",
      json={
          "fiat_amount":         "100",
          "fiat_currency":       "USD",
          "destination_address": "0xYourUserWalletAddress",
      },
      headers={"x-api-key": "YOUR_API_KEY"},
  ).json()

  payment_id        = create["payment_id"]
  checkout_url      = create["checkout_url"]
  user_instructions = create["user_instructions"]
  # Send the user to `checkout_url` in a browser, then poll status with `payment_id`.
  ```

  ```typescript TypeScript theme={"system"}
  const create = await fetch(
    "https://api.compasslabs.ai/v2/onramp/create",
    {
      method: "POST",
      headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" },
      body: JSON.stringify({
        fiat_amount:         "100",
        fiat_currency:       "USD",
        destination_address: userWalletAddress,
      }),
    },
  ).then(r => r.json());

  const { payment_id, checkout_url, user_instructions } = create;
  window.open(checkout_url, "_blank");
  ```
</CodeGroup>

The response includes:

* `checkout_url` — a **Compass-hosted page** (`/onramp/checkout`) that embeds
  Halliday's card + KYC checkout. Open it in a browser.
* `payment_id` — Halliday's order id, used for status polling.
* `user_instructions` — an agent-actionable string explaining the browser
  handoff and the poll loop (surfaced verbatim by the CLI and MCP tools).
* `deposit_address` — the one-time wallet (OTW) Halliday creates for this
  payment; it is owned solely by the user's wallet.
* `status` — the initial order status.

## Status

`GET /v2/onramp/status?payment_id=…` returns the current state.

<CodeGroup>
  ```bash cURL theme={"system"}
  curl "https://api.compasslabs.ai/v2/onramp/status?payment_id=PAYMENT_ID" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```python Python theme={"system"}
  status = httpx.get(
      "https://api.compasslabs.ai/v2/onramp/status",
      params={"payment_id": payment_id},
      headers={"x-api-key": "YOUR_API_KEY"},
  ).json()

  print(status["status"])  # pending | processing | delivered | failed
  if status["status"] == "delivered":
      print(status["output_amount_delivered"], status["delivery_tx_hash"])
  ```

  ```typescript TypeScript theme={"system"}
  const status = await fetch(
    `https://api.compasslabs.ai/v2/onramp/status?payment_id=${payment_id}`,
    { headers: { "x-api-key": "YOUR_API_KEY" } },
  ).then(r => r.json());
  ```
</CodeGroup>

Status maps onto a 4-value enum:

| Status       | Meaning                                                                                                  |
| ------------ | -------------------------------------------------------------------------------------------------------- |
| `pending`    | Order created, awaiting payment.                                                                         |
| `processing` | Payment received; bridging / swapping to USDC on Ethereum.                                               |
| `delivered`  | USDC delivered to `destination_address`. `output_amount_delivered` and `delivery_tx_hash` are populated. |
| `failed`     | Payment failed, expired, or was refunded.                                                                |

## KYC and Custody

<Tip>
  **KYC is a wallet-signature gate, tiered by amount:**

  * **Under \$300** — no signature required.
  * **\$300 and above** — Halliday requires an `EVM_OWNER` wallet signature from
    the destination wallet.
  * The underlying payment provider runs the heavy ID / document KYC inside the
    hosted checkout; you do not build any KYC UI.

  **Non-custodial end to end.** Halliday's **One-Time-Wallet (OTW)** model creates
  a fresh deposit address owned solely by the user's wallet for each payment, so
  neither Halliday nor Compass ever custodies the funds. The regulated fiat / KYC
  leg lives entirely with the underlying provider.
</Tip>

## Constraints

<Warning>
  * **USDC on Ethereum only.** The output is fixed to USDC on Ethereum mainnet;
    any other asset or chain is rejected. (Halliday's any-token / any-chain
    capability is intentionally not exposed.)
  * **No Compass fee yet.** `business_fees` is `"0"` — there is no monetization on
    the on-ramp today (it is a single future lever).
  * **Sandbox until the live key lands.** The integration runs against Halliday's
    **sandbox** by default. Use a test card in sandbox; production requires the
    live publishable key.
  * **On-ramp only.** Off-ramp (crypto → fiat) is **not available** — it is not
    yet live at Halliday. If you need it, [get in touch](https://discord.com/invite/ujetyJJPYr).
</Warning>

## Across Every Surface

Because the on-ramp is an ordinary `/v2/*` API surface, it shows up everywhere
Compass surfaces do:

* **Widgets** — the [`<HallidayOnrampCheckout/>`](/v2/Products/Widgets) component
  powers the "Buy with card" path in the Tokenized Assets widget (and the
  Telegram mini-app's deposit sheet).
* **Hosted page** — the `checkout_url` points at a Compass-hosted
  `/onramp/checkout` page embedding that same component.
* **CLI** — `compass onramp buy` runs quote → create → opens the browser →
  polls status until `delivered` (a `gh auth login`-style handoff).
* **MCP** — the `v2_onramp_quote` / `v2_onramp_create` / `v2_onramp_status`
  tools let an agent start a payment, present `checkout_url` + `user_instructions`
  to the user, and poll `v2_onramp_status` to confirm delivery.

## Next Steps

<CardGroup cols={3}>
  <Card title="Tokenized Assets" icon="building-columns" href="/v2/Products/Tokenized-Assets">
    The second leg — deposit the delivered USDC and buy tokenized equities / RWA.
  </Card>

  <Card title="Product Accounts" icon="wallet" href="/v2/Products/Accounts">
    Where the deposited USDC lands before a tokenized buy.
  </Card>

  <Card title="Widgets" icon="puzzle-piece" href="/v2/Products/Widgets">
    Embed `<HallidayOnrampCheckout/>` and the rest of the Compass widgets.
  </Card>
</CardGroup>
