Skip to main content

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.

Introduction

A saved card is not automatically usable by agents. Before agents can use it to pay, the card must be verified for agentic payments. Verification is a one-time step per card that produces two things:
  1. Account verification via a one-time code sent to the user’s email.
  2. A passkey bound to the user’s device, so future payment authorizations only need a single passkey tap.
Once a card is verified, every subsequent card permission can be authorized by the user with their passkey alone. The email step is not repeated.

Prerequisites

  • A saved card. See Save a Card if you have not done this yet.
  • The paymentMethodId of the saved card.
  • An authenticated user with a JWT.
Eligible CardsYou can currently use card permissions with Mastercard and eligible U.S.-issued Visa credit and debit cards.Not supported for Visa: non-US cards, business cards, prepaid cards, Chase cards, Fidelity cards.For AMEX and Ramp cards, contact us.

Steps

1

Check the card's current verification status

Before starting verification, check whether the card is already verified. The API returns a status that is always one of the following:
StatusMeaning
not_startedVerification has not been started yet.
pendingVerification was started; the user still needs to complete the challenge (email code and/or passkey).
activeVerification finished; the card is ready for agentic card permissions.
const BASE_URL = "https://staging.crossmint.com/api/unstable";

async function checkEnrollment(jwt: string, paymentMethodId: string) {
    const response = await fetch(
        `${BASE_URL}/payment-methods/${paymentMethodId}/agentic-enrollment`,
        {
            headers: {
                "Content-Type": "application/json",
                "X-API-KEY": CROSSMINT_CLIENT_API_KEY,
                Authorization: `Bearer ${jwt}`,
            },
        }
    );

    return response.json();
    // { status: "active" | "pending" | "not_started", ... }
}
If the status is active, verification is complete and you can skip directly to Give Card Permission. If it is pending, reuse the existing verification response in the next step rather than creating a new one.
2

Start verification

If the card is not_started, send a POST request with the user’s email to begin verification. The response includes an enrollmentId and a verificationConfig that the verification component uses to run the passkey ceremony.
async function startEnrollment(
    jwt: string,
    paymentMethodId: string,
    email: string
) {
    const response = await fetch(
        `${BASE_URL}/payment-methods/${paymentMethodId}/agentic-enrollment`,
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "X-API-KEY": CROSSMINT_CLIENT_API_KEY,
                Authorization: `Bearer ${jwt}`,
            },
            body: JSON.stringify({ email }),
        }
    );

    return response.json();
}
Example response:
{
    "enrollmentId": "enr_abc123",
    "status": "pending",
    "verificationConfig": {
        "environment": "test",
        "publicApiKey": "YOUR_PUBLIC_API_KEY"
    }
}
3

Render the verification component

Pass the pending verification response to the PaymentMethodAgenticEnrollmentVerification component. It runs the full device-binding ceremony inside your UI — the user receives an email code, enters it, and then creates a passkey bound to the current device.
import { PaymentMethodAgenticEnrollmentVerification } from "@crossmint/client-sdk-react-ui";

function EnrollCardStep({ enrollment }: { enrollment: PendingEnrollment }) {
    return (
        <PaymentMethodAgenticEnrollmentVerification
            enrollment={enrollment}
            onVerificationComplete={() => {
                console.log("Card is now verified for agentic use");
            }}
            onVerificationError={(error) => {
                console.error("Verification failed", error);
            }}
        />
    );
}
When onVerificationComplete fires, the server has flipped the verification to active. The card is now ready for agentic card permissions.

Understanding the Verification Flow

The PaymentMethodAgenticEnrollmentVerification component runs the following sequence in order:
  1. The server sends a one-time code to the user’s email.
  2. The user enters the code in the component’s UI.
  3. The component prompts the browser to create a passkey bound to this device.
  4. The server marks the verification active.
The email code and the passkey are not two separate checks. The email code proves the user owns the account; the passkey then binds the device so that future payment authorizations can skip the email step. Both are part of a single device-binding ceremony.

Common Gotchas

Once a card is verified, all subsequent payment authorizations use the passkey alone. If you see the email code prompt on a non-verification flow, the device is not yet bound — complete verification first.
If the user clears browser state, switches browsers, or moves to a new device, they may be asked to re-verify for future actions on that new device.
Once a card is verified, any agent on the account can be given card permissions from it.

What Is Next

With the card verified, the last step in this setup path is to Give Card Permission so your agent can pay within scoped spending rules against the verified payment method.