Cart Verification

After an agent has an approved Intent Mandate, it can build a shopping cart with a merchant. Before payment, the cart must be verified against the intent and policy to ensure compliance.

Overview

Cart verification is the second step in the payment flow:

Intent ApprovedCart VerifiedPayment Executed

During verification, AutopayOS checks:

  • Amount ≤ Intent maximum
  • Merchant matches intent
  • Categories allowed by policy
  • No duplicate submission
  • Velocity limits OK

Verify a cart

<tabs> <tab title="TypeScript">
TypeScript
const verification = await client.verifyCart({
  intentVc: permission.intentVc,
  cartVc: merchantCartVc,
});

if (verification.allowed) {
  console.log('Cart verified!');
  console.log('Approval token:', verification.approvalToken);
  console.log('Payment rail:', verification.railDecision.rail);
} else {
  console.log('Cart rejected:', verification.reasonCodes);
}
</tab> <tab title="cURL">
Bash
curl https://api.autopayos.com/ap2/carts/validate \
  -H "Authorization: Bearer $AUTOPAYOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "intentVc": {
      "type": ["VerifiableCredential", "IntentMandate"],
      "credentialSubject": {
        "mandateId": "intent_abc123",
        "maxAmount": 100.00,
        "currency": "USD",
        "merchantDomain": "amazon.com"
      },
      "proof": { ... }
    },
    "cartVc": {
      "type": ["VerifiableCredential", "CartMandate"],
      "credentialSubject": {
        "merchant": "amazon.com",
        "items": [
          { "name": "USB-C Cable", "sku": "USB001", "price": 12.99, "quantity": 2 },
          { "name": "Phone Stand", "sku": "PHN002", "price": 9.99, "quantity": 1 }
        ],
        "subtotal": 35.97,
        "tax": 2.88,
        "total": 38.85,
        "currency": "USD"
      },
      "proof": { ... }
    }
  }'
</tab> </tabs>

Request parameters

ParameterTypeRequiredDescription
intentVcobjectYesThe Intent Mandate VC from permission request
cartVcobjectYesThe Cart VC from the merchant
hpProofobjectNoHuman Presence proof (if required)
idempotencyKeystringNoPrevent duplicate verifications

Cart VC structure

Merchants create Cart VCs with this structure:

JSON
{
  "@context": ["https://www.w3.org/2018/credentials/v1"],
  "type": ["VerifiableCredential", "CartMandate"],
  "issuer": "did:web:amazon.com",
  "issuanceDate": "2025-12-17T10:30:00Z",
  "credentialSubject": {
    "cartId": "cart_xyz789",
    "merchant": "amazon.com",
    "items": [
      {
        "name": "USB-C Cable 6ft",
        "sku": "B08USB6FT",
        "price": 12.99,
        "quantity": 2,
        "category": "electronics"
      },
      {
        "name": "Phone Stand",
        "sku": "B09STAND1",
        "price": 9.99,
        "quantity": 1,
        "category": "electronics"
      }
    ],
    "subtotal": 35.97,
    "tax": 2.88,
    "shipping": 0.00,
    "total": 38.85,
    "currency": "USD"
  },
  "proof": {
    "type": "Ed25519Signature2020",
    "created": "2025-12-17T10:30:00Z",
    "verificationMethod": "did:web:amazon.com#key-1",
    "jws": "eyJhbGciOiJFZERTQSJ9..."
  }
}

Response

Approved

JSON
{
  "allowed": true,
  "approvalToken": "apt_abc123xyz789...",
  "approvalTokenExpiresAt": "2025-12-17T10:35:00Z",
  "railDecision": {
    "rail": "STRIPE",
    "reason": "Optimal for merchant capabilities",
    "merchantConnected": true,
    "expiresAt": "2025-12-17T10:35:00Z"
  },
  "cartHash": "sha256:abc123def456...",
  "verifiedAt": "2025-12-17T10:30:05Z"
}

Rejected

JSON
{
  "allowed": false,
  "reasonCodes": [
    "CART_EXCEEDS_INTENT",
    "CATEGORY_NOT_ALLOWED"
  ],
  "details": {
    "CART_EXCEEDS_INTENT": {
      "cartTotal": 150.00,
      "intentMax": 100.00
    },
    "CATEGORY_NOT_ALLOWED": {
      "item": "Premium Subscription",
      "category": "digital_goods",
      "allowedCategories": ["electronics", "groceries"]
    }
  }
}

Verification checks

CheckDescriptionReason Code
AmountCart total ≤ intent max amountCART_EXCEEDS_INTENT
MerchantCart merchant matches intentMERCHANT_MISMATCH
CategoriesAll items in allowed categoriesCATEGORY_NOT_ALLOWED
MCCMerchant Category Code allowedMCC_DENIED
DuplicatesCart not submitted beforeDUPLICATE_CART
Intent validIntent not expired or usedINTENT_EXPIRED, INTENT_ALREADY_USED
SignatureCart VC signature validINVALID_SIGNATURE
VelocityWithin transaction limitsVELOCITY_EXCEEDED
AnomalyNo unusual patterns detectedANOMALY_DETECTED

