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

> Payment acceptance phase of the order lifecycle for pay with crypto

An overview of the process works as follows:

<Steps>
  <Step title="Order Creation or Update">
    Your user selects the chain, token, and wallet they want to pay from via your application and you create or
    update an existing order with this information.
  </Step>

  <Step title="API Response">
    The API response returned from create or update order will include a `serializedTransaction` that your
    application uses to request payment from the user's wallet.
  </Step>

  <Step title="User Confirms Transaction">
    After your application initiates the payment request the user must confirm the transaction.
  </Step>

  <Step title="Poll for Status">
    Your application will poll the GET order status and update the UI as the order progresses to the next phase.
  </Step>
</Steps>

<Note>During the initial `quote` phase of the order the payment status will be `requires-quote`.</Note>

Once the quote phase is completed, the order enters the payment phase.

For most orders the payment phase will begin with the status `awaiting-payment`, which indicates that the order is ready to be paid. It can also begin with `requires-crypto-payer-address` if the payer address is missing.

For the complete, authoritative list of payment statuses and their meanings, see the [Status Codes](/payments/headless/guides/status-codes) page. |

### Setting the Payer Address

The order must know the address that will be sending the crypto payment. This enables Crossmint's payment listeners to associate incoming transactions with the correct order. To update the order with the payer address, call the update API as demonstrated below:

`PATCH` `/api/2022-06-09/orders/<orderId>`

```json theme={null}
{
    "payment": {
        "currency": "eth",
        "method": "base-sepolia",
        "payerAddress": "0x1234abcd…"
    }
}
```

The `payerAddress` is the wallet the user will be sending the payment from. Note that you must send the entire payment object even if the currency and/or method values are not changing.

### Submitting the Payment

When you've fully prepared the order such that the payment status is `awaiting-payment` you'll have everything necessary to request the crypto payment from your user. The details will be returned in the `order.payment.preparation` property.

<Accordion title="Example response">
  ```json theme={null}
  {
    "orderId": "c167db0f-0cb9-4c59-80d3-aface6bcb338",
    "phase": "payment",
    "locale": "en-US",
    "lineItems": [], // removed for brevity
    "quote": // removed for brevity
    "payment": {
      "status": "awaiting-payment",
      "method": "base-sepolia",
      "currency": "eth",
      "preparation": {
        "chain": "base-sepolia",
        "payerAddress": "0x6C3b3225759Cbda68F96378A9F0277B4374f9F06",
        "serializedTransaction": "0x02f9015083014a34238489173700848917387582653d94a105c311fa72b8fb78c992ecbdb8b02ea5bd394d868644e0f88d81b9011e2d2d2d2d2d2d424547494e204d454d4f2d2d2d2d2d2d65794a68624763694f694a49557a49314e694973496e523563434936496b705856434a392e65794a756232356a5a534936496a4e6b5954673159324a6b4c546c6a4e4459744e4459774f4331694d44686a4c5746694e6d557a595746684e4468694d794973496d39795a4756795357526c626e52705a6d6c6c63694936496d4d784e6a646b596a426d4c54426a596a6b744e474d314f5330344d47517a4c57466d59574e6c4e6d4a6a596a4d7a4f434973496d6c68644349364d5463784f446b784d7a63774f48302e75574365534961563642504b6f6935724d7939394c2d4b56303256644d4d343442343934724c4352656f632d2d2d2d2d2d454e44204d454d4f2d2d2d2d2d2dc0"
      }
    }
  }
  ```
</Accordion>

The `order.payment.preparation` property contains details about the chain that Crossmint is expecting the payment to be received on, the payer address, and a `serializedTransaction` that you can use to open a payment request in the user's wallet. See examples of how to parse the response and request transaction confirmation from the user below:

<Tabs>
  <Tab title="EVM">
    ```jsx theme={null}
    import { parseTransaction } from "viem";
    import { useSendTransaction } from "wagmi";

    const { sendTransactionAsync } = useSendTransaction();

    const signAndSendTransaction = async (serializedTransaction) => {
        const txn = parseTransaction(serializedTransaction)

        try {
          const txId = await sendTransactionAsync(txn);
          console.log("Transaction ID:", txId);
        } catch (error) {
          console.error("Error sending transaction:", error);
        }
    };
    ```
  </Tab>

  <Tab title="Solana">
    ```jsx theme={null}
    import bs58 from "bs58";
    import { useConnection, useWallet } from "@solana/wallet-adapter-react";

    const { connection } = useConnection();
    const { sendTransaction } = useWallet();

    const signAndSendTransaction = async (serializedTransaction) => {
        const transaction = Transaction.from(bs58.decode(serializedTransaction));

        try {
           const txId = await sendTransaction(transaction, connection);
           console.log("Transaction ID:", txId);
        } catch (error) {
          console.error("Error sending transaction:", error);
        }
    }
    ```
  </Tab>
</Tabs>

<Warning>
  You should **never** alter the values in the parsed transaction object. Simply parse the transaction object as shown
  in the example above. Changing any of these values may result in Crossmint not being able to validate the payment.
