> ## Documentation Index
> Fetch the complete documentation index at: https://crossmint-devin-1787949784-wallet-docs-two-concept-model.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Create an Agent Card

> Create and authorize an order intent backed by a saved card

An agent card is an order intent that gives an agent a bounded amount to spend before a fixed expiration. An order intent can have multiple rails, each with its own status, credential formats, and verification.

## Prerequisites

* **Registered card** — [register a saved card](/agents/payment-methods/cards/register-card) and confirm that it has an `enabled` rail.
* **Crossmint API key** — a client-side key with `order-intents.create` and `order-intents.read` scopes. In staging, all scopes are included by default.
* **User JWT** — use the JWT for the user who owns the saved card.

## Create the Order Intent

Create an order intent with the saved card, spending limit, description, expiration, and merchant. Include the merchant now when you already know where the agent will spend:

```typescript theme={null}
const CROSSMINT_CLIENT_API_KEY = "YOUR_CROSSMINT_CLIENT_API_KEY";
const jwt = "YOUR_USER_JWT";
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();

const response = await fetch("https://staging.crossmint.com/api/unstable/order-intents", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-API-KEY": CROSSMINT_CLIENT_API_KEY,
        Authorization: `Bearer ${jwt}`,
    },
    body: JSON.stringify({
        paymentMethodId: "pm_123",
        amount: { value: "150.00", currency: "USD" },
        merchant: {
            name: "Acme Store",
            url: "https://acme.example.com",
            countryCode: "US",
        },
        description: "Weekly grocery purchases",
        expiresAt,
    }),
});

if (!response.ok) {
    throw new Error(`Order intent creation failed (${response.status})`);
}

const orderIntent = await response.json();
```

The response separates the order intent's lifecycle from the status of each rail:

```json theme={null}
{
    "orderIntentId": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
    "paymentMethodId": "pm_123",
    "status": "active",
    "amount": {
        "total": "150.00",
        "spent": "0.00",
        "reserved": "0.00",
        "available": "150.00",
        "currency": "USD"
    },
    "merchant": {
        "name": "Acme Store",
        "url": "https://acme.example.com",
        "countryCode": "US"
    },
    "description": "Weekly grocery purchases",
    "rails": [
        {
            "rail": "agentic-token",
            "provider": "vic",
            "status": "pending_verification",
            "credentialFormats": ["card", "network-token"]
        }
    ],
    "verificationConfig": {
        "environment": "test",
        "publicApiKey": "key_test_123",
        "allowanceId": "alw_123"
    },
    "expiresAt": "2099-01-01T00:00:00.000Z"
}
```

Setting `merchant` when creating the order intent is preferred when you know it. The merchant is fixed for the lifetime of that order intent, and credential requests inherit the restriction.

If the agent will choose a merchant later, omit `merchant`. This creates an open order intent, and every credential request must supply the merchant instead.

The top-level `status` is `active` while the allowance exists. A specific rail can still require verification.

Treat `rails` as a set of independent ways to spend the same allowance:

1. Choose the rail that provides the credential you need.
2. If that rail is `pending_verification`, verify it.
3. Once it is `active`, mint with the same `rail` and `provider` values.

You do not need every rail to be active. Other rails can remain `pending_verification` or `error` without blocking the selected rail. For example, when an allowance contains both VIC and SPT, minting a VIC credential only requires the VIC rail to be verified; you do not need to complete an SPT step. Crossmint currently exposes VIC and Mastercard Agent Pay card-network rails, and the same selection rule applies as more rails are added.

## Verify the Selected Rail

When the rail you want to use has `status: "pending_verification"`, render `OrderIntentVerification` in your client application. Do not start verification merely because an unrelated rail is pending.

```tsx theme={null}
import {
    OrderIntentVerification,
    type OrderIntentVerificationProps,
} from "@crossmint/client-sdk-react-ui";

function VerifyOrderIntent({
    orderIntent,
}: {
    orderIntent: OrderIntentVerificationProps["orderIntent"];
}) {
    return (
        <OrderIntentVerification
            orderIntent={orderIntent}
            displayName="Acme Shopping Agent"
            onVerificationComplete={() => {
                console.log("Allowance verified");
            }}
            onVerificationError={(error) => {
                console.error("Allowance verification failed", error);
            }}
        />
    );
}
```

After verification completes, fetch the order intent again and wait for the selected rail to report `status: "active"`. You do not need to wait for the other rails.

Card registration never prompts for verification. Verification belongs to an individual order-intent rail. The first Visa verification on a device can create a passkey; later order intents authenticate with the existing passkey when the device remains bound. The component also handles the Mastercard-hosted flow.

For the complete request and response schemas, see the [Create Order Intent API Reference](/api-reference/agentic-commerce/order-intents/create-order-intent).

## Common Gotchas

<AccordionGroup>
  <Accordion title="An active order intent can still have a pending rail">
    Read `rails[].status` before minting. The top-level `status` describes the order intent's lifetime, not whether every rail is ready.
  </Accordion>

  <Accordion title="Each order intent has its own verification state">
    Register the card once, then verify only the order-intent rail you plan to use when it returns `pending_verification`. Do not repeat card registration to authorize a new allowance.
  </Accordion>

  <Accordion title="The expiration is required">
    Set `expiresAt` to a future ISO 8601 timestamp that matches the permission you present to the user.
  </Accordion>

  <Accordion title="A scoped merchant cannot be changed later">
    Include `merchant` when creating the order intent if you already know it. Otherwise, omit it and supply a merchant with every credential request.
  </Accordion>

  <Accordion title="Browser verification requires HTTPS">
    Use an HTTPS tunnel when testing the verification ceremony from a local browser.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Retrieve Secure Card Numbers" icon="key" href="/agents/payment-methods/cards/retrieve-agent-card">
    Mint a credential from an active rail
  </Card>

  <Card title="Customize UI" icon="palette" href="/agents/payment-methods/cards/customize-verification-ui">
    Style the allowance verification modal
  </Card>
</CardGroup>
