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

# Pay with Card

> Accept card payments for NFTs or tokens through the Orders REST API

## Introduction

In this quickstart you will learn how to accept credit card payments (including Apple and Google Pay) using Crossmint's headless APIs to purchase an NFT or a token (such as a Solana memecoin).

> [!TIP]
>
> For a faster, embedded checkout solution with minimal setup time, see the [embedded
> quickstart](https://docs.crossmint.com/payments/embedded/quickstarts/credit-card.md).

## Prerequisites

### From Crossmint

1. Create a developer account in the [Staging Console](https://staging.crossmint.com/console).
2. Create a server-side API key with the `orders.create`, `orders.update`, and `orders.read` scopes enabled. [More info on creating API keys here](https://docs.crossmint.com/introduction/platform/api-keys#how-to-get-and-use-api-keys).

> [!WARNING]
>
> This Quickstart assumes that you will be using the [API Playground](https://docs.crossmint.com/api-reference/headless/create-order.md) or cURL requests to make the API calls. This approach requires the use of a server-side API key.
>
> If you would rather follow the quickstart while building a client-side app that makes requests to Crossmint directly from the browser, you must use a client-side API key. For client-side usage, you don't need the `orders.read` scope - use the `clientSecret` from order creation for subsequent operations.
> See the [Server or Client Guide](https://docs.crossmint.com/payments/headless/guides/client-or-server) for more information.

> [tab] NFTs
>
> [Create a new collection](https://docs.crossmint.com/payments/guides/create-collection.md) or [import yours](https://docs.crossmint.com/payments/guides/register-collection.md) into the console, and have your `collectionId` ready. You'll find it on the Collection details page. This guide purchases an NFT on
> the `polygon-amoy` testnet.
>
> Make sure you follow the maximum prices for collections set in staging outlined [here](https://docs.crossmint.com/payments/advanced/testing-tips.md#limits-in-staging).

> [tab] Memecoins & Tokens
>
> <Snippet file="enterprise-feature.mdx" />
>
> <Snippet file="memecoins_important_notes.mdx" />
>
> <Snippet file="memecoins_prerequisites.mdx" />
>
> <Snippet file="memecoins_fungible_token_specification.mdx" />

> [!NOTE]
>
> To integrate in production/mainnet, you also need a signed Order Form with Crossmint and KYB. NFT Checkout additionally requires collection verification. See the [production launch guide](https://docs.crossmint.com/payments/advanced/production-launch) for the full sequence.

## Integration Steps

<Snippet file="headless-credit-card-integration-steps-intro.mdx" />

**1. Create an Order**

<Snippet file="headless-create-order-preamble.mdx" />

> [tab] NFTs
>
> ```json theme={null}
> {
>     "payment": {
>         "method": "card"
>     },
>     "lineItems": [
>         {
>             "collectionLocator": "crossmint:<collectionId>", // Use the collectionId from the Prerequisites section
>             "callData": {
>                 "totalPrice": "0.0001"
>             }
>         }
>     ]
> }
> ```
>
> > [accordion] Example Response
> >
> > ```json theme={null}
> > {
> >   "clientSecret": "_removed_",
> >   "order": {
> >     "orderId": "cc40e6af-f8dc-4ac2-8e26-d91a32f271cf",
> >     "phase": "quote",
> >     "locale": "en-US",
> >     "lineItems": [
> >       {
> >         "chain": "polygon-amoy",
> >         "quantity": 1,
> >         "callData": {
> >           "quantity": 1
> >         },
> >         "metadata": {
> >           "name": "Headless Demo",
> >           "description": "NFT Checkout Demo",
> >           "imageUrl": "https://utfs.io/f/cd8545b7-3410-4fcd-988d-cd11951ed53c-g287ok.png"
> >         },
> >         "quote": {
> >           "status": "requires-recipient",
> >           "charges": {
> >             "unit": {
> >               "amount": "0.000169004",
> >               "currency": "eth"
> >             }
> >           },
> >           "totalPrice": {
> >             "amount": "0.000169004",
> >             "currency": "eth"
> >           }
> >         },
> >         "delivery": {
> >           "status": "awaiting-payment"
> >         }
> >       }
> >     ],
> >     "quote": {
> >       "status": "requires-recipient",
> >       "quotedAt": "_DATE_",
> >       "expiresAt": "_DATE_",
> >       "totalPrice": {
> >         "amount": "0.000169004",
> >         "currency": "eth"
> >       }
> >     },
> >     "payment": {
> >       "status": "requires-quote",
> >       "method": "basis-theory",
> >       "preparation": {}
> >     }
> >   }
> > }
> > ```

> [tab] Memecoins & Tokens
>
> > [!NOTE]
> >
> > Memecoins are testable in staging using the xmeme token
> > (`7EivYFyNfgGj8xbUymR7J4LuxUHLKRzpLaERHLvi7Dgu`). All other token purchases will fail in staging.
>
> ```javascript Node.js theme={null}
> const apiKey = "<your-server-api-key>";
> const tokenId = "solana:7EivYFyNfgGj8xbUymR7J4LuxUHLKRzpLaERHLvi7Dgu"; // xmeme token for staging
> const deliveryAddress = "your-solana-wallet-address";
> const receiptEmail = "your-email@example.com";
>
> const options = {
>     method: "POST",
>     headers: {
>         "x-api-key": apiKey,
>         "Content-Type": "application/json",
>     },
>     body: JSON.stringify({
>         lineItems: [
>             {
>                 tokenLocator: tokenId, // Token address in format solana:tokenAddress
>                 executionParameters: {
>                     mode: "exact-in", // Tells Crossmint to operate in buying fungibles mode
>                     amount: "1", // default currency USD
>                     maxSlippageBps: "500", // Optional, or else default autogenerated slippage will be applied
>                 },
>             },
>         ],
>         payment: {
>             method: "card",
>             receiptEmail: receiptEmail,
>         },
>         recipient: {
>             walletAddress: deliveryAddress,
>         },
>     }),
> };
>
> fetch("https://staging.crossmint.com/api/2022-06-09/orders", options)
>     .then((response) => response.json())
>     .then((response) => console.log(JSON.stringify(response, null, 2)))
>     .catch((err) => console.error(err));
> ```
>
> ```json JSON theme={null}
> {
>     "lineItems": [
>         {
>             "tokenLocator": "solana:tokenAddress",
>             "executionParameters": {
>                 "mode": "exact-in",
>                 "amount": "1",
>                 "maxSlippageBps": "500"
>             }
>         }
>     ],
>     "payment": {
>         "method": "card",
>         "receiptEmail": "receiptEmail"
>     },
>     "recipient": {
>         "walletAddress": "deliveryAddress"
>     }
> }
> ```
>
> Note the following parameters in the request body:
>
> * `maxSlippageBps`: Optional, or else default autogenerated slippage will be applied
> * `receiptEmail`: Optional. If the buyer pays with Apple Pay or Google Pay, Crossmint obtains the email automatically. Providing it improves fraud signal quality.
> * `executionParameters.mode`: The execution method for the order. "exact-out" is for NFTs, "exact-in" is for fungible tokens
>
> For more details on `tokenLocator` formatting, see the [item selection page](https://docs.crossmint.com/payments/guides/select-items.md).

<Snippet file="headless-create-order-ending.mdx" />

**2. Update the Order with Recipient**

<Snippet file="headless-update-order-preamble.mdx" />

> [!NOTE]
>
> If you already set `recipient` and `payment.receiptEmail` when creating the order — as in the token example above
> — you can skip this step.

> [!WARNING]
>
> Legally, for card payments, **an email *must* be specified** in order to deliver a receipt to your user, either in
> `recipient.email` or in `payment.receiptEmail`. If one is not specified, the API will not return the fields
> necessary to collect the user's payment.

> [tab] Email recipient
>
> > [!NOTE]
> >
> > Email recipients work for NFT orders only. Token orders need `recipient.walletAddress`.
>
> ```json theme={null}
> {
>     "recipient": {
>         "email": "test@example.com"
>     }
> }
> ```

> [tab] Wallet recipient with receipt email
>
> ```json theme={null}
> {
>     "recipient": {
>         "walletAddress": "0xabcd1234..."
>     },
>     "payment": {
>         "method": "card", // When updating the payment, you must pass the complete object
>         "receiptEmail": "test@example.com"
>     }
> }
> ```

**3. Render the Crossmint Embedded Component**

After creating an order, render the Crossmint Embedded Component to collect payment information. This secure, embeddable UI component lets you accept payment methods, validates input, and handles errors:

```tsx theme={null}
import { CrossmintEmbeddedCheckout, CrossmintProvider } from "@crossmint/client-sdk-react-ui";

export function MyCheckoutPage({ clientSecret, order, receiptEmail }) {
    return (
        <div className="w-full">
            <CrossmintProvider apiKey="<YOUR CLIENT SIDE KEY>">
                <CrossmintEmbeddedCheckout
                    clientSecret={clientSecret}
                    orderId={order.orderId}
                    payment={{
                        crypto: {
                            enabled: false,
                        },
                        fiat: {
                            enabled: true,
                        },
                        defaultMethod: "fiat",
                        receiptEmail: receiptEmail,
                    }}
                    appearance={{
                        rules: {
                            DestinationInput: {
                                display: "hidden",
                            },
                            ReceiptEmailInput: {
                                display: "hidden",
                            },
                        },
                    }}
                />
            </CrossmintProvider>
        </div>
    );
}
```

> [!TIP]
>
> The `CrossmintEmbeddedCheckout` component is highly customizable. You can adjust colors, styling, layout, and
> behavior to match your brand. Learn more in the [appearance guide](https://docs.crossmint.com/payments/guides/appearance.md).

**4. Poll for Status Updates**

<Snippet file="poll-for-status-updates.mdx" />

### Handling Refunded Payments

When polling for order status, you may encounter a situation where `payment.status` is `completed` but the order also contains a `payment.refunded` property. This indicates that the payment was initially successful but has since been refunded.

```json theme={null}
{
    "order": {
        "payment": {
            "status": "completed",
            "refunded": {
                "amount": "1.00",
                "currency": "usd",
                "txId": "0x1234abcd...",
                "chain": "ethereum"
            }
        }
    }
}
```

The `payment.refunded` object includes the following fields:

* `amount`: The amount that was refunded
* `currency`: The currency of the refund
* `txId`: The on-chain transaction ID the refund was sent in
* `chain`: The blockchain where the refund transaction occurred

When you encounter this state, your application should display an appropriate message to the user, provide the `txId` so they can verify the refund on-chain, and offer the option to place a new order.

## Memecoin & Token Specifics

The following applies to fungible token purchases (`tokenLocator` + `executionParameters`), not NFTs.

### Refreshing Orders

For memecoin checkout, the order expiration is 1 minute. The Crossmint Embedded Checkout will automatically refresh the order for you when the time comes. Alternatively, you can either create a new order or use the refresh quote API:

```javascript theme={null}
async refreshOrder(orderId, clientSecret) {
    try {
        const ancestorOrigins =
            typeof window !== "undefined" && window.location?.ancestorOrigins
                ? Array.from(window.location.ancestorOrigins)
                : [];

        const response = await this.callApi(`2022-06-09/orders/${orderId}/refresh`, "POST", {}, {
            authorization: `${clientSecret}`,
            "x-ancestor-origins": JSON.stringify(ancestorOrigins),
        });

        const parsed = await response.json();
        return parsed;
    } catch (error) {
        console.error("Error refreshing quote:", error);
        throw error;
    }
}
```

<Snippet file="memecoins-understanding-the-code.mdx" />

<Snippet file="memecoins_order_lifecycle.mdx" />

<Snippet file="memecoins_faq.mdx" />

## Next Steps

> [card] [Design Your UI](https://docs.crossmint.com/payments/guides/appearance.md)
>
> Learn how to design your headless checkout experience

> [card] [Webhooks](https://docs.crossmint.com/payments/advanced/webhooks.md)
>
> Implement webhook handling for order updates
