/**
* Autonomous Purchase Flow — Complete Example
*
* Demonstrates the full end-to-end agentic commerce flow using all 5 MCP tools:
*
* 1. scout_inventory — Search for products
* 2. manage_cart — Create cart and add items
* 3. negotiate_terms — Negotiate capabilities, discounts, and shipping
* 4. execute_checkout — Complete the purchase with AP2 mandate chain
* 5. track_order — Track the resulting order
*
* This example simulates what an AI agent (Claude, GPT, etc.) does internally
* when a user says: "Buy me the best wireless headphones under $50."
*
* In practice, the agent calls these tools via MCP — this file shows the
* equivalent programmatic calls for understanding and testing.
*/
import { scoutInventory } from '../src/tools/scout-inventory.js';
import { manageCart } from '../src/tools/manage-cart.js';
import { negotiateTerms } from '../src/tools/negotiate-terms.js';
import { executeCheckout } from '../src/tools/execute-checkout.js';
import { trackOrder } from '../src/tools/track-order.js';
import { loadConfig } from '../src/types.js';
import { CheckoutSessionManager } from '../src/ucp/checkout-session.js';
import { MandateVerifier } from '../src/ap2/verifier.js';
import { MandateStore } from '../src/ap2/mandate-store.js';
import { Guardrail } from '../src/middleware/guardrail.js';
import { FeeCollector } from '../src/middleware/fee-collector.js';
import type { ExecuteCheckoutDeps } from '../src/tools/execute-checkout.js';
async function autonomousPurchaseFlow(): Promise<void> {
console.log('=== Autonomous Purchase Flow ===\n');
const config = loadConfig();
// ─────────────────────────────────────────────
// Step 1: Scout Inventory
// The agent searches for products matching the user's request.
// "Find wireless headphones under $50" -> price_max: 5000 (cents)
// ─────────────────────────────────────────────
console.log('Step 1: Scouting inventory...');
const scoutResult = await scoutInventory({
query: 'wireless headphones',
category: 'electronics',
price_max: 5000, // $50.00 in minor units (cents)
limit: 5,
});
console.log(` Found ${scoutResult.total_count} products`);
console.log(` Has more results: ${scoutResult.has_more}`);
if (scoutResult.products.length === 0) {
console.log(' No products found. Using mock product for demonstration.\n');
}
// In a real flow, the agent would analyze the results and pick the best match.
// For this example, we use the first result or a placeholder variant ID.
const selectedVariantId =
scoutResult.products[0]?.variants[0]?.id ?? 'gid://shopify/ProductVariant/demo-001';
console.log(` Selected variant: ${selectedVariantId}\n`);
// ─────────────────────────────────────────────
// Step 2: Create Cart and Add Item
// The agent creates a new cart and adds the selected product.
// ─────────────────────────────────────────────
console.log('Step 2: Managing cart...');
// 2a. Create an empty cart
const createResult = await manageCart({ action: 'create' });
const cartId = createResult.cart_id;
console.log(` Created cart: ${cartId}`);
// 2b. Add the selected product to the cart
const addResult = await manageCart({
action: 'add',
cart_id: cartId,
variant_id: selectedVariantId,
quantity: 1,
});
console.log(` Added item. Cart now has ${addResult.item_count} item(s)`);
console.log(` Cart total: ${addResult.totals.total} ${addResult.totals.currency}\n`);
// ─────────────────────────────────────────────
// Step 3: Negotiate Terms
// The agent and merchant negotiate capabilities, discounts,
// and shipping options. The agent provides its UCP profile URL
// so the merchant knows what the agent supports.
// ─────────────────────────────────────────────
console.log('Step 3: Negotiating terms...');
const negotiateResult = await negotiateTerms(
{
cart_id: cartId,
agent_profile_url: 'https://agent.example.com/.well-known/ucp',
discount_code: 'AGENT10', // Try the agent discount code
},
config,
);
console.log(` Active capabilities: ${negotiateResult.negotiation.active_capabilities.length}`);
console.log(` Available discounts: ${negotiateResult.negotiation.available_discounts.length}`);
console.log(` Shipping options: ${negotiateResult.negotiation.shipping_options.length}`);
console.log(` Discount applied: ${negotiateResult.discount_applied}`);
if (negotiateResult.checkout_session) {
console.log(` Checkout session: ${negotiateResult.checkout_session.id}`);
console.log(` Checkout status: ${negotiateResult.checkout_session.status}`);
}
console.log();
// ─────────────────────────────────────────────
// Step 4: Execute Checkout
// The agent submits the AP2 mandate chain to complete the purchase.
//
// In a real flow:
// - The buyer's agent generates the Intent Mandate (spending limit)
// - The merchant gateway generates the Cart Mandate (locked prices)
// - The buyer's agent generates the Payment Mandate (authorized amount)
//
// All three mandates are JWS compact serialization tokens signed with ES256.
// For this example, we use placeholder tokens.
// See examples/mandate-flow.ts for the full mandate generation flow.
// ─────────────────────────────────────────────
console.log('Step 4: Executing checkout...');
// Set up the checkout execution dependencies
const sessionManager = new CheckoutSessionManager();
const verifier = new MandateVerifier(
config.ap2.verificationPublicKey ?? config.ap2.signingPrivateKey,
);
const mandateStore = new MandateStore();
const guardrail = new Guardrail();
const feeCollector = new FeeCollector({
feeRate: config.gateway.feeRate,
walletAddress: config.gateway.feeWalletAddress,
});
const checkoutDeps: ExecuteCheckoutDeps = {
sessionManager,
verifier,
mandateStore,
guardrail,
feeCollector,
storefrontAPI: null,
};
// For demonstration, create a checkout session and populate it to
// "ready_for_complete" status. In production, the negotiate_terms and
// manage_cart tools progressively build this session.
const demoSession = sessionManager.create('USD');
sessionManager.update(demoSession.id, {
line_items: [
{
id: 'line-001',
product_id: 'gid://shopify/Product/100',
variant_id: selectedVariantId,
title: 'Wireless Headphones',
quantity: 1,
unit_amount: 2999,
total_amount: 2999,
type: 'product',
},
],
buyer: { email: 'buyer@example.com', first_name: 'Jane', last_name: 'Doe' },
shipping_address: {
line1: '123 Main St',
city: 'San Francisco',
province: 'CA',
postal_code: '94105',
country: 'US',
},
payment_instruments: [
{
handler_id: 'shopify_payments',
type: 'card',
display: { brand: 'Visa', last_digits: '4242' },
},
],
});
console.log(` Demo session status: ${sessionManager.getStatus(demoSession.id)}`);
// In production, these would be real JWS tokens from the AP2 mandate flow.
// The execute_checkout tool verifies the full chain before proceeding.
const checkoutResult = await executeCheckout(
{
checkout_id: demoSession.id,
intent_mandate: 'eyJhbGciOiJFUzI1NiIsInR5cCI6Im1hbmRhdGUrand0In0.intent_placeholder',
cart_mandate: 'eyJhbGciOiJFUzI1NiIsInR5cCI6Im1hbmRhdGUrand0In0.cart_placeholder',
payment_mandate: 'eyJhbGciOiJFUzI1NiIsInR5cCI6Im1hbmRhdGUrand0In0.payment_placeholder',
},
checkoutDeps,
);
if (checkoutResult.success) {
console.log(` Checkout successful!`);
console.log(` Order ID: ${checkoutResult.order?.id}`);
console.log(` Order total: ${checkoutResult.order?.totals.total} ${checkoutResult.order?.totals.currency}`);
console.log(` Checkout URL: ${checkoutResult.checkout_url}`);
console.log(` Platform fee: ${checkoutResult.fee?.fee_amount} ${checkoutResult.fee?.currency}`);
} else {
// In this demo, mandate verification will fail because we used placeholder tokens.
// This is expected behavior -- the gateway rejects unverifiable mandates.
console.log(` Checkout returned errors (expected with placeholder mandates):`);
checkoutResult.errors?.forEach((err) => console.log(` - ${err}`));
}
console.log();
// ─────────────────────────────────────────────
// Step 5: Track Order
// After the purchase, the agent can track the order status
// and fulfillment information.
// ─────────────────────────────────────────────
console.log('Step 5: Tracking order...');
const orderId = checkoutResult.order?.id ?? 'demo-order-001';
const trackResult = await trackOrder({ order_id: orderId });
if (trackResult.found) {
console.log(` Order status: ${trackResult.order?.status}`);
console.log(` Tracking: ${trackResult.tracking?.carrier} ${trackResult.tracking?.tracking_number}`);
console.log(` Estimated delivery: ${trackResult.estimated_delivery}`);
} else {
console.log(` Order not found (expected for demo order ID)`);
}
console.log('\n=== Flow Complete ===');
}
// Run the example
autonomousPurchaseFlow().catch((err) => {
console.error('Flow failed:', err);
process.exit(1);
});