Agent Commerce API
Make your storefront machine-readable for AI shopping agents: the discovery manifest, llms.txt, robots.txt rules, and the anonymous, market-aware catalog read-API — endpoints, request parameters, and example responses.
Overview
Agent Commerce is the discoverability and read-API layer that lets AI shopping agents — assistants like ChatGPT, Claude, and Perplexity, and the shopping tools built on top of them — find, understand, and query a Cartly storefront's catalog without authentication. It is on by default for every shop and pairs with the storefront's existing Product/Collection JSON-LD (see below) and sitemap. A shop can opt out from Settings → Agent Commerce in the admin — see the Help Center article for the merchant-facing view.
Everything documented here is anonymous and read-only: there is no write path, no cart, and no checkout capability exposed to an agent.
Discovery: the Manifest and llms.txt
Every shop publishes a machine-readable manifest at GET /.well-known/agent-commerce.json (proxied from GET /shops/:shopId/agent/v1/manifest) describing the shop, its markets, its structured-data support, and its catalog endpoint:
{
"spec": "cartly-agent-commerce/0.1",
"agent_ready": true,
"shop": {
"name": "Example Store",
"url": "https://your-store.mycartly.pro",
"logo": "https://your-store.mycartly.pro/logo.png",
"currency": "USD"
},
"markets": [
{ "code": "US", "currency": "USD", "locales": ["en"] }
],
"structured_data": {
"product_jsonld": true,
"sitemap": "https://your-store.mycartly.pro/sitemap.xml"
},
"endpoints": {
"catalog": "https://your-store.mycartly.pro/shops/<shop_id>/agent/v1"
},
"policies": {
"returns": "https://your-store.mycartly.pro/pages/returns",
"shipping": "https://your-store.mycartly.pro/pages/shipping",
"terms": "https://your-store.mycartly.pro/terms",
"privacy": "https://your-store.mycartly.pro/privacy"
},
"capabilities": { "browse": true, "price": true, "availability": true, "cart": false, "checkout": false },
"usage": { "rate_limit": "60/min", "pii": "none" }
}When a shop has opted out, the manifest still returns 200 (never a 404) with a minimal body — just spec, shop, and "agent_ready": false — so an agent learns "found, but disabled" and stops probing instead of retrying a missing endpoint.
A plain-language companion is published at GET /llms.txt, following the llms.txt convention: a short summary with links to the storefront, sitemap, catalog API, and published policies:
# Example Store
> Online store. Products, prices and availability are machine-readable.
## Links
- [Storefront](https://your-store.mycartly.pro)
- [Sitemap](https://your-store.mycartly.pro/sitemap.xml)
- [Catalog API](https://your-store.mycartly.pro/shops/<shop_id>/agent/v1)
## Policies
- [privacy](https://your-store.mycartly.pro/privacy)
- [returns](https://your-store.mycartly.pro/pages/returns)
- [shipping](https://your-store.mycartly.pro/pages/shipping)
- [terms](https://your-store.mycartly.pro/terms)Both endpoints are cacheable (Cache-Control: public, max-age=300) and always return 200.
robots.txt Rules for AI Crawlers
Every storefront's /robots.txt carries an explicit User-agent block for the major AI crawlers — GPTBot, OAI-SearchBot, ChatGPT-User, PerplexityBot, Google-Extended, and ClaudeBot — separate from the wildcard rules general search engines see:
# AI agents (per-shop opt-out via agent_ready)
User-agent: GPTBot
Allow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: ClaudeBot
Allow: /When the shop opts out, every AI-agent User-agent block flips to Disallow: / while the general User-agent: * block — the one search engines read — is untouched.
Rich Structured Data (JSON-LD)
Product pages emit one complete schema.org/Product node: name, description, image, brand, a per-variant Offer (SKU, GTIN, price, availability), an AggregateOffer spanning all variants, and an aggregateRating once the product has reviews. Collection pages emit an ItemList of their products; other pages emit a BreadcrumbList. This is the same structured data that powers search-engine rich results — AI agents parse it too.
Unlike the read-API below, JSON-LD emission is not gated by the Agent Commerce opt-out: a merchant who opts out still keeps full structured data for Googlebot and other search engines — opting out only turns off the AI-agent-specific surfaces (manifest, llms.txt, read-API, AI-crawler robots.txt rules).
The Anonymous Catalog Read-API
Base path: /shops/:shopId/agent/v1. No authentication or API key is required. Every endpoint below honors the shop's Agent Commerce opt-out: once a shop has opted out, every read-API request returns 403 with {"agent_ready": false}.
| Method & Path | Description |
|---|---|
GET /shops/:shopId/agent/v1/products | List published, active products |
GET /shops/:shopId/agent/v1/products/:handle | Full detail for one product |
GET /shops/:shopId/agent/v1/collections | List active collections |
GET /shops/:shopId/agent/v1/collections/:handle | One collection with its products |
List Products
GET /shops/:shopId/agent/v1/products
Query parameters:
market— a market country code; prices are returned in that market's presentment currency. Omit it to get the shop's primary market (or its base currency, if no market is configured)limit(aliasfirst) — page size, default 50, max 100cursor(aliasafter) — opaque keyset cursor read from a previous response'snext_cursorcollection— filter to one collection by handleq— case-insensitive title search
GET /shops/<shop_id>/agent/v1/products?market=US&limit=2
{
"products": [
{
"handle": "hydrating-serum",
"title": "Hydrating Serum",
"url": "https://your-store.mycartly.pro/products/hydrating-serum",
"image": "https://your-store.mycartly.pro/media/serum.jpg",
"brand": "Example Brand",
"price": { "amount_minor": 2900, "amount": "29.00", "currency": "USD" },
"price_range": {
"low": { "amount_minor": 2900, "amount": "29.00", "currency": "USD" },
"high": { "amount_minor": 3900, "amount": "39.00", "currency": "USD" }
},
"availability": "in_stock"
}
],
"next_cursor": "ODRhYjM4MDktNGRkYi00MTdiLThhZTAtNDkzZTQxMTJlOTE2"
}price_range only appears when a product's variants span more than one distinct price; price is always the minimum. availability is one of in_stock, low_stock, or out_of_stock — Cartly never returns an exact quantity to an anonymous caller. The last page omits next_cursor (empty string).
Get a Product
GET /shops/:shopId/agent/v1/products/:handle
{
"handle": "hydrating-serum",
"title": "Hydrating Serum",
"url": "https://your-store.mycartly.pro/products/hydrating-serum",
"image": "https://your-store.mycartly.pro/media/serum.jpg",
"brand": "Example Brand",
"price": { "amount_minor": 2900, "amount": "29.00", "currency": "USD" },
"availability": "in_stock",
"description": "A lightweight, fast-absorbing serum...",
"variants": [
{
"sku": "SER-30ML",
"gtin": "0123456789012",
"title": "30ml",
"options": { "Size": "30ml" },
"price": { "amount_minor": 2900, "amount": "29.00", "currency": "USD" },
"availability": "in_stock",
"url": "https://your-store.mycartly.pro/products/hydrating-serum?variant=<variant_id>"
}
],
"shipping": { "available": true, "region": "US" },
"returns": { "url": "https://your-store.mycartly.pro/pages/returns" },
"rating": { "value": 4.8, "count": 132 }
}shipping, returns, and rating are each omitted entirely (not emitted as empty objects) when the shop has no active shipping zone, no published returns page, or the product has no reviews yet — an honest degrade rather than invented data.
List and Get Collections
GET /shops/:shopId/agent/v1/collections lists active collections (limit/first plus offset):
{
"collections": [
{ "handle": "skincare", "title": "Skincare", "url": "https://your-store.mycartly.pro/collections/skincare" }
]
}GET /shops/:shopId/agent/v1/collections/:handle returns one collection with its products, in the same flat shape as the products-list endpoint:
{
"handle": "skincare",
"title": "Skincare",
"url": "https://your-store.mycartly.pro/collections/skincare",
"products": [ { "handle": "hydrating-serum", "...": "..." } ]
}Opt-Out, Rate Limits & Caching
- Opt-out — when a merchant turns Agent Commerce off (Settings → Agent Commerce), every read-API request returns
403 {"agent_ready": false}. The discovery manifest still returns200withagent_ready: false, so an agent gets a definite answer instead of a broken lookup. - Rate limit — roughly 60 requests/min per caller, matching the
usage.rate_limitfield advertised in the manifest. - Caching — every read-API response sets
Cache-Control: public, max-age=60, s-maxage=300; the manifest and llms.txt usepublic, max-age=300. Respect these headers rather than polling faster than necessary.