Back to articles
ArchitectureAPI GatewayRESTIntegration Architectureagentic-commercemcp

Visa VIC vs UCP: Two Competing Visions for Agentic Commerce

Visa published their VIC reference agent — a 5-microservice demo of AI-driven shopping with tokenized payments. I dissected the architecture, compared it to UCP and other open protocols, and found a fundamental design tension: card networks optimize for payment security, open protocols optimize for merchant flexibility.

Written by Artemii Karkusha — Integration Architect

April 10, 202618 min read

Visa just published vic-reference-agent — their open-source vision for how AI agents should buy things on behalf of humans. Five microservices, LangGraph orchestration, MCP tool integration, and a deep pipeline into Visa Token Service and Visa Intelligent Commerce APIs.

I spent two days dissecting every file in that repository. Not because Visa needs my code review — but because when the world's largest payment network publishes their architectural opinion on agentic commerce, it reveals something important about where this space is heading.

After building UCP (Universal Commerce Protocol) middleware that handles multi-merchant, multi-platform checkout for AI agents, I have a specific lens on what matters in this architecture. Here's the full analysis — what VIC gets right, where it falls short, and the fundamental design tension between card-network-centric and protocol-first approaches.

The VIC Architecture at a Glance

Visa's reference agent is a 5-service system orchestrated via Docker Compose:

VIC Architecture — 5 microservices: Agent Frontend → Agent Backend → MCP Server → Merchant Backend, plus Merchant Frontend. Agent Backend connects to Visa VTS/VIC APIs

Service Stack Role
Agent Frontend React 19, TypeScript, Vite Shopping agent UI + card management
Agent Backend FastAPI, LangGraph, Python 3.12 AI agent orchestration + Visa API integration
Merchant MCP Express, @modelcontextprotocol/sdk MCP tool server bridging agent to merchant
Merchant Backend FastAPI, SQLAlchemy, SQLite Product catalog, cart, orders
Merchant Frontend React, JSX, Vite Traditional merchant storefront

The tech choices are solid for a reference implementation. FastAPI for the Python services, LangGraph for stateful agent orchestration, and the official MCP SDK with Streamable HTTP transport. Nothing exotic.

But the architecture reveals something deeper about Visa's mental model: the agent is a Visa customer, not a merchant customer. The entire system is designed around Visa's token lifecycle, not around merchant flexibility.

What VIC Gets Right

1. Payment Credential Security Is Best-in-Class

This is where VIC genuinely shines. The payment credential flow is the most sophisticated I've seen in any agentic commerce implementation:

VIC Payment Credential Flow — PAN enrollment through VTS token provisioning, VIC enrollment, intent creation, credential retrieval, and transaction confirmation

The credential never touches the AI agent in plaintext. Here's the actual flow:

  1. User enrolls their card PAN into Visa Token Service (encrypted with JWE)
  2. VTS provisions a token with presentationType: ["AI_AGENT"] — a new token type specifically for agent commerce
  3. The token gets enrolled in VIC (Visa Intelligent Commerce)
  4. At checkout, VIC creates an intent with FIDO assurance data from the user's passkey
  5. VIC retrieves tokenized credentials — a dynamic card number, expiry, and cryptographic CVV
  6. These credentials flow through MCP elicitation to the merchant
  7. After the merchant processes payment, VIC confirms the transaction status

The security layers are serious:

  • Message Level Encryption (MLE): RSA-OAEP-256 + A256GCM (JWE) for all VIC API calls
  • Field-level encryption: A256GCMKW for sensitive fields like PAN and risk data
  • HMAC-SHA256 request signing: Every API call gets an x-pay-token header
  • FIDO2/WebAuthn passkeys: Biometric step-up for payment authorization
Real-World Example: The AI_AGENT token presentation type is new. Traditional e-commerce uses E_COMMERCE. By creating a distinct type, Visa can apply different risk scoring, different liability rules, and different fraud models specifically for agent-initiated transactions. This is a smart regulatory play — it gives card networks a way to treat agent purchases differently from human-initiated ones without breaking existing payment rails.

2. MCP Elicitation Pattern Is Elegant

The checkout_cart MCP tool uses server.elicitInput() to request payment details at checkout time:

