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

# Accept crypto at checkout

> Add pay with crypto to an existing checkout. Customers pay from any wallet, token, or chain, and you receive an exact amount in the token and network you choose.

This guide shows you how to add pay with crypto to a checkout: you receive an exact amount in the token and network you choose, and the customer pays from whatever they hold. You need an OMS publishable key (`pk_...`) and the [SDK installed](https://docs.polygon.technology/cross-chain/sdk/index.md).

> [!TIP]
>
> To see the customer experience first, try the [demo store checkout](https://demo.trails.build/storefront/checkout).

## Accept a payment

Render `Pay` with the amount you want to receive. The customer picks a wallet and token, OMS quotes how much they need to send, and the widget handles the rest.

```tsx theme={null}
import { Pay } from "0xtrails/widget";

export function CheckoutButton({ orderId }: { orderId: string }) {
  return (
    <Pay
      apiKey="pk_..."
      to={{
        recipient: "0xYOUR_SETTLEMENT_ADDRESS",
        token: "USDC",
        chain: "polygon",
        amount: "25",
      }}
      payMessage={`Order #${orderId}`}
      onPaymentSuccess={({ intentId }) => markOrderPaid(orderId, intentId)}
    />
  );
}
```

`to.amount` is the exact amount you receive, in human-readable units. `to.token` and `to.chain` fix what you are paid in; the customer cannot change them.

## Confirm payment before fulfilling

`onPaymentSuccess` runs in the browser, so treat it as a signal, not proof. Send the `intentId` to your server and confirm the intent reached `SUCCEEDED` with [`GetIntentReceipt`](https://docs.polygon.technology/cross-chain/api-reference/monitoring#getintentreceipt) before you ship the order.

## Choose how the customer pays

Omit `paymentMethod` to let the customer choose. Set it to open a specific flow:

| Value | Customer pays with |
| - | - |
| `CONNECTED_WALLET` | A connected wallet (default) |
| `CRYPTO_TRANSFER` | A transfer to a deposit address, shown as a QR code |
| `CREDIT_DEBIT_CARD` | A card |
| `EXCHANGE` | An exchange account balance |

`CRYPTO_TRANSFER` suits in-store and QR checkouts where the customer pays from a phone wallet that is not connected to your site.

## Charge a USD price

If you already take card payments through a processor account connected to OMS, you can price the order in US dollars and let customers pay that price in crypto. Render `TrailsWidget` with `stripe` set to the price in cents and your order reference. The destination comes from the armed payment, so do not pass destination props.

```tsx theme={null}
import { TrailsWidget } from "0xtrails/widget";

<TrailsWidget
  apiKey="pk_..."
  stripe={{ amountCents: 2500, orderRef: "order-123", chainId: 137 }}
  onSuccess={({ intentId, settlement }) => fulfillOrder(intentId, settlement)}
/>
```

Settlement chains are Polygon (`137`), Base (`8453`, the default), and Ethereum (`1`). The widget holds `onSuccess` until the processor confirms settlement. The browser declares `amountCents`, so verify the settled amount and order reference against your own order records before fulfilling. This flow must be enabled for your project; contact the team to turn it on.

`onPaymentCreated` fires once per processor payment, with its `settlement` details, when the quote creates it and before the customer pays. Re-quotes for the same `orderRef` reuse the payment. Use it to link the payment to your order. If your processor account uses test keys, set `stripe.testMode` to `true`; test payments settle on Base Sepolia (`84532`).

## Brand the checkout

Set `appMetadata` so wallet connection prompts show your store, and use `theme` and `customCss` to match your site. To rename the confirm button or screen titles, pass `labels`. To require agreement to your terms before paying, pass `consentCheckbox`; the customer must tick it every session.

```tsx theme={null}
<Pay
  apiKey="pk_..."
  to={{ recipient: "0xYOUR_SETTLEMENT_ADDRESS", token: "USDC", chain: "polygon", amount: "25" }}
  labels={{ confirmButton: "Place order" }}
  consentCheckbox={{
    label: 'I agree to the <a href="/terms">terms of sale</a>',
    requiredMessage: "Accept the terms of sale to continue.",
  }}
/>
```

See [configuration](https://docs.polygon.technology/cross-chain/sdk/configuration.md) for every option.

## Without React

Load the widget from a CDN and render it into any element:

```html theme={null}
<div id="checkout"></div>
<script src="https://cdn.jsdelivr.net/npm/0xtrails/dist/iife/trails.min.js"></script>
<script>
  TrailsWidget.render(document.getElementById("checkout"), {
    apiKey: "pk_...",
    mode: "pay",
    toAddress: "0xYOUR_SETTLEMENT_ADDRESS",
    toAmount: "25",
    toChainId: 137,
    toToken: "USDC",
  });
</script>
```

Pin a package version in production, for example `0xtrails@1.2.3`, so an SDK release cannot change your checkout unannounced.