</Warning>

Calling the `signAndSendTransaction` function in the code snippet(s) above will open the user's wallet and enable them to confirm the crypto payment.

### Awaiting Payment Confirmation

<Check>We recommend a polling interval of about 2500ms and never below 500ms.</Check>

<Note>
  You can use client-side or server-side API keys to implement headless checkout. Check the code samples for the type
  of API key you're using in your application.
</Note>

<Tabs>
  <Tab title="Client Side">
    ```tsx theme={null}
    const getOrderPaymentStatus = async () => {
        const apiUrl = "https://staging.crossmint.com/api/2022-06-09";
        try {
            const res = await fetch(`${apiUrl}/orders/${order.orderId}`, {
                method: "GET",
                headers: {
                    "Content-Type": "application/json",
                    "x-api-key": process.env.NEXT_PUBLIC_CROSSMINT_API_KEY,
                    authorization: clientSecret, // saved from response of create order call
                },
            });

            const refreshedOrder = await res.json();

            setOrder(refreshedOrder);

            return refreshedOrder.payment.status;
        } catch (e) {
            console.error(e);
            throw new Error("Failed to fetch order");
        }
    };

    const pollPaymentStatus = async () => {
        const intervalId = setInterval(async () => {
            const status = await getOrderPaymentStatus();
            console.log("payment status: ", status);
            if (status === "completed") {
                clearInterval(intervalId);
            }
        }, 2500);

        // Set a timeout to stop polling after 60 seconds
        setTimeout(() => {
            clearInterval(intervalId);
            console.log("Taking longer than expected...");
        }, 60000);
    };
    ```
  </Tab>

  <Tab title="Server Side">
    <Note>
      The sample code below is from a NextJS application. The `component.tsx` file is simplified to only show the relevant
      logic. The client-side component sends an API request to the application's backend, which then proxies the request
      to Crossmint. This is because the example is using a server-side API key, which requires making requests from a server environment.
    </Note>

    <CodeGroup>
      ```tsx component.tsx (client-side) theme={null}
      const getOrderPaymentStatus = async () => {
          try {
              const res = await fetch(`/orders/${order.orderId}`, {
                  method: "GET",
                  headers: {
                      "Content-Type": "application/json",
                  },
              });

              const refreshedOrder = await res.json();

              setOrder(refreshedOrder);

              return refreshedOrder.payment.status;
          } catch (e) {
              console.error(e);
              throw new Error("Failed to fetch order");
          }
      };

      const pollPaymentStatus = async () => {
          const intervalId = setInterval(async () => {
              try {
                  const status = await getOrderPaymentStatus();
                  console.log("payment status: ", status);
                  if (status === "completed") {
                      clearInterval(intervalId);
                  }
              } catch (e) {
                  clearInterval(intervalId);
                  console.error("Error polling payment status: ", e);
              }
          }, 2500);

          // Set a timeout to stop polling after 60 seconds
          setTimeout(() => {
              clearInterval(intervalId);
              console.log("Taking longer than expected...");
          }, 60000);
      };
      ```

      ```typescript route.ts (server-side) theme={null}
      import { callCrossmintAPI } from "@/app/utils/crossmint";
      import { NextRequest, NextResponse } from "next/server";

      export async function GET(req: NextRequest, { params }: { params: { orderId: string } }) {
          if (params.orderId) {
              const order = await callCrossmintAPI(`/orders/${params.orderId}`, {
                  method: "GET",
              });

              return NextResponse.json(order, { status: 200 });
          } else {
              return NextResponse.json({ error: true, message: "Missing orderId" }, { status: 400 });
          }
      }
      ```

      ```typescript crossmint.ts theme={null}
      const crossmintBaseUrl = process.env.CROSSMINT_API_URL;

      const crossmintAPIHeaders = {
          accept: "application/json",
          "content-type": "application/json",
          "x-api-key": process.env.CROSSMINT_API_KEY!,
      };

      const callCrossmintAPI = async (endpoint: string, options: { method: string; body?: any; params?: any }) => {
          const url = `${crossmintBaseUrl}/${endpoint}`;
          const { body, method } = options;

          const response = await fetch(url, {
              body: body ? JSON.stringify(body) : null,
              method,
              headers: crossmintAPIHeaders,
          });
          const json = await response.json();
          return json;
      };

      export { callCrossmintAPI };
      ```
    </CodeGroup>
  </Tab>
</Tabs>

Once the payment is confirmed, you can move on to the delivery phase of the order lifecycle.

### 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.23",
                "currency": "eth"
            }
        }
    }
}
```

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

* `amount`: The amount that was refunded
* `currency`: The currency of the refund

When you encounter this state, your application should:

1. Display an appropriate message to the user indicating that their payment was refunded
2. Prevent any further actions related to the order (such as delivery expectations)
3. Provide options for the user to place a new order if desired

This state typically occurs when there was an issue with processing the order after payment was received, such as insufficient liquidity for memecoin purchases or compliance issues.