// Merchant MCP server — checkout tool
const result = await mcpServer.server.elicitInput({
  message: "Payment information required",
  requestedSchema: {
    type: "object",
    properties: {
      card_number: { type: "string", title: "Card Number" },
      expiry_date: { type: "string", title: "Expiry Date" },
      cvv: { type: "string", title: "CVV" },
    },
    required: ["card_number", "expiry_date", "cvv"],
  },
});

The agent backend responds to this elicitation via a callback:

# Agent backend — elicitation handler
async def on_elicitation(context, params):
    if current_credentials:
        return ElicitationResult(
            action="accept",
            content=current_credentials
        )
    return ElicitationResult(action="decline")

This is a genuinely good pattern. The merchant doesn't know where the credentials come from — it just asks. The agent doesn't expose credentials until the merchant specifically requests them during a checkout operation. Clean separation of concerns at the protocol level.

3. Intent-Mandate-Transaction Model

VIC introduces a three-level hierarchy for purchase authorization:

Concept Purpose Lifecycle
Intent What the buyer wants to buy Created per checkout session
Mandate Spending limit + constraints + time window Bound to an intent, has effective_until_time
Transaction Actual charge against a mandate SUCCESS or FAILURE, confirmed back to VIC

This maps well to real-world agent scenarios. An autonomous agent might have a mandate to "spend up to $500/month on office supplies" — the intent is each purchase, the mandate is the budget constraint, and transactions are individual charges.

What's interesting is that UCP arrived at a remarkably similar abstraction independently — the AP2 Mandates Extension. UCP uses Verifiable Digital Credentials (VDCs) to formalize three distinct mandate types:

UCP Mandate Purpose Scenario
Intent Mandate Grants the agent authority to purchase within defined constraints (budget, time window, categories) Human-not-present: autonomous agent shopping
Cart Mandate User's cryptographic signature on a specific cart — exact items and price, non-repudiable Human-present: user reviews and approves
Payment Mandate Signals AI agent involvement and user presence status to payment networks and issuers Shared with payment rails for risk assessment

The key difference: VIC's mandate model is payment-rail-centric — the mandate lives inside Visa's infrastructure and is enforced by VIC. UCP's mandates are cryptographic and portable — they're signed VDCs that travel with the transaction and can be verified by any party in the chain (merchant, payment processor, issuer) regardless of the specific payment network.

UCP also makes a critical architectural distinction that VIC doesn't: human-present vs human-not-present scenarios. The Intent Mandate grants an agent autonomous spending authority with guardrails. The Cart Mandate requires the user's explicit, cryptographic approval of a specific cart. VIC's model conflates these two scenarios into a single intent — you always need a FIDO passkey assertion, even for autonomous agent purchases, which undermines the "autonomous" part.

Real-World Example: Consider a corporate procurement agent authorized to buy office supplies up to $500/month. With UCP's Intent Mandate, the agent operates autonomously within those constraints — no human step-up needed for each purchase. With VIC, every purchase requires a FIDO passkey assertion, meaning someone has to physically authenticate with their device. That's secure, but it's not autonomous — it's just adding an AI layer on top of human-initiated payments.

The convergence on mandate abstractions from both a card network (Visa) and an open protocol (UCP) validates that this is the right architectural pattern for agentic commerce. But the implementation philosophy diverges: centralized enforcement (VIC) vs. portable, cryptographic proof (UCP).

Where VIC Falls Short

1. Single Merchant, Single Network, Zero Extensibility

Here's the fundamental problem: VIC is hardcoded to one merchant and one payment network.

The MCP server connects to exactly one merchant backend at http://reference-merchant-backend:8001. There's no adapter pattern, no registry, no routing. If an AI agent needs to comparison-shop across multiple merchants — which is literally the core value proposition of agentic commerce — the entire MCP server needs to be duplicated.

Compare this to a protocol-first approach where a single gateway handles multiple merchants:

// UCP approach — adapter pattern with tenant isolation
interface PlatformAdapter {
  readonly searchProducts: (query: SearchQuery) => Promise<readonly Product[]>;
  readonly createCart: (items: readonly CartItem[]) => Promise<Cart>;
  readonly placeOrder: (cart: Cart, payment: PaymentToken) => Promise<Order>;
}

