Skip to main content
Enterprise feature. Contact us for access.

Introduction

This guide will show you how to accept credit card payments using Crossmint’s Headless Checkout API for memecoin sales. You’ll learn how to:
  • Set up credit card payments for Solana memecoin purchases in JavaScript
  • Implement a checkout UI
  • Track order status and delivery
For a faster, embedded checkout solution with minimal setup time, see our embedded memecoin quickstart.

Important Notes

Compliance Checks

Crossmint runs compliance checks on all tokens to ensure they do not qualify as securities or currencies under applicable regulations. Transactions for tokens that are determined to be too similar to securities or currencies will fail.

Supported Tokens

Currently, memecoin checkout only supports Solana network. You can check which tokens are supported by using the fungibleCheckoutAvailable endpoint. A more in depth guide on token support is here.

Delivery to External Wallets Only

Memecoin checkout only delivers memecoins to EOAs (Externally Owned Accounts), not Crossmint supported delivery solutions, such as on-the-fly wallet creation (both Crossmint custodial wallets and smart wallet), delivery to Twitter handle, etc.

Merchant of Record

Crossmint remains the merchant of record for all transactions. Your buyers will still receive delivery receipts and transaction confirmations from Crossmint.

Prerequisites

1

Solana Wallet

Have a Solana wallet address ready to receive purchased memecoins
2

Get API Keys

Get your API keys from the Crossmint Console
Navigate to the "Integrate" section on the left navigation bar, and ensure you're on the "API Keys" tab.Within the Client-side keys section, click the "Create new key" button in the top right.On the authorized origins section, enter http://localhost:3000 and click "Add origin".Finally, create your key and save it for subsequent steps.

Fungible Token Specification

To define which fungible token you'd like to purchase, you'll need to specify the tokenLocator in the format:
  • For Solana: solana:${tokenMintHash}
    • Example: solana:6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN
    • tokenMintHash: The token mint hash (commonly known as contract address, CA, or mint hash)
  • For EVM chains (Ethereum, Polygon, Arbitrum, Base, etc.): <chain>:<contractAddress>
    • Example: ethereum:0x1234567890123456789012345678901234567890
    • chain: The chain name (ethereum, polygon, arbitrum, base, etc.)
    • contractAddress: The contract address corresponding to the ERC20 token contract (40 hexadecimal characters, beginning with 0x)

Headless Memecoin Checkout

The headless checkout API allows complete control over your checkout experience, including:
  • Custom UI components and styling
  • Custom payment flow sequences
  • Integrated analytics and tracking
  • Custom error handling and retry logic
  • Branded confirmation pages

Create an Order

The first step in the headless checkout process is to create an order. An order is an object datastructure that represents an intent to purchase in Crossmint’s systems. This guide will create a basic order, and then update it with required info step-by-step.
You can also create the entire order in one API call if the necessary information is available at the time of order creation. This can be used for custom “one-click-checkout” experiences, should you wish to make them.
Endpoint: POST https://www.crossmint.com/api/2022-06-09/orders Refer to the complete create order API reference here.
Memecoins are now testable in staging using the xmeme token (7EivYFyNfgGj8xbUymR7J4LuxUHLKRzpLaERHLvi7Dgu). All other token purchases will fail in staging. For production launch with other tokens, contact our sales team.
Use the JavaScript code snippet below to create a starting point for your order. Alternatively, use the API playground to explore and create your own order.
const apiKey = "your-server-api-key"; // CHANGE THIS TO YOUR SERVER API KEY
const tokenId = "solana:7EivYFyNfgGj8xbUymR7J4LuxUHLKRzpLaERHLvi7Dgu"; // xmeme token for staging
const deliveryAddress = "your-solana-wallet-address"; // CHANGE THIS TO YOUR RECEIVING SOLANA WALLET ADDRESS
const receiptEmail = "[email protected]"; // CHANGE THIS TO YOUR EMAIL

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 (e.g., solana:7EivYFyNfgGj8xbUymR7J4LuxUHLKRzpLaERHLvi7Dgu for xmeme token)
                executionParameters: {
                    mode: "exact-in", // The execution method for the order. It 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));
{
  "clientSecret": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmRlcklkZW50aWZpZXIiOiJlZDM0YTU3OS03ZmJjLTQ1MDktYjhkOC05ZTYxOTU0Y2Q1NTUiLCJpYXQiOjE3Mzk0MDI3NjEsImV4cCI6MTczOTQ4OTE2MX0.8AU0Y31lJhnQD2-vAXEZp3ZeMSyh_Wdm9An02Z5AW0M",
  "order": {
    "orderId": "ed34a579-7fbc-4509-b8d8-9e61954cd555",
    "phase": "payment",
    "locale": "en-US",
    "lineItems": [
      {
        "chain": "solana",
        "metadata": {
          "name": "xmeme",
          "description": "Token xmeme from the contract: 7EivYFyNfgGj8xbUymR7J4LuxUHLKRzpLaERHLvi7Dgu",
          "imageUrl": "https://arweave.net/VQrPjACwnQRmxdKBTqNwPiyo65x7LAT773t8Kd7YBzw"
        },
        "quote": {
          "status": "valid",
          "charges": {
            "unit": {
              "amount": "35.73",
              "currency": "usd"
            }
          },
          "totalPrice": {
            "amount": "1",
            "currency": "usd"
          },
          "quantityRange": {
            "lowerBound": "0.0265905",
            "upperBound": "0.0293895"
          }
        },
        "delivery": {
          "status": "awaiting-payment",
          "recipient": {
            "locator": "solana:BuWmGweapdysxU5VuUdi1RGoc4ibDG7TNirWjRtqF995",
            "walletAddress": "your-solana-wallet-address"
          }
        },
        "executionMode": "exact-in",
        "maxSlippageBps": "500",
        "executionParams": {
          "mintHash": "7EivYFyNfgGj8xbUymR7J4LuxUHLKRzpLaERHLvi7Dgu",
          "mode": "exact-in",
          "amount": "1",
          "maxSlippageBps": "500"
        }
      }
    ],
    "quote": {
      "status": "valid",
      "quotedAt": "2025-02-12T23:26:00.397Z",
      "expiresAt": "2025-02-12T23:26:30.397Z",
      "totalPrice": {
        "amount": "1",
        "currency": "usd"
      }
    },
    "payment": {
      "status": "awaiting-payment",
      "method": "basis-theory",
      "currency": "usd",
      "preparation": {},
      "receiptEmail": "[email protected]"
    }
  }
}
Note the following parameters in the request body:
  • maxSlippageBps: Optional, or else default autogenerated slippage will be applied
  • receiptEmail: Required for credit card payments to deliver receipt
  • executionParameters.mode: The execution method for the order. “exact-out” is for NFTs, “exact-in” is for fungible tokens

Render the Crossmint Embedded Component

After creating an order, you’ll need to render the Crossmint Embedded Component to collect payment information. This secure, embeddable UI component lets you accept payment methods, validates input, and handles errors:
import { CrossmintEmbeddedCheckout, CrossmintProvider } from "@crossmint/client-sdk-react-ui";

export function MyCheckoutPage({ clientSecret, order, recipientWalletAddress, receiptEmail }) {
  return (
    <div className="w-full">
      <CrossmintProvider apiKey="<YOUR CLIENT SIDE KEY>">
        <CrossmintEmbeddedCheckout 
          recipient={{ walletAddress: recipientWalletAddress}}
          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>
  );
}
The CrossmintEmbeddedCheckout component is highly customizable. You can adjust colors, styling, layout, and behavior to match your brand. Learn more in our UI customization guide.

Poll for Status Updates

After making the payment, you’ll need to poll the Get Order API to check on the delivery status and present this information to your user. Endpoint: GET https://staging.crossmint.com/api/2022-06-09/orders/<orderId> Refer to the complete get order API reference here. Example Response:
{
    "id": "order_xyz",
    "status": "completed",
    "phases": {
        "quote": { "status": "completed" },
        "payment": { "status": "completed" },
        "delivery": { "status": "completed", "details": "Memecoins delivered to specified wallet" }
    }
}

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.
{
    "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:
  1. Display an appropriate message to the user indicating that their payment was refunded
  2. Provide the transaction ID (txId) so users can verify the refund on-chain
  3. Prevent any further actions related to the order (such as delivery expectations)
  4. 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. 🎉 Congratulations! You’ve successfully set up your headless memecoin checkout. Check out the Next Steps section below to learn how to customize your integration.

Understanding the Code

Quote Expiration

Price quotes are valid for 30 seconds. After expiration, you'll need to request a new quote from the embedded checkout component

Slippage

Crossmint applies the slippage specified in your executionParameters.maxSlippageBps. If not provided, Crossmint will use the default slippage configuration (typically 500 BPS or 5%) from Crossmint's provider

Next Steps

Order Lifecycle

The order goes through several phases: Learn more about order phases in the headless checkout guide or embedded checkout guide A summary of the phases is below:
  1. Quote Phase (30-second validity)
    • Initial price quote generated
    • Requires recipient information to proceed
  2. Payment Phase
    • Collect payment information
    • Handle payment completion and errors
  3. Delivery Phase
    • Purchase memecoin with USDC
    • Apply specified slippage tolerance
    • Send transfer transaction to recipient wallet
  4. Completion
    • Order marked as completed
    • Receipt email sent to recipient
    • Memecoins have been delivered to the recipient wallet

Refreshing Orders

For memecoin checkout, the order expiration is 30 seconds. 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:
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;
  }
}

FAQ

Yes, you can use our embedded checkout or hosted checkout options. Contact our sales team to learn more about these solutions and find the best fit for your needs.
Crossmint KYC is currently disabled for memecoin purchases. This means that if your buyers typically have high risk profiles, their transaction may be declined. To increase conversion, please read the improving conversion guide.
When a user attempts a purchase, Crossmint puts a hold on their credit card. Only if the blockchain transaction succeeds, funds are captured. If the blockchain transaction fails, funds are released and the user is never charged.
The default transaction limit is 1,000 USD per user. A single wallet address is subject to a daily limit of 1,000 USD per user, the same as for NFT purchases. If you need a higher limit, speak to your Crossmint representative.
Yes, there is a volume limit of 1,000,000 USD worth of credit card purchases per day. This limit resets daily at 11:59 PM EST.
The order creation request includes several important parameters:Payment Object
  • method: Set to checkoutcom-flow for Checkout.com credit card payments
  • currency: Set to usd for US Dollar payments
  • receiptEmail: Required for credit card payments to deliver receipt
Line Items Object
  • tokenLocator: Specifies the memecoin token address in the format solana:tokenAddress
  • executionParameters:
    • mode: Set to "exact-in" for memecoin purchases (specifies exact USD amount to spend)
    • amount: Amount to purchase in USD
    • maxSlippageBps: Set to "500" for 5% slippage tolerance. If not provided, the default slippage will be applied from the available liquidity provider.
Response Parameters The order response includes Checkout.com-specific parameters:
  • checkoutcomPaymentSession: Contains the payment session information from Checkout.com
    • id: The payment session ID
    • payment_session_secret: The secret used to authenticate with Checkout.com
    • payment_session_token: The token used to initialize the Checkout.com Flow component
  • checkoutcomPublicKey: The public key used to initialize the Checkout.com Flow component