Skip to main content
These flows are actively being refined. Crossmint’s customer success engineers (CSE) will work with you to review your architecture. Contact Crossmint to get started.

Overview

Virtual cards let your agent make credit card purchases without ever seeing the user’s real card number. Crossmint derives a scoped virtual card number from the user’s saved card, with configurable spend limits and issuer verification.

Key Properties

These are not new cards. Virtual cards are tokenized representations of the user’s existing card. This means:
  • Charges appear on the user’s regular bank statement
  • The user keeps their rewards points and cashback
  • Standard dispute resolution and fraud protection apply
  • No separate account or card to manage
Each virtual card (called an order intent in the API) comes with configurable mandates (spend limits, description) and requires card issuer verification before it can be used.

How It Works

The system has three layers:
ConceptAPI nameWhat it isLifetime
Saved cardPayment Method (paymentMethodId)The user’s tokenized credit cardPersistent, save once
Agentic enrollmentEnrollment (enrollmentId)Registers the card for agent use; requires cardholder verificationPersistent, one-time setup per card
Virtual cardOrder Intent (orderIntentId)A scoped spending authorization with mandatesOne per purchase
The flow is: save card (once) > enroll for agentic use (once per card) > create order intents as needed.
Virtual card flow: save card, enroll, create order intent, get credentials

Prerequisites

  • A Crossmint developer account
  • A client-side API key
  • Save Cards on File guide completed
  • JWT authentication configured. Crossmint uses a JWT to identify the user. See JWT Authentication for setup.
  • HTTPS required, even in local development. Visa’s Click to Pay verification uses the Web Authentication API (passkeys), which requires a secure context.

Integration Steps

1

Save a Card and Enroll for Agentic Use

The Crossmint React SDK handles card tokenization, agentic enrollment, and passkey verification in a secure iframe. Mount the CrossmintPaymentMethodManagement component and listen for callbacks:
import { useState } from "react";
import { CrossmintPaymentMethodManagement } from "@crossmint/client-sdk-react-ui";

const [verificationConfig, setVerificationConfig] = useState(null);

<CrossmintPaymentMethodManagement
    jwt={userJwt}
    onPaymentMethodSelected={(pm) => {
        console.log("Card saved:", pm.paymentMethodId);
    }}
    onAgenticEnrollmentCreated={(enrollment, verificationConfig) => {
        console.log("Enrollment:", enrollment.enrollmentId, enrollment.status);
        setVerificationConfig(verificationConfig);
    }}
/>
Store verificationConfig in state. You will pass it to the OrderIntentVerification component in Step 3 to authorize spending.When a user saves a Visa card, the SDK automatically enrolls it for agentic use and fires onAgenticEnrollmentCreated alongside onPaymentMethodSelected.
Only Visa cards can be enrolled for agentic use. The onAgenticEnrollmentCreated callback only fires for Visa cards.
2

Create an Agent

An agent represents your application acting on behalf of the user. Create one agent per logical use case. You only need to do this once; reuse the same agentId for subsequent order intents.
curl -X POST 'https://staging.crossmint.com/api/unstable/agents' \
  -H 'Content-Type: application/json' \
  -H 'X-API-KEY: <your_api_key>' \
  -H 'Authorization: Bearer <your_jwt>' \
  -d '{
    "metadata": {
      "name": "My Shopping Agent",
      "description": "Agent for making purchases"
    }
  }'
Response:
{
  "agentId": "agent_abc123",
  "metadata": { "name": "My Shopping Agent", "description": "Agent for making purchases" }
}
Store the returned agentId; you will need it to create virtual cards.
3

Create a Virtual Card and Authorize Spending

Before creating an order intent, check the enrollment status via GET /api/unstable/payment-methods/<payment_method_id>/agentic-enrollment. If the status is not active (e.g. pending_verification or pending), mount PaymentMethodAgenticEnrollmentVerification to complete it:
import { PaymentMethodAgenticEnrollmentVerification } from "@crossmint/client-sdk-react-ui";