// One gateway, N merchants via adapter registry
const adapter = adapterRegistry.resolve(tenant.platformType);
const products = await adapter.searchProducts(query);

VIC's design means each merchant needs its own MCP server, its own tool definitions, its own connection management. In production, this creates an N-microservices problem for N merchants.

2. Global Mutable State Kills Concurrency

This one surprised me in a Visa reference implementation. The agent service uses module-level globals:

# From reference-agent-backend/src/services/agent.py
current_thread_id: str | None = None
current_credentials: dict | None = None

Two users checking out simultaneously would corrupt each other's credentials. This is a demo-level pattern that would be a critical security vulnerability in production. Session isolation isn't optional in payment systems — it's the bare minimum.

Production Pattern

Payment credentials must be scoped to a session, never stored in global state. Use Redis-backed session stores with tenant isolation, TTL-based expiration, and cryptographic session IDs. The credential retrieval and the checkout completion must happen within the same session boundary — ideally with an idempotency key to prevent double-charge on retry.

3. No Formal Schema Governance

VIC has no published schema, no JSON Schema files, no OpenAPI specification, no automated compliance checks. The data contracts are implicit in Python Pydantic models and TypeScript Zod schemas within the MCP tool definitions.

This matters because schema drift is one of the most common failure modes in integrations. When Visa updates their VTS or VIC APIs, there's no automated way to detect breaking changes in this reference implementation. No conformance test suite, no gap analysis, no version tracking.

For comparison, production-grade protocol implementations track schema coverage explicitly — every field, every constraint, every validation rule mapped to a spec version. The Schema Drift Trap catches teams who skip this step: what works today breaks silently when the upstream API evolves.

4. Visa-Only Payment Rail

VIC only supports Visa cards. The entire system — VTS token provisioning, VIC enrollment, intent creation, credential retrieval — is built on Visa-proprietary APIs at cert.api.visa.com.

In the real world, merchants accept Mastercard, Amex, PayPal, Apple Pay, buy-now-pay-later, crypto, and bank transfers. An agentic commerce protocol that only works with one card network is like an integration middleware that only supports one ERP — technically correct but architecturally limited.

Open protocols handle this differently by abstracting the payment method behind a handler interface:

interface PaymentHandler {
  readonly id: string;
  readonly name: string;
  readonly type: "card" | "wallet" | "redirect" | "offline" | "other";
}

// Payment network is a detail, not a constraint
const handlers = await adapter.getSupportedPaymentMethods();
// Returns: Visa, Mastercard, PayPal, Klarna, etc.

The Architecture Comparison

Here's the systematic comparison across every dimension that matters for production agentic commerce:

Dimension Visa VIC UCP / Open Protocol
Nature Reference demo Production gateway framework
Protocol support MCP only REST + MCP + A2A + Embedded
Payment networks Visa only Network-agnostic (adapter-driven)
Merchant integration Single hardcoded merchant Multi-tenant, multi-platform
Adapter pattern None First-class PlatformAdapter interface
Schema governance Implicit (Pydantic/Zod) SDK-derived schemas, 150+ checks
Session management In-memory + global state Redis-backed, tenant-isolated, idempotent
Auth model Visa API keys + HMAC + MLE + FIDO2 JWS request signing + tenant JWT
Agent orchestration LangGraph baked in Agent-agnostic (any HTTP client)
Testing 3 unit tests 222+ integration tests, E2E per adapter
Payment depth Deep (VTS + VIC + FIDO) Abstract (payment handler interface)
Mandate model Intent → Mandate → Transaction (VIC-enforced) 3 VDC types: Intent / Cart / Payment (cryptographic, portable)
Human-not-present Requires FIDO passkey for every purchase Intent Mandate grants autonomous authority

The Flexibility Question

Is VIC more flexible than open protocols? No — and it's not trying to be.

VIC optimizes for a different axis: payment security depth over integration breadth. And within that axis, it's genuinely impressive. The token lifecycle management, the MLE encryption, the FIDO2 passkey integration — this is how a card network with decades of fraud prevention experience thinks about agent payments.

But flexibility in agentic commerce means:

