Building AI Shopping Agents That Actually Buy: A UCP Developer Guide
A technical guide to building AI shopping agents with real purchase capability using UCP. Covers discovery, cart management, checkout, payment token exchange, authentication, and error handling.
From Assistant to Buyer: What UCP Unlocks for Agent Developers
Most AI shopping assistants today are elaborate search engines. They can find products, compare options, summarize reviews, and then hand the user off to a browser tab to actually complete the purchase. That handoff is where conversion dies.
UCP eliminates the handoff. The Universal Commerce Protocol gives an AI agent a structured, authenticated pathway to discover merchants, query catalogs, manage carts, and complete checkout without ever leaving the agent context. This guide walks through the full technical architecture for building an agent that can actually buy things.
If you are looking for a quick overview of which platforms and SDKs currently support UCP, the UCPList directory is a good starting point. This post goes deeper: how to wire it all together.
The Architecture of a UCP-Enabled Agent
A UCP shopping agent has four distinct layers:
Discovery layer finds merchants and retrieves their capability manifests. Catalog layer queries product data, availability, and pricing. Cart layer manages session state across multiple merchants. Checkout layer handles identity, payment token exchange, and order confirmation.
Each layer has a defined API surface in the UCP spec. The layers are independent: you can have a robust discovery and catalog integration without implementing checkout, which is a reasonable starting point for agents that need approval workflows before purchasing.
Discovery: Finding Merchants via .well-known/ucp
Every UCP-enabled merchant publishes a manifest at /.well-known/ucp. This file describes what the merchant supports: which UCP spec version they implement, which product categories they carry, checkout capabilities, and supported payment methods.
import { UCPClient } from '@ucp/sdk';
const client = new UCPClient();
// Discover a specific merchant
const manifest = await client.discover('https://shop.example.com');
console.log(manifest.ucpVersion); // "1.2"
console.log(manifest.capabilities); // ["catalog", "cart", "checkout"]
console.log(manifest.paymentMethods); // ["ucp-token", "stripe", "adyen"]
// Discover merchants by category using a registry
const merchants = await client.registry.search({
category: 'electronics',
capability: 'checkout',
inStock: true,
});The @ucp/sdk TypeScript package handles manifest parsing, version negotiation, and capability detection. The equivalent Python package is ucp-sdk on PyPI. Both are listed in the developer tools section of UCPList.
Querying the Catalog
Once you have a merchant's manifest, catalog queries follow a consistent GraphQL-style schema regardless of the underlying platform. This is one of UCP's core value propositions: a Shopify merchant and a custom commerce backend look identical to your agent at the catalog layer.
const catalog = await client.catalog(manifest);
const results = await catalog.search({
query: 'noise canceling headphones',
filters: {
priceMax: 35000, // cents
inStock: true,
},
limit: 10,
});
for (const product of results.items) {
console.log(product.id, product.title, product.price.amount);
console.log(product.variants); // sizes, colors, etc.
console.log(product.availability.quantity);
}Price values in UCP are always integers in the smallest currency unit (cents for USD) to avoid floating-point ambiguity. Your agent should store and compare prices this way throughout the session.
Cart Management
UCP carts are server-side sessions scoped to a merchant. Creating a cart returns a cartId that you will use through to checkout. Carts have a TTL (typically 30 minutes, but specified in the manifest) and must be refreshed if the user's session extends.
const cartSession = await client.cart.create(manifest, {
agentId: 'your-agent-id',
sessionId: 'user-session-abc123',
});
// Add items
await cartSession.addItem({
productId: product.id,
variantId: product.variants[0].id,
quantity: 1,
});
// Check current state (prices may have changed)
const cart = await cartSession.get();
console.log(cart.items, cart.subtotal, cart.estimatedTax);
// Handle the case where something changed since you queried the catalog
if (cart.warnings.length > 0) {
for (const warning of cart.warnings) {
// warning.type: "PRICE_CHANGED" | "OUT_OF_STOCK" | "QUANTITY_REDUCED"
console.log(warning.type, warning.productId, warning.details);
}
}Always re-check the cart state before presenting a purchase confirmation to the user. Prices and availability change between catalog query and checkout.
Checkout and Payment Token Exchange
The checkout flow separates identity verification from payment. Your agent first initiates checkout to get a checkout session, then exchanges a consumer-authorized payment token to complete the purchase.
// Initiate checkout
const checkoutSession = await client.checkout.initiate(cartSession, {
shippingAddress: {
line1: '123 Main St',
city: 'San Francisco',
state: 'CA',
postalCode: '94105',
country: 'US',
},
shippingMethod: 'standard',
});
// Exchange a payment token
// The consumer pre-authorizes a payment token with your agent platform
// This token is scoped: it can only be used for this checkout session
const order = await client.checkout.complete(checkoutSession, {
paymentToken: consumerPaymentToken,
confirmationRequired: false, // set true for high-value purchases
});
console.log(order.orderId, order.status, order.estimatedDelivery);The payment token model is critical to understand. Consumers do not give agents their raw payment credentials. Instead, they pre-authorize a scoped token through their wallet provider (Stripe, Apple Pay, etc.) that specifies: maximum spend amount, permitted merchant categories, and an expiry window. Your agent receives this token and can only use it within those constraints.
Agent Authentication and Scoped Tokens
Agents authenticate to the UCP network with two credentials: an agent identity token (who you are) and a consumer authorization token (permission to act on behalf of a specific user). Both are JWTs with standard UCP claims.
const ucpClient = new UCPClient({
agentId: process.env.UCP_AGENT_ID,
agentSecret: process.env.UCP_AGENT_SECRET,
});
// Attach consumer authorization for a specific session
const sessionClient = ucpClient.withConsumerAuth(consumerAuthToken);
// All subsequent calls carry both credentials
const manifest = await sessionClient.discover('https://shop.example.com');Scoped tokens are the right pattern for production agents. An agent with broad payment authority is a liability. Issue tokens scoped to a purchase category and a spend limit, and expire them aggressively.
MCP Integration
If your agent is built on the Model Context Protocol, UCP has a native MCP server that exposes shopping actions as MCP tools. This means your LLM can call ucp_search_products, ucp_add_to_cart, and ucp_checkout directly through the tool use interface, without custom integration code in your agent loop.
{
"mcpServers": {
"ucp": {
"command": "npx",
"args": ["@ucp/mcp-server"],
"env": {
"UCP_AGENT_ID": "your-agent-id",
"UCP_AGENT_SECRET": "your-secret"
}
}
}
}With this configuration, your Claude or GPT-based agent gains shopping tools automatically. The MCP server handles manifest discovery, catalog queries, cart state, and checkout as tool implementations. You can see which agent frameworks have published UCP MCP integrations in the agent integrations category on UCPList.
Error Handling Patterns
Three failure modes deserve explicit handling in any production agent:
Out of stock after add: The cart API will return a QUANTITY_REDUCED or OUT_OF_STOCK warning on cart.get(). Surface this to the user before confirming purchase, never silently drop the item.
Price change: If a product's price increases between catalog query and checkout, the cart will reflect the new price. Always show the user the final cart total, not the originally displayed price.
Payment failure: The checkout.complete() call will throw a UCPPaymentError with a code property. Codes include INSUFFICIENT_FUNDS, TOKEN_EXPIRED, MERCHANT_DECLINED, and NETWORK_ERROR. Each requires a different recovery path. TOKEN_EXPIRED means you need a new consumer authorization; the others may be retriable or require user intervention.
try {
const order = await client.checkout.complete(checkoutSession, { paymentToken });
} catch (err) {
if (err instanceof UCPPaymentError) {
switch (err.code) {
case 'TOKEN_EXPIRED':
return requestNewConsumerAuth(userId);
case 'MERCHANT_DECLINED':
return notifyUser('The merchant declined this order. Please contact support.');
case 'NETWORK_ERROR':
return retryWithBackoff(() => client.checkout.complete(checkoutSession, { paymentToken }));
}
}
throw err;
}Testing Your Integration
The UCP conformance test suite at @ucp/conformance gives you a mock merchant server and a set of scenario tests covering the full purchase flow, including error conditions. Run it against your integration before going to production:
npx @ucp/conformance test --agent-url http://localhost:3000/ucp-agentThe test suite covers: discovery, catalog pagination, cart creation, item add/remove, price change simulation, checkout initiation, payment token exchange, and order confirmation. A passing conformance suite means your agent handles the protocol correctly. It does not mean your UX is good, so test that separately.
Best Practices
Always confirm before purchasing. Show the user a summary with merchant, items, total, and shipping before calling checkout.complete(). Even automated reorder agents should log what they purchased and surface it to the user immediately.
Respect rate limits. Merchant manifests include rate limit headers. Your catalog search layer should cache results aggressively (5-10 minutes for most product data) and back off on 429 responses.
Handle partial cart failures gracefully. If a user wants items from three merchants and one fails, complete the other two and report the failure clearly. Do not abort the entire session.
Keep consumer auth tokens short-lived. 15-30 minute expiry windows are appropriate for interactive sessions. Background reorder agents should use single-use tokens.
The full spec reference and SDK documentation live at ucp.dev. For a browsable list of UCP-enabled merchants to test against, the UCPList merchant directory is the most current source available.
Read next
Headless commerce stores separate the front end from the commerce engine. Here is how UCP fits into headless stacks and what changes when your agent talks to a headless merchant.
An honest guide to the UCP developer tools worth knowing in 2026, from specs and conformance tests to directories and SDKs.
B2B commerce has purchase orders, net terms, approval workflows, and customer-specific pricing. Here is what enterprise UCP looks like for agent developers.