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
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:

| 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:

The credential never touches the AI agent in plaintext. Here's the actual flow:
- User enrolls their card PAN into Visa Token Service (encrypted with JWE)
- VTS provisions a token with
presentationType: ["AI_AGENT"]— a new token type specifically for agent commerce - The token gets enrolled in VIC (Visa Intelligent Commerce)
- At checkout, VIC creates an intent with FIDO assurance data from the user's passkey
- VIC retrieves tokenized credentials — a dynamic card number, expiry, and cryptographic CVV
- These credentials flow through MCP elicitation to the merchant
- 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-tokenheader - FIDO2/WebAuthn passkeys: Biometric step-up for payment authorization
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.
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.comand the@stripe/agent-toolkitfor 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-sdkfor runtime-validated schemas and@omnixhq/ucp-clientfor 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.

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.
Related Articles
Polling vs Webhooks: How to Choose the Right Integration Trigger
The polling vs webhooks debate has a clear winner in most integration projects — and it's neither. Learn the real trade-offs, the hybrid pattern that survives production, and a 5-question decision framework for choosing the right trigger strategy.
A 2 AM Integration Failure That Changed How I Design Systems Forever
Black Friday exposed a hidden architectural mistake: using eCommerce as the integration bridge. Here’s why it breaks at scale — and the rule I follow now.
Idempotency: The #1 Rule of Safe Integrations Teams Ignore
Duplicate requests don’t look like outages — they look like “everything worked” twice. Learn how idempotency prevents double orders, double charges, and event replays that silently break production systems.
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.