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

# Stripe On-ramp Tutorial

> Tutorial: use Stripe's Crypto On-ramp API to let users buy USDC on Polygon inside your app.

This tutorial shows how to use Stripe's Crypto On-ramp API to let users buy USDC
on Polygon directly inside your application. You will create an On-ramp session
on the backend and render Stripe's hosted widget on the frontend.

<Warning title="Security notice">
  All examples below are demonstrations only.
  In production, never expose `STRIPE_SECRET_KEY` or private wallet keys in client code. Store them in a secure vault or secrets manager.
</Warning>

## Prerequisites

* A US-based business entity (excluding Hawaii)
* [Stripe account](https://dashboard.stripe.com/) with the On-ramp feature enabled (appears automatically after compliance verification)
* Stripe API key (`sk_test_...` or `sk_live_...`)

### Reference docs

* [Stripe API - Crypto On-ramp Sessions](https://docs.stripe.com/crypto/onramp_sessions)
* [Stripe Node SDK](https://github.com/stripe/stripe-node)

## Schema

| name                          | type   | required | example                  | description                            |
| ----------------------------- | ------ | -------- | ------------------------ | -------------------------------------- |
| destination\_currency         | string | ✅        | `"usdc"`                 | The target crypto asset                |
| destination\_network          | string | ✅        | `"polygon"`              | Blockchain network                     |
| wallet\_address\[0]\[type]    | string | ✅        | `"self_custody"`         | Type of wallet                         |
| wallet\_address\[0]\[address] | string | ✅        | `"0xYourPolygonAddress"` | Destination wallet address             |
| STRIPE\_SECRET\_KEY           | string | ✅        | `"sk_test_..."`          | Your Stripe API key (server-side only) |

## Create Session cURL

Run this on your backend server only (never in a browser):

```bash theme={null}
curl https://api.stripe.com/v1/crypto/onramp_sessions \
  -u sk_test_your_secret_key: \
  -d destination_currency=usdc \
  -d destination_network=polygon \
  -d wallet_addresses[0][type]=self_custody \
  -d wallet_addresses[0][address]=0xYOUR_POLYGON_ADDRESS
```

If successful, Stripe returns a JSON response containing a client\_secret:

```json theme={null}
{
  "id": "cos_0MYvmj589O8KAxCGp14dTjiw",
  "object": "crypto.onramp_session",
  "client_secret": "cos_0MYvmj589O8KAxCGp14dTjiw_secret_BsxEqQLiYKANcTAoVnJ2ikH5q002b9xzouk",
  "created": 1675794053,
  "livemode": false
}
```

## Bun / NodeJS backend

```ts theme={null}
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export async function createOnrampSession(req, res) {
  const session = await stripe.crypto.onramps.sessions.create({
    destination_currency: "usdc",
    destination_network: "polygon",
    wallet_addresses: [
      { type: "self_custody", address: "0xYOUR_POLYGON_ADDRESS" }
    ],
    // optional: customer, email, reference
  });
  res.json({ client_secret: session.client_secret });
}
```

## Serve to Frontend

Pass only the client\_secret to your client app. Never pass your Stripe secret key.

```html theme={null}
<script src="https://js.stripe.com/v3/crypto/onramp.js"></script>
<div id="onramp"></div>

<script>
(async () => {
  // Fetch client_secret from your backend
  const { client_secret } = await fetch("/api/create-onramp-session").then(r => r.json());

  const onramp = await window.StripeOnramp.init({
    clientSecret: client_secret,
    appearance: {
      theme: "light", // optional UI customization
    },
  });

  onramp.mount("#onramp");
})();
</script>
```

Users can now buy USDC on Polygon directly from your site.

The funds are sent to the wallet specified in your `onramp_session`.

## Reference

Configuration parameters, error codes, and guardrails.

### Do / Don't Do Guardrails

| ✅ Do                                   | ❌ Don't                                         |
| -------------------------------------- | ----------------------------------------------- |
| Store API keys in a vault, not in code | Hardcode `STRIPE_SECRET_KEY` in frontend        |
| Use Stripe Sandbox first               | Test with live key before compliance is cleared |
| Log only non-sensitive session info    | Log full `client_secret` values                 |

### Errors

| code                          | meaning                   | fix                          |
| ----------------------------- | ------------------------- | ---------------------------- |
| 403\_access\_denied           | Onramp not enabled        | Wait for compliance review   |
| 400\_invalid\_wallet\_address | Bad or unsupported wallet | Verify address format        |
| 401\_unauthorized             | Wrong API key             | Use correct/test or live key |

### Quick Checklist

* Backend has `STRIPE_SECRET_KEY` set
* Frontend only receives `client_secret`
* Wallet address is valid on Polygon
* Tested in Sandbox before production