Flexibility axis VIC Open Protocol
Add a new merchant Duplicate MCP server Register adapter + tenant
Support non-Visa payments Impossible Add payment handler
Switch LLM framework Rewrite agent.py Any HTTP client works
Deploy without Docker Difficult (5-service coupling) Single deployable + Redis
Add new protocol binding Not supported Add route handler

What Open Protocols Can Learn from VIC

Despite VIC being less flexible, it has patterns worth adopting:

1. MCP Elicitation for Credential Transfer

The elicitInput() pattern is protocol-level elegance. Instead of passing payment tokens in the request body, the merchant requests credentials at the exact moment they're needed. This creates a just-in-time credential flow that minimizes the window of credential exposure.

Open protocols that support MCP bindings should adopt this for checkout completion — it's strictly better than embedding payment tokens in a complete-session POST body.

2. Token Presentation Types

The AI_AGENT token type is forward-thinking. As regulators begin distinguishing between human-initiated and agent-initiated purchases, having distinct token types allows different risk scoring, liability rules, and fraud models per presentation type.

3. API Log Transparency

VIC logs every Visa API call and displays the full request/response in a dedicated UI panel. This follows the Observability Rule — if you can't see the data flowing through your integration, you can't debug it.

4. Convergent Evolution on Mandates

Both VIC and UCP independently arrived at mandate-based authorization for agent spending. This convergent evolution validates the pattern — any agentic commerce system needs a way to express spending authority with constraints. Where VIC adds value is in demonstrating how card networks can consume these mandates for risk scoring. The Payment Mandate concept (signaling agent involvement to issuers) is especially relevant as regulators begin distinguishing between human-initiated and agent-initiated purchases.

The Fundamental Design Tension

Here's what this comparison really reveals: card networks and open protocols are optimizing for different stakeholders.

Visa's VIC optimizes for the card network:

  • Every transaction flows through Visa rails
  • Token lifecycle is managed by Visa
  • Risk scoring happens at Visa's layer
  • The merchant sees tokenized credentials, not raw PANs

Open protocols optimize for the merchant ecosystem:

  • Any payment network can participate
  • Merchants keep their existing platform (Magento, Shopware, Shopify)
  • The protocol doesn't mandate a specific payment rail
  • Multi-tenant by design — one gateway serves many merchants

Neither approach is wrong. But they serve different masters. A merchant who already accepts multiple payment methods won't lock into a Visa-only agent flow. A bank that wants maximum control over the payment security stack won't trust an open protocol's payment handler abstraction.

Production Pattern

The winning architecture in production is probably a hybrid: an open protocol layer for merchant integration and multi-network support, with card-network-specific modules (like VIC) plugged in as payment handlers. VIC becomes an adapter, not the entire system. The protocol handles discovery, cart, and session management. The card network handles token lifecycle, credential retrieval, and transaction confirmation. Each layer does what it's best at.

The Broader Agentic Commerce Landscape