<PaymentMethodAgenticEnrollmentVerification
    config={verificationConfig}
    agentEnrollmentId={enrollment.enrollmentId}
    onVerificationComplete={() => { /* now proceed to create order intent */ }}
    onVerificationError={(err) => console.error(err)}
/>
This can happen if the user navigated away during card save before passkey verification completed.An order intent defines the spending rules for a virtual card. Think of it as a “permission slip” with limits. It ties together an agent, a payment method, and a set of mandates (spending constraints).3a. Create the order intentUse the paymentMethodId from Step 1 (returned in the onPaymentMethodSelected callback) and the agentId from Step 2:
curl -X POST 'https://staging.crossmint.com/api/unstable/order-intents' \
  -H 'Content-Type: application/json' \
  -H 'X-API-KEY: <your_api_key>' \
  -H 'Authorization: Bearer <your_jwt>' \
  -d '{
    "agentId": "<your_agent_id>",
    "payment": {
      "paymentMethodId": "<your_payment_method_id>"
    },
    "mandates": [
      {
        "type": "maxAmount",
        "value": "150.00",
        "details": { "currency": "usd", "period": "transaction" }
      },
      {
        "type": "description",
        "value": "Groceries from Whole Foods"
      }
    ]
  }'
Get the orderIntentId, phase, and payment.btAgentId / payment.btInstructionId from the response.3b. Authorize the expenditureWhen the response phase is "requires-verification", mount the OrderIntentVerification component to prompt the user for passkey authorization:Pass verificationConfig (from Step 1’s onAgenticEnrollmentCreated callback) and the order intent response — including btAgentId and btInstructionId from the payment object — to the component:
import { OrderIntentVerification } from "@crossmint/client-sdk-react-ui";

<OrderIntentVerification
    config={verificationConfig}
    orderIntent={{
        orderIntentId: "<your_order_intent_id>",
        phase: "requires-verification",
        mandates: [/* mandate objects from the response */],
        payment: {
            btAgentId: response.payment.btAgentId,
            btInstructionId: response.payment.btInstructionId,
        },
    }}
    onVerificationComplete={() => {}}
    onVerificationError={(err) => console.error(err)}
/>
After verification, the order intent phase changes to active.
There are two passkey prompts in the full flow: enrollment verification (Step 1, handled automatically by the SDK during card save) and spending authorization (this step, which authorizes the specific spending scope defined by the mandates).
4

Get Card Credentials

Once the order intent is active, retrieve the virtual card credentials. These are the actual card number, expiration, and CVC that your agent uses to make a purchase.
curl -X POST 'https://staging.crossmint.com/api/unstable/order-intents/<your_order_intent_id>/credentials' \
  -H 'Content-Type: application/json' \
  -H 'X-API-KEY: <your_api_key>' \
  -H 'Authorization: Bearer <your_jwt>' \
  -d '{
    "merchant": {
      "name": "Whole Foods",
      "url": "https://www.wholefoodsmarket.com",
      "countryCode": "US"
    }
  }'
Response:
{
  "card": {
    "number": "4000001000004242",
    "expirationMonth": "03",
    "expirationYear": "2027",
    "cvc": "654"
  },
  "expiresAt": "2026-12-31T23:59:59.000Z"
}
Credentials are ephemeral — they expire in minutes and are single-use.
Create a new order intent for each purchase. The underlying saved card and agentic enrollment are persistent and do not need to be re-created.

Useful Endpoints

MethodEndpointDescription
GET/api/unstable/agentsList existing agents (check before creating a new one)
GET/api/unstable/order-intentsList all order intents for the user
GET/api/unstable/order-intents/{id}Get a single order intent’s current status

Next Steps

Save Cards on File

Set up the card tokenization component that serves as the foundation for virtual cards.

Fund a Stablecoin Wallet

An alternative payment path: fund your agent’s wallet with stablecoins via onramp.