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

> Buy or sell any tokenized asset with USDC, in an API call

## Introduction

This guide will show you how to quickly buy or sell any tokenized asset (NFT) with USDC, using Crossmint's headless APIs.

## Prerequisites

<Snippet file="headless-checkout-prereqs.mdx" />

## External prerequisites

<Steps>
  <Step icon="circle-dot" iconType="duotone" title="Wallet">
    Crypto wallet supporting USDC - [Metamask](https://metamask.io/), [Phantom](https://phantom.app/), [Coinbase Wallet](https://wallet.coinbase.com), etc.
  </Step>

  <Step icon="circle-dot" iconType="duotone" title="Testnet Balance">
    A small balance of **USDC** testnet currency in your wallet on the **Base-sepolia** network.

    Get testnet USDC here:

    * [Crossmint USDC Faucet (Base-sepolia)](https://usdc-faucet.vercel.app/)

    <Warning>
      The above faucet provides both USDC and USDXM. This quickstart uses USDC by default, but you can also use USDXM (see contract address below).
    </Warning>

    <Note>
      USDXM is a test token that represents USDC. It has the same behavior as USDC. In production, you'll use real USDC instead.
    </Note>

    **Adding USDC to MetaMask:**

    * Import the token to MetaMask:
      1. Open MetaMask and click "Import tokens"
      2. For USDC: Use the official USDC contract address from Circle `0x036CbD53842c5426634e7929541eC2318f3dCF7e`
      3. For USDXM: Use the USDXM contract address `0x14196F08a4Fa0B66B7331bC40dd6bCd8A1dEeA9F`
      4. Click Import
      5. Refresh your wallet
  </Step>
</Steps>

## Create an order and pay with USDC

<Steps>
  <Step title="Setup your environment">
    Clone the quickstart repo:

    ```bash theme={null}
    git clone https://github.com/Crossmint/headless-pay-usdc.git
    ```

    Navigate to the project directory:

    ```bash theme={null}
    cd headless-pay-usdc
    ```

    Install the dependencies:

    ```bash theme={null}
    pnpm i
    ```
  </Step>

  <Step title="Set keys in .env">
    Set the following keys in the `.env` file:

    ```bash theme={null}
    CROSSMINT_API_KEY="<your-api-key>"
    COLLECTION_ID="<your-collection-id>"
    PAYER_ADDRESS="<your-payer-address>"
    EMAIL_ADDRESS="<your-email-address>"
    ```

    * `CROSSMINT_API_KEY`, `COLLECTION_ID` are found from the [Developer Console](https://staging.crossmint.com/console/). See [Prerequisites](#prerequisites)
    * `PAYER_ADDRESS` is your wallet address that contains USDC.
    * `EMAIL_ADDRESS` is where you'll receive your NFT in a new Crossmint wallet that you can access later.
  </Step>

  <Step title="Create order with USDC payment">
    Run the application:

    ```bash theme={null}
    pnpm dev
    ```

    This will:

    1. Create an order that is waiting for a **USDC** payment on the **Base-sepolia** network
    2. Return the **serializedTransaction**, which will be used in the next step
    3. Poll the status of the order until it is complete

    <Frame type="simple">
      <img src="https://mintcdn.com/crossmint/QK6rWfcUCMmvIQPT/images/payments/headless/serialized-transaction.png?fit=max&auto=format&n=QK6rWfcUCMmvIQPT&q=85&s=c8afdee2625052f0929f1717ded7169d" alt="Serialized transaction" width="2168" height="286" data-path="images/payments/headless/serialized-transaction.png" />
    </Frame>
  </Step>

  <Step title="Receive Payment">
    1. Copy the `serializedTransaction` returned in the previous step and paste it below
    2. Connect to your USDC wallet that was specified in the `.env` file
    3. Send the transaction

    <Frame type="simple">
      <iframe src="https://headless-sendpayment.vercel.app" width="730px" height="500px" />
    </Frame>
  </Step>

  <Step title="Status of order">
    The code will poll for the status of the order until it is marked as complete.
    You should see it changing from "payment" to "delivery" and finally to "completed".

    <Info>
      You will also see the final order details, including the transaction hash, in your terminal.
    </Info>

    <Frame type="simple">
      <img src="https://mintcdn.com/crossmint/QK6rWfcUCMmvIQPT/images/payments/headless/terminal-order-status.png?fit=max&auto=format&n=QK6rWfcUCMmvIQPT&q=85&s=5c85bd2f38a4539a796449297239cd36" alt="Order status" width="509" height="299" data-path="images/payments/headless/terminal-order-status.png" />
    </Frame>
  </Step>
</Steps>

## Access your NFT

Once the order is complete, you will receive an email with a link to the purchased item, which can be viewed in the Crossmint website.

<Info>
  You can also access your NFT by logging in to your Crossmint wallet at
  [crossmint.com](https://staging.crossmint.com/user/collection) with the email address you specified in the `.env`
  file.
</Info>

## Understanding the code

### Creating an order

The order creation process involves sending a POST request to Crossmint's API with the necessary payment and recipient details. Let's break down the key components:

```ts src/createOrder.ts theme={null}
import { API_KEY, API_URL, COLLECTION_ID, EMAIL_ADDRESS, PAYER_ADDRESS } from "./utils";


export async function createOrder() {
    const payload = {
        recipient: {
            email: EMAIL_ADDRESS, // Replace with actual recipient wallet address
        },
        payment: {
            method: "base-sepolia",
            currency: "usdc",
            payerAddress: PAYER_ADDRESS,
        },
        lineItems: [
            {
                collectionLocator: `crossmint:${COLLECTION_ID}`
            },
        ],
    };
    ...
}
```

#### Key parameters explained

* **recipient**: Specifies where to deliver the tokenized asset

  * `email`: The email address where the tokenized asset will be delivered in a Crossmint wallet.
    Instead of an email, a `walletAddress` field can be used to deliver the asset to a specific wallet address.

* **payment**: Defines how the payment will be made

  * `method`: The blockchain network (`base-sepolia` for testnet)
  * `currency`: The payment currency (`usdc`)
  * `payerAddress`: The wallet address that will send the USDC payment

* **lineItems**: Specifies what is being purchased
  * `collectionLocator`: Identifies the collection

#### API request

```ts src/createOrder.ts theme={null}
    const response = await fetch(`${API_URL}/api/2022-06-09/orders`, {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "x-api-key": API_KEY,
        },
        body: JSON.stringify(payload),
    });
```

The API request:

* Sends a POST request to Crossmint's order endpoint
* Includes your API key for authentication
* Sends the order data as JSON in the request body

#### Response handling

```ts src/createOrder.ts theme={null}
    if (!response.ok) {
        throw new Error(`Failed to create order: ${response.status} ${response.statusText}`);
    }
    const jsonResponse = await response.json();
    return {
        "clientSecret": jsonResponse["clientSecret"], // Used for order authentication
        "order": jsonResponse["order"] // Contains the order details
    }
```

The response includes:

* `clientSecret`: A unique token used for authenticating subsequent requests for this order
* `order`: The order details including the order ID and status

For more details on creating orders via the headless API, see the [Create Order API Reference](/api-reference/headless/create-order).

### Polling an order

The order status polling process involves periodically checking the order's status until it's completed. Let's examine how this works:

```ts src/getOrder.ts theme={null}
import { API_KEY, API_URL } from "./utils";

export async function getOrder(orderId: string) {
    const response = await fetch(`${API_URL}/api/2022-06-09/orders/${orderId}`, {
        method: "GET",
        headers: {
            "Content-Type": "application/json",
            "x-api-key": API_KEY, // API authentication
        }
    });
    if (!response.ok) {
        throw new Error(`Failed to create order: ${response.status} ${response.statusText}`);
    }
    return response.json();
}
```

#### Get order function explained

* Takes `orderId` as parameter
* Makes a GET request to fetch the current state of the order
* Uses API key for authentication
* Returns the order details as JSON

```ts src/getOrder.ts theme={null}
export async function pollOrder(orderId: string) {
    while (true) {
        const order = await getOrder(orderId);
        console.log(`Current order status: \x1b[33m${order.phase}\x1b[0m`);
        if (order.phase === "completed") {
            return order;
        }
        await new Promise(resolve => setTimeout(resolve, 3000));
    }
}
```

#### Poll order function explained

* Continuously checks the order status every 3 seconds.
* Prints the current phase of the order
* Possible order phases include:
  * `payment`: Waiting for or processing payment
  * `delivery`: NFT is being delivered
  * `completed`: Order is successfully completed
* Returns the final order details when completed

The 3-second polling interval helps prevent rate limiting while still providing timely updates. Adjust this value based on your needs.

For more details on polling for order status, see the [Get Order API Reference](/api-reference/headless/get-order).

<Warning>
  Always implement proper error handling, retry mechanisms, and asynchronous polling in production environments to
  handle network issues or API interruptions.
</Warning>