VIC and UCP aren't the only players. The agentic commerce space is moving fast, with major infrastructure bets from every layer of the stack:

  • Google's A2A protocol (now under the Linux Foundation with 50+ partners) handles agent-to-agent communication -- discovery via Agent Cards, task delegation, and real-time status updates. It's transport-agnostic (JSON-RPC, gRPC, REST bindings) and doesn't prescribe a commerce model. A2A operates at a different layer than UCP: it's how agents find and delegate work to each other, not how they buy things.
  • Anthropic's MCP (Model Context Protocol) connects AI models to external systems via tools, resources, and prompts. VIC uses MCP as its agent-to-merchant bridge. UCP defines its own protocol with REST as the primary transport today, with MCP as a potential future transport binding. MCP and UCP operate at different layers -- MCP is a model-to-system integration protocol; UCP is a commerce-domain protocol that could use MCP as one of its transports.
  • Shopify has gone all-in on agentic commerce -- far beyond wrapping existing APIs. They built entirely new infrastructure: a Catalog API for cross-merchant product search (billions of products, all Shopify stores), a Universal Cart that holds items from multiple merchants simultaneously, a Checkout Kit for embedded checkout in agent UIs, and multiple MCP servers (Catalog MCP, Storefront MCP). Shopify also co-developed UCP with Google as an open standard, with Walmart, Target, Etsy, and 20+ other retailers endorsing it. Their Agentic Storefronts feature makes all Shopify merchants discoverable in ChatGPT, Copilot, and Gemini by default.
  • Stripe launched the Agentic Commerce Suite with purpose-built payment primitives: Shared Payment Tokens (SPTs) that scope a buyer's payment method to a specific seller, amount, and time window; Agentic Network Tokens issued by Visa/Mastercard for agent-initiated payments; and the Agentic Commerce Protocol (ACP) co-developed with OpenAI. They also ship an official MCP server at mcp.stripe.com and the @stripe/agent-toolkit for LangChain, CrewAI, and Vercel AI SDK integration.
  • Adyen is building a Universal Token Vault -- a bank-grade, provider-agnostic tokenization system for agent transactions with portable tokens. They're collaborating on Google's AP2 (Agent Payments Protocol) and Visa's Trusted Agent Protocol, with a merchant-first framework that keeps merchants in control of tokenization strategies and payment routing.
  • Omnix takes a different angle entirely: source-available middleware that connects existing stores (Magento, Shopware, Shopify) to AI agents through UCP without replatforming. Instead of building new storefronts, Omnix Gateway translates existing platform APIs into UCP -- one integration, any agent. Paired with @omnixhq/ucp-js-sdk for runtime-validated schemas and @omnixhq/ucp-client for capability-aware UCP consumption, it's the adapter layer that makes UCP practical for merchants who aren't Shopify-native.

The API Contract Rule applies here: in a fragmenting ecosystem, the implementations that survive are the ones with formal, versioned, machine-readable contracts. VIC has strong security contracts but weak interface contracts. Open protocols tend to have the inverse. The ones that get both right will win.

Implementation Checklist

If you're building agentic commerce infrastructure, here's what to evaluate:

Protocol Layer

  • Multi-protocol support (REST for legacy, MCP for AI agents, A2A for agent-to-agent)
  • Formal schema governance with versioned specs
  • Automated conformance testing against the spec
  • Agent-agnostic design (no LLM framework lock-in)

Commerce Layer

  • Multi-merchant support via adapter pattern
  • Multi-tenant session isolation with idempotency
  • Payment network abstraction (not locked to one rail)
  • Full checkout lifecycle: search → cart → totals → shipping → payment → order

Payment Security

  • Tokenized credentials (never raw PANs in agent context)
  • Just-in-time credential retrieval (elicitation pattern or equivalent)
  • Step-up authentication for high-value purchases
  • Transaction confirmation loop back to the payment provider

Observability

  • Full request/response logging for all payment API calls
  • Agent decision audit trail
  • Credential access logging with session correlation
  • Alerting on checkout abandonment and payment failures

The Integration Maestro Perspective

The API Contract Rule: The strength of an integration is determined by the precision of its contract — not the sophistication of its implementation.

Visa's VIC reference agent is an impressive demonstration of payment security engineering. The token lifecycle, the MLE encryption, the FIDO2 passkeys — this is what 60 years of payment infrastructure experience looks like when applied to AI agents.

But a payment security demo is not a commerce protocol. Production agentic commerce needs multi-merchant discovery, multi-network payments, formal schema governance, and session isolation that doesn't rely on global Python variables.

The right mental model: VIC is a payment handler adapter for an open commerce protocol — not a replacement for one. The future architecture has an open protocol layer (UCP, or something like it) handling the commerce lifecycle, with Visa's VIC, Mastercard's equivalent, and every other payment network plugged in as adapters.

Related rules: The API Contract Rule · The Schema Drift Trap · The Observability Rule · Fallback-First Design

Related articles: REST vs SOAP vs GraphQL: What Wins for Integrations in 2025? · Polling vs Webhooks: How to Choose the Right Integration Trigger

Enjoying this article?

Get more deep dives on integration architecture delivered to your inbox.

Artemii Karkusha
Artemii Karkusha

Integration Architect

Artemii Karkusha is an integration architect focused on ERP, eCommerce, and high-load system integrations. He writes about integration failures, architectural trade-offs, and performance patterns.

Came from LinkedIn or X? Follow me there for more quick insights on integration architecture, or subscribe to the newsletter for the full deep dives.