Protocol Specification
The @opencommerceprotocol/spec package contains TypeScript types, JSON schemas, and constants that define the Open Commerce Protocol. Everything in OCP starts here.
Installation
npm install @opencommerceprotocol/spec
import { OCPManifest, OCPProduct, OCP_VERSION } from '@opencommerceprotocol/spec';OCP Manifest
The merchant discovery manifest served at /.well-known/ocp.json. This is the single file that makes any e-commerce site agent-ready.
{
"version": "1.0",
"merchant": {
"name": "My Store",
"url": "https://mystore.com",
"currency": "USD",
"locale": "en",
"logo": "https://mystore.com/logo.png",
"description": "Quality products for everyone",
"contact": "support@mystore.com"
},
"capabilities": {
"catalog": true,
"search": true,
"cart": true,
"checkout": "redirect",
"orders": false,
"returns": false
},
"discovery": {
"feed": "https://mystore.com/ocp/products.jsonl",
"feed_format": "jsonl",
"feed_updated": "2026-03-01T00:00:00Z",
"total_products": 500
},
"interact": {
"runtime": "https://cdn.opencommerceprotocol.org/runtime/v1/ocp-runtime.min.js",
"webmcp": true,
"tools": ["search_products", "get_product", "add_to_cart", "begin_checkout"]
},
"bridge": {
"mcp": "https://mystore.com/mcp",
"ucp": "https://mystore.com/.well-known/ucp",
"acp": "https://mystore.com/acp",
"a2a": "https://mystore.com/.well-known/agent.json"
},
"payments": {
"handlers": ["card", "paypal", "apple_pay"],
"currencies": ["USD", "EUR"]
},
"permissions": {
"requires_human_checkout": true,
"agent_purchase_limit": 500,
"rate_limit": "100/hour"
},
"shipping": {
"regions": ["US", "CA", "GB"],
"methods": ["standard", "express", "overnight"],
"free_above": 50
}
}Manifest Field Reference
versionstringrequiredProtocol version. Always "1.0".merchant.namestringrequiredStore name.merchant.urlURIrequiredCanonical store URL.merchant.currencystringDefault ISO 4217 currency code.merchant.logoURIStore logo URL.merchant.descriptionstringShort store description for agent context.merchant.contactstringSupport email or URL.capabilities.catalogbooleanWhether the store exposes a product catalog.capabilities.searchbooleanWhether product search is supported.capabilities.cartbooleanWhether cart operations are supported.capabilities.checkout"full" | "escalate" | "redirect" | "none"Checkout mode. "redirect" sends user to store checkout page.capabilities.ordersbooleanWhether order tracking is supported.capabilities.returnsbooleanWhether returns are supported.discovery.feedURIURL to the product feed (JSONL, JSON, or CSV).discovery.feed_format"jsonl" | "json" | "csv"Feed format. Default: jsonl.discovery.feed_updatedISO 8601When the feed was last updated.discovery.total_productsnumberTotal products in the feed.interact.runtimeURIOCP browser runtime script URL.interact.webmcpbooleanWhether WebMCP (Chrome 146+) is supported.interact.toolsstring[]Which OCP tools to expose. If omitted, all 11 are available.bridge.*URIProtocol bridge endpoint URLs (mcp, ucp, acp, a2a).payments.handlersstring[]Accepted payment methods (card, paypal, apple_pay, etc.).payments.currenciesstring[]Accepted ISO 4217 currency codes.permissions.requires_human_checkoutbooleanWhether a human must complete checkout.permissions.agent_purchase_limitnumberMaximum order value an agent can initiate.permissions.rate_limitstringRate limit string, e.g. "100/hour".shipping.regionsstring[]ISO country codes the merchant ships to.shipping.methodsstring[]Shipping methods offered.shipping.free_abovenumberOrder value above which shipping is free.Product Feed Format
Products are served as a JSONL feed at /ocp/products.jsonl — one JSON object per line. Each line is an OCPProduct.
{"id":"prod-001","name":"Premium Wireless Headphones","price":149.99,"currency":"USD","url":"https://mystore.com/products/headphones","availability":"in_stock","description":"Studio-quality sound with active noise cancellation.","image":"https://mystore.com/images/headphones.jpg","category":"Electronics","agent_notes":"Best-seller. Ideal for frequent flyers and open-plan offices. 30-hour battery.","variants":[{"id":"var-black","name":"Black","price":149.99,"availability":"in_stock"},{"id":"var-white","name":"White","price":149.99,"availability":"limited"}]}
{"id":"prod-002","name":"USB-C Hub","price":49.99,"currency":"USD","url":"https://mystore.com/products/usb-hub","availability":"in_stock","category":"Electronics","agent_notes":"7-in-1. Works with all USB-C laptops. HDMI 4K@60Hz."}Key Fields
idstringrequiredUnique product identifier.namestringrequiredProduct name.pricenumberrequiredCurrent price.currencystringrequiredISO 4217 currency code.urlURIrequiredProduct page URL.availabilityOCPAvailabilityStock status. Preferred over deprecated in_stock boolean.descriptionstringHuman-readable product description.agent_notesstringAgent-optimized description in natural language. Explains product for AI agents.imageURIPrimary product image URL.categorystringPrimary product category.variantsVariant[]Product variants with id, name, price, and availability.specsProductSpec[]Typed specifications for B2B comparison (name, value, unit, group).bulk_pricingBulkPricingTier[]Volume discount tiers (min_quantity, price).promotionsPromotion[]Active promotions with discount type, value, and optional code.Availability States
The OCPAvailability type replaces the deprecated boolean in_stock field with richer stock status information.
in_stockAvailable to purchase now.out_of_stockCurrently unavailable.pre_orderNot yet released, can be ordered.backorderTemporarily out of stock, will ship when restocked.limitedLow stock — may sell out soon.check_siteAgent should direct the user to the product page for current status.Standard Tools
OCP defines 11 standard tools that agents use to interact with a store. Declare which tools your store supports via interact.tools in the manifest.
search_productsSearch the product catalog by keyword, category, or price range.get_productGet detailed product information by ID.get_product_qaAsk a specific question about a product.compare_productsCompare multiple products side by side.add_to_cartAdd a product to the cart with quantity and optional variant.get_cartRetrieve current cart contents and totals.update_cartUpdate cart item quantities or remove items.begin_checkoutStart a checkout session with optional prefill data.check_availabilityCheck product stock status, optionally by location.check_checkout_statusPoll a checkout session for completion status.get_promotionsGet active promotions, optionally filtered by product or category.Handler Signatures
import type { OCPHandlers } from '@opencommerceprotocol/spec';
const handlers: Partial<OCPHandlers> = {
search_products: async ({ query, category, min_price, max_price, in_stock, limit, offset, sort }) => {
// Returns: ProductResult[]
},
get_product: async ({ id }) => {
// Returns: OCPProduct
},
get_product_qa: async ({ id, question }) => {
// Returns: QAResult { answer, confidence?, sources? }
},
compare_products: async ({ ids, attributes }) => {
// Returns: ComparisonResult { products, comparison?, spec_matrix?, recommendation? }
},
add_to_cart: async ({ product_id, quantity, variant_id, agent_context }) => {
// Returns: CartResult { success, cart, message? }
},
get_cart: async () => {
// Returns: Cart { items, total, currency, session_id? }
},
update_cart: async ({ items }) => {
// Returns: Cart
},
begin_checkout: async ({ prefill, callback_url, agent_context }) => {
// Returns: CheckoutResult { checkout_url, session_id, expires_at?, ... }
},
check_availability: async ({ id, location, quantity }) => {
// Returns: AvailabilityResult { availability, in_stock, quantity?, ... }
},
check_checkout_status: async ({ session_id }) => {
// Returns: CheckoutStatusResult { session_id, status, order_id?, message?, ... }
},
get_promotions: async ({ product_id, category }) => {
// Returns: PromotionsResult { promotions: Promotion[] }
},
};Agent Context
Orchestrating agents (e.g. ChatGPT, Amazon) can pass buyer context when adding to cart or beginning checkout. This enables cross-merchant session correlation and personalization.
import type { AgentContext } from '@opencommerceprotocol/spec';
const agentContext: AgentContext = {
agent_id: 'chatgpt-shopping',
session_ref: 'sess-abc123',
buyer_preferences: {
locale: 'en-US',
shipping_country: 'US',
size: 'M',
color: 'blue',
loyalty_ids: [{ program: 'store-rewards', member_id: 'MBR-001' }],
},
};Checkout Handoff
The begin_checkout tool accepts pre-fill data and returns a checkout URL. Agents redirect or embed this URL so the user completes payment.
import type { CheckoutPrefill, CheckoutResult } from '@opencommerceprotocol/spec';
const prefill: CheckoutPrefill = {
email: 'buyer@example.com',
name: 'Jane Doe',
shipping_address: {
line1: '123 Main St',
city: 'Austin',
postal_code: '78701',
country: 'US',
},
payment_method_hint: 'apple_pay',
};
// CheckoutResult returned by begin_checkout:
// {
// checkout_url: string;
// session_id: string;
// expires_at?: string;
// prefilled_fields?: string[];
// checkout_type?: 'full_page' | 'embedded' | 'api';
// status_url?: string;
// estimated_total?: { subtotal, tax?, shipping?, total, currency };
// }Checkout Modes
fullAgent handles the entire checkout flow via API.redirectAgent gets a checkout URL and sends the user to the store.escalateAgent hands off to a human agent or support channel.noneNo checkout supported — catalog browsing only.Constants
import {
OCP_VERSION, // '1.0'
OCP_MANIFEST_PATH, // '/.well-known/ocp.json'
OCP_FEED_PATH, // '/ocp/products.jsonl'
OCP_DOC_PATH, // '/ocp.md'
OCP_TOOL_DESCRIPTIONS, // Record<string, string> — descriptions for all 11 tools
OCP_TOOL_NAMES, // string[] — all 11 tool names
} from '@opencommerceprotocol/spec';JSON Schemas
Three JSON Schema files are included for runtime validation of manifests, products, and tool inputs/outputs.
ocp-manifest.schema.jsonValidates the /.well-known/ocp.json manifest.ocp-product.schema.jsonValidates each product in the JSONL feed.ocp-tools.schema.jsonValidates tool input and output contracts.import { manifestSchema, productSchema } from '@opencommerceprotocol/spec';
import Ajv from 'ajv';
const ajv = new Ajv();
const validate = ajv.compile(manifestSchema);
const valid = validate(myManifest);
if (!valid) {
console.error(validate.errors);
}