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

# Events

> Listen to embedded checkout events

You can subscribe to both payment and minting / asset delivery events.

<Accordion title="See a live demo">
  Fill out the checkout below and observe the events on the right side. Enter a valid email address to receive the purchase receipt.

  <Check>Use the test card number `4242 4242 4242 4242` to trigger a successful payment.</Check>

  <iframe src="https://embedded-events-demo.vercel.app/" width="760px" height="500px" />
</Accordion>

## Event Types

<Tabs>
  <Tab title="Payment Events">
    Payment events notify of price changes and events happening while capturing the user's payment (e.g. successful payments, rejected cards).

    ### Adding Payment Events

    Subscribe by adding an `onEvent` handler to the `CrossmintPaymentElement`.

    <Accordion title="See example">
      The following example  will log **all** events to the browser console. You can jump ahead to see some examples for capturing and reacting to specific events further below.

      <CodeGroup>
        ```javascript react theme={null}
        import { CrossmintPaymentElement } from "@crossmint/client-sdk-react-ui";

        const Crossmint: React.FC = () => {
          return (
            <CrossmintPaymentElement
              projectId={projectId}
              collectionId={collectionId}
              environment={environment}
              emailInputOptions={{
                show: true,
              }}
              mintConfig={{
                totalPrice: "0.001",
                quantity: "1",
              }}
              onEvent={(event) => {
                console.log(event.type, event);
              }}
            />
          );
        };

        export default Crossmint;
        ```

        ```javascript vue theme={null}
        <script setup lang="ts">
        import type { CrossmintEvent } from "@crossmint/client-sdk-base";
        import { CrossmintPaymentElement } from "@crossmint/client-sdk-vue-ui";
        import "@crossmint/client-sdk-vue-ui/dist/index.css";

        const emailInputOptions = {
          show: true
        };

        function onEvent(event: CrossmintEvent) {
          console.log(event.type, event);
        }
        </script>

        <template>
          <CrossmintPaymentElement
            project-id="_YOUR_PROJECT_ID_"
            collection-id="_YOUR_COLLECTION_ID_"
            environment="staging"
            :emailInputOptions="emailInputOptions"
            :mint-config="{
              totalPrice: String(0.001),
              quantity: String(1),
            }"
            @event="onEvent"
          />
        </template>
        ```

        ```javascript vanilla js theme={null}
        <script src="https://unpkg.com/@crossmint/client-sdk-vanilla-ui@latest/dist/index.global.js"></script>

        <crossmint-payment-element
          projectId="_YOUR_PROJECT_ID_"
          collectionId="_YOUR_COLLECTION_ID_"
          environment="staging"
          emailInputOptions='{
            "show": true
          }'
          mintConfig='{
            "totalPrice": "0.0001",
            "quantity": "1"
          }'
          onevent="return function onEvent(event) {
            console.log(event.type, event);
          }"
        />
        ```
      </CodeGroup>
    </Accordion>

    ### Types of Payment Events

    <Accordion title="Quotes">
      <ParamField body="quote:status.changed">
        Triggered when the price is calculated or when it changes.

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "quote:status.changed",
            "payload": {
              "totalPrice": {
                "amount": "0.50",
                "currency": "usd"
              },
              "lineItems": [
                {
                  "metadata": {
                    "title": "Collection Name (set in dev console)",
                    "description": "Collection Description (set in dev console)",
                    "imageUrl": "https://uploadthing.com/f/your_collection_image.png"
                  },
                  "price": {
                    "amount": "0.50",
                    "currency": "usd"
                  },
                  "quantity": 1
                }
              ]
            }
          }
          ```
        </Accordion>
      </ParamField>

      <ParamField body="quote:status.invalidated">
        Triggered when a new quote is retrieved and invalidates the previous one.

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "quote:status.invalidated",
            "payload": {}
          }
          ```
        </Accordion>
      </ParamField>
    </Accordion>

    <Accordion title="Payments">
      <ParamField body="payment:preparation.succeeded">
        Triggered when checkout is ready for payment.

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "payment:preparation.succeeded",
            "payload": {}
          }
          ```
        </Accordion>
      </ParamField>

      <ParamField body="payment:preparation.failed">
        Triggered when checkout preparation fails.

        <Accordion title="How to solve">
          The most common cause is a missing email address.
          You can render an email input field to the `CrossmintPaymentElement` by setting the `emailInputOptions` prop to `{ show: true }`. If you collect email elsewhere in your application you can set `recipient.email` programmatically.

          <CodeGroup>
            ```javascript Render Input theme={null}
              <CrossmintPaymentElement
                // removed for brevity
                emailInputOptions={{
                  show: true,
                }}
                ...
              />
            ```

            ```javascript Set Email Programmatically theme={null}
              <CrossmintPaymentElement
                // removed for brevity
                recipient={{
                  email: {email},
                }}
              ...
            />
            ```
          </CodeGroup>
        </Accordion>

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "payment:preparation.failed",
            "payload": {}
          }
          ```
        </Accordion>
      </ParamField>

      <ParamField body="payment:process.started">
        Triggered when checkout is ready for payment.

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "payment:process.started",
            "payload": {}
          }
          ```
        </Accordion>
      </ParamField>

      <ParamField body="payment:process.succeeded">
        Triggered when payment has been successfully authorized.

        (Payment capture occurs after `transaction:fulfillment.succeeded`)

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "payment:process.succeeded",
            "payload": {
              "orderIdentifier": "7723139d-fba3-474d-8e52-0ac7512d5c7b"
            }
          }
          ```
        </Accordion>

        <br />

        <Check>The `orderIdentifier` returned in the response is used to subscribe to minting events.</Check>
      </ParamField>

      <ParamField body="payment:process.rejected">
        Triggered if a user's card has been rejected.

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "payment:process.rejected",
            "payload": {
              "error": {
                "code": "payments:payment-rejected.generic-decline",
                "message": "The card was declined for an unknown reason."
              },
              "orderIdentifier": "3b8860e5-837b-44c5-99be-17f3f19238f6",
              "paymentMethodType": "credit-card"
            }
          }
          ```
        </Accordion>

        <br />

        <Note>You can trigger this event using the high risk test card number: `4000 0000 0000 4954`</Note>
      </ParamField>

      <ParamField body="payment:process.cancelled">
        Triggered if a user cancelled the payment or closed the checkout.
      </ParamField>
    </Accordion>
  </Tab>

  <Tab title="Minting Events">
    Minting events are triggered only after a payment has been successful captured. They notify of the status of the NFT mint and delivery (e.g. beginning the minting process, delivering the token to the user).

    ### Adding Minting events

    Minting events are not sent to the `onEvent` handler of the `CrossmintPaymentElement`. Instead, you must set them up using the code below

    <Accordion title="How to subscribe to minting events">
      You can subscribe by passing the `orderIdentifier` returned in the `payment:process.succeedded` event to the `Minting` component below.

      <CodeGroup>
        ```javascript Crossmint.tsx theme={null}
        "use client";

        import React, { useState } from 'react';
        import { CrossmintPaymentElement } from "@crossmint/client-sdk-react-ui";
        import Minting from './Minting';

        const Crossmint: React.FC = () => {
          const [orderIdentifier, setOrderIdentifier] = useState<string | null>(null);

          const projectId = process.env.NEXT_PUBLIC_CROSSMINT_PROJECT_ID as string;
          const collectionId = process.env.NEXT_PUBLIC_CROSSMINT_COLLECTION_ID as string;
          const environment = process.env.NEXT_PUBLIC_CROSSMINT_ENVIRONMENT as string;

          return (
            <>
              {orderIdentifier === null ? (
                <CrossmintPaymentElement
                  projectId={projectId}
                  collectionId={collectionId}
                  environment={environment}
                  emailInputOptions={{
                    show: true,
                  }}
                  mintConfig={{
                    totalPrice: "0.001",
                    quantity: "1"
                  }}
                  onEvent={(event) => {
                    switch (event.type) {
                      case "payment:process.succeeded":
                        console.log(event);
                        setOrderIdentifier(event.payload.orderIdentifier);
                        break;
                      default:
                        console.log(event);
                        break;
                    }
                  }}
                />
              ) : (
                <Minting orderIdentifier={orderIdentifier} />
              )}
            </>
          );
        }

        export default Crossmint;
        ```

        ```javascript Minting.tsx theme={null}
        import React from "react";
        import { useCrossmintEvents } from "@crossmint/client-sdk-react-ui";

        interface MintingProps {
          orderIdentifier: string;
        }

        const Minting: React.FC<MintingProps> = ({ orderIdentifier }) => {
          const [status, setStatus] = React.useState < string > "pending"; // ["pending", "success", "failure"
          const [result, setResult] = React.useState < any > null;
          const { listenToMintingEvents } = useCrossmintEvents({
            environment: "staging",
          });

          if (status === "pending") {
            listenToMintingEvents({ orderIdentifier }, (event) => {
              switch (event.type) {
                case "transaction:fulfillment.succeeded":
                  setStatus("success");
                  setResult(event.payload);
                  break;
                case "transaction:fulfillment.failed":
                  setStatus("failure");
                  break;
                default:
                  break;
              }
              console.log(event.type, ":", event);
            });
          }

          return (
            <>
              {status === "pending" && (
                <>
                  <h3>Minting your NFT...</h3>
                  <div className="loading-wrap">
                    <div className="loading"></div>
                  </div>
                  This may take up to a few minutes
                </>
              )}
              {status === "success" && (
                <>
                  <h3>NFT Minted Successfully!</h3>
                  <a
                    target="_blank"
                    className="xmint-button"
                    href={`https://staging.crossmint.com/user/collection/poly:${result?.contractAddress}:${result?.tokenIds[0]}`}
                  >
                    View in Crossmint
                  </a>
                </>
              )}
              {status === "failure" && (
                <>
                  <h3>Failed to Mint NFT</h3>
                  <p>
                    Something went wrong. You will be refunded if the mint cannot be
                    fulfilled successfully.
                  </p>
                </>
              )}
            </>
          );
        };

        export default Minting;
        ```

        ```css globals.css theme={null}
        .loading-wrap {
          text-align: center;
          height: 70px;
          padding: 10px;
        }
        .loading {
          display: inline-block;
          width: 50px;
          height: 50px;
          border: 3px solid rgba(32, 32, 32, 0.3);
          border-radius: 50%;
          border-top-color: #fff;
          animation: spin 1s ease-in-out infinite;
          -webkit-animation: spin 1s ease-in-out infinite;
        }
        @keyframes spin {
          to {
            -webkit-transform: rotate(360deg);
          }
        }
        @-webkit-keyframes spin {
          to {
            -webkit-transform: rotate(360deg);
          }
        }
        .xmint-button {
          display: block;
          background: #81feab;
          color: #000;
          border-radius: 5px;
          padding: 10px;
          margin: 5px;
        }
        ```
      </CodeGroup>
    </Accordion>

    ### Types of Minting Events

    <Accordion title="Orders">
      <ParamField body="order:process.started">
        Triggered when payment has been successfully authorized and the minting process has started.

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "order:process.started",
            "payload": {}
          }
          ```
        </Accordion>
      </ParamField>

      <ParamField body="order:process.finished">
        Triggered when all transactions have succeeded.

        This event fires **after** the `transaction:fulfillment.succeeded` event.

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "order:process.finished",
            "payload": {
              "successfulTransactionIdentifiers": [
                "601b06a9-e4af-423d-8db0-89eb7a457772"
              ],
              "failedTransactionIdentifiers": [],
              "totalPrice": {
                "amount": "0.50",
                "currency": "usd"
              },
              "verification": {
                "required": false
              },
              "paymentMethodType": "credit-card"
            }
          }
          ```
        </Accordion>
      </ParamField>
    </Accordion>

    <Accordion title="Transactions">
      <ParamField body="transaction:fulfillment.succeeded">
        Triggered when an NFT has been delivered successfully.

        <Warning>This event is returned after the blockchain transaction has been confirmed. It
        will **not** return immeditately after sending to RPC. This ensures the `txId` in the
        response will be valid.</Warning>

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "transaction:fulfillment.succeeded",
            "payload": {
              "transactionIdentifier": "601b06a9-e4af-423d-8db0-89eb7a457772",
              "txId": "0x2e69f11dae7869b92e3d5eaf4cadd50c48b5c6803d1232815f979d744521ad4c",
              "contractAddress": "0xE04Cf294985282Ddc088E6433c064cfB85eD9EdA",
              "tokenIds": [
                "3"
              ],
              "price": {
                "amount": "0.50",
                "currency": "usd"
              }
            }
          }
          ```
        </Accordion>
      </ParamField>

      <ParamField body="transaction:fulfillment.failed">
        Triggered when minting the NFT fails.

        <Note>There is not a reliable way for you to trigger this event in testing. <br /><br />
        One scenario when this may fire is if the last NFT is sold between the time
        payment is sent and Crossmint attempts to make the purchase.</Note>

        <Accordion title="Example response">
          ```json theme={null}
          {
            "type": "transaction:fulfillment.failed",
            "payload": {}
          }
          ```
        </Accordion>
      </ParamField>
    </Accordion>

    <Accordion title="Errors">
      <ParamField body="payments:mint-config.invalid">
        Error parsing parameter `mintConfig`.

        <Accordion title="How to solve">
          The value of the `mintConfig` must be an object type. Ensure you are passing in a valid object.
        </Accordion>
      </ParamField>

      <ParamField body="payments:payment-method.invalid">
        The param `paymentMethod` must be a string

        <Accordion title="How to solve">
          `paymentMethod` only accepts a string value. Ensure that you are passing in a string containing one of these possible values: "fiat", "ETH, or "SOL".
        </Accordion>
      </ParamField>

      <ParamField body="payments:email.invalid">
        The email value passed into the `recipient.email` property is invalid.

        <Accordion title="How to solve">
          Ensure that a valid email address is being passed.
        </Accordion>
      </ParamField>

      <ParamField body="payments:client-id.invalid">
        The provided `collectionId` does not exist.

        <Accordion title="How to solve">
          Ensure that you are using the correct `collectionId`. Common causes for this error include:

          * using the wrong [environment](/introduction/platform/staging-vs-production)<br />
            e.g. `environment="staging"` with a production `collectionId` or vice versa
          * using the `projectId` instead of the `collectionId`
        </Accordion>
      </ParamField>

      <ParamField body="payments:minting-contract.missing">
        The collection associated with the provided `collectionId` does not have a minting contract registered.

        <Accordion title="How to solve">
          Register a smart contract in the developer console.
        </Accordion>
      </ParamField>

      {/*

                <ParamField body="payments:collection.disabled">
                Payments are disabled for this collection.

                  <Accordion title="How to solve">
                    Ensure that payments are enabled in the developer console.
                  </Accordion>
                </ParamField>

                <ParamField body="payments:collection.unavailable">
                  Buying with Crossmint is currently disabled for this project.

                  <Accordion title="How to solve">
                    Please contact <a href="https://help.crossmint.com/hc/en-us/requests/new?ticket_form_id=20311271387277" target="_blank">Crossmint support</a> and include your `collectionId` in the request.
                  </Accordion>
                </ParamField>

                <ParamField body="payments:collection.unverified">
                  Collection verification is not completed.

                  <Accordion title="How to solve">
                    You must complete <a href="/payments/advanced/production-launch#collection-verification" target="_blank">collection verification</a> to enable credit card payments for this collection.
                  </Accordion>
                </ParamField>

                <ParamField body="payments:project.unverified">
                  This project is pending KYC verification by Crossmint

                  <Accordion title="How to solve">
                    Ensure you have completed creator KYC.
                  </Accordion>
                </ParamField>

                <ParamField body="payments:collection.sold-out">
                  This one went quick! Unfortunately all the available items have been sold

                  <Accordion title="How to solve">
                    Your collection has sold out. Ensure proper messaging is in the UI.
                  </Accordion>
                </ParamField>

                <ParamField body="payments:collection.not-live">
                  This sale is not live yet

                  <Accordion title="How to solve">
                    Your mint is not yet live. Ensure proper messaging is in the UI.
                  </Accordion>
                </ParamField>

                <ParamField body="payments:collection.sale-ended">
                  This sale has ended on {time} UTC.

                  <Accordion title="How to solve">
                    Your mint has ended. Ensure proper messaging is in the UI.
                  </Accordion>
                </ParamField>

                <ParamField body="payments:user-wallet.limit-reached">
                  You have reached the maximum number of NFTs purchased for this stage of the sale.

                  <Accordion title="How to solve">
                    The user has minted the max amount of NFTs allowed per wallet. Ensure proper messaging is in the UI.
                  </Accordion>
                </ParamField>

                <ParamField body="payments:user-wallet.not-whitelisted">
                  Your wallet is not eligible for this purchase

                  <Accordion title="How to solve">
                    The user is not eligible to mint. Ensure proper messaging is in the UI.
                  </Accordion>
                </ParamField>
                */}
    </Accordion>
  </Tab>
</Tabs>