Rail selection

AutopayOS automatically selects the best payment rail based on:

FactorConsideration
Merchant capabilitiesWhich rails the merchant supports
CostTransaction fees for each rail
SpeedSettlement time
Policy preferenceRails allowed by policy
AmountSome rails have limits
JSON
{
  "railDecision": {
    "rail": "STRIPE",
    "reason": "Optimal for merchant capabilities",
    "alternatives": [
      { "rail": "VISA_IC", "reason": "Not configured for merchant" }
    ]
  }
}

Rail priorities

Configure rail preferences in your policy:

JSON
{
  "rails": {
    "allow": ["STRIPE", "VISA_IC"],
    "priorities": ["STRIPE", "VISA_IC"],
    "fail_over": true
  }
}

Approval token

The approvalToken is a short-lived, single-use token for executing the payment:

PropertyValue
Lifetime2-5 minutes (configurable)
UsageSingle use only
ScopeSpecific cart and amount
RevocableYes, before use
TypeScript
// Use the approval token to execute payment
const payment = await client.executePayment({
  approvalToken: verification.approvalToken,
});

Important: Approval tokens expire quickly. Execute payment immediately after verification.

Duplicate detection

AutopayOS prevents duplicate cart submissions using cart hashing:

Cart items + merchant + amount → SHA-256 hash → Dedup check

If the same cart is submitted twice within 60 seconds, you'll receive:

JSON
{
  "allowed": false,
  "reasonCodes": ["DUPLICATE_CART"],
  "existingApprovalToken": "apt_existing..."
}

Use the existing approval token instead of creating a new one.

Human Presence for carts

If Human Presence was required at intent creation, include the HP proof:

TypeScript
const verification = await client.verifyCart({
  intentVc: permission.intentVc,
  cartVc: merchantCartVc,
  hpProof: {
    type: 'WebAuthn',
    challengeId: 'hp_xyz789',
    credential: webAuthnCredential,
    timestamp: new Date().toISOString(),
  },
});

Category validation

AutopayOS validates cart item categories against your policy:

JSON
// Policy
{
  "spend": {
    "categories": ["groceries", "household", "electronics"]
  }
}
JSON
// Cart item
{
  "name": "Premium Subscription",
  "category": "digital_goods"  // Not in allowed list
}

Result: CATEGORY_NOT_ALLOWED

Category synonyms

AutopayOS recognizes category synonyms:

Policy CategoryAlso Matches
groceriesfood, supermarket, grocery_stores
electronicstech, computers, consumer_electronics
householdhome, home_goods, housewares

Best practices

1. Verify immediately

Don't delay between building the cart and verifying:

TypeScript
// Good: Verify right away
const cart = await merchant.buildCart(items);
const verification = await client.verifyCart({ intentVc, cartVc: cart });
await client.executePayment({ approvalToken: verification.approvalToken });

// Bad: Long delay
const cart = await merchant.buildCart(items);
await sleep(300000); // 5 minutes
const verification = await client.verifyCart({ intentVc, cartVc: cart }); // Intent may expire

2. Handle rejections

TypeScript
const verification = await client.verifyCart({ intentVc, cartVc });

if (!verification.allowed) {
  for (const code of verification.reasonCodes) {
    switch (code) {
      case 'CART_EXCEEDS_INTENT':
        // Remove items or request new intent
        break;
      case 'CATEGORY_NOT_ALLOWED':
        // Remove disallowed items
        break;
      case 'DUPLICATE_CART':
        // Use existing approval token
        break;
      case 'INTENT_EXPIRED':
        // Request new intent
        break;
    }
  }
}

3. Include all cart details

Provide complete cart information for accurate verification:

TypeScript
const cartVc = {
  credentialSubject: {
    merchant: 'amazon.com',
    items: [
      {
        name: 'USB-C Cable',
        sku: 'B08USB6FT',
        price: 12.99,
        quantity: 2,
        category: 'electronics',  // Include category
      }
    ],
    subtotal: 25.98,
    tax: 2.08,
    shipping: 5.99,
    total: 34.05,  // Include all fees
    currency: 'USD',
  }
};

Evidence events

Cart verification produces these evidence events:

EventDescription
CART_VALIDATEDCart was verified successfully
CART_REJECTEDCart failed verification
CART_DUPLICATEDuplicate cart detected

Query cart events:

Bash
curl "https://api.autopayos.com/ap2/evidence/search?eventType=CART_VALIDATED" \
  -H "Authorization: Bearer $AUTOPAYOS_API_KEY"

Next steps