Goal
Build a service that a shopper can talk to. The shopper asks for a product in plain language, the agent searches your catalog, and the agent adds the chosen Product to a Cart in your Project. You will scaffold the backend with a plugin, run the service locally, and verify that a chat turn creates a real Cart.
The blueprint provides the agent itself: the turn loop, the tools, and the guardrails. What it leaves for you is the backend, which is the layer that turns an agent's request for a product into a commercetools API call. The plugin in this tutorial generates that layer.
The blueprint defines two agents, and the plugin can scaffold either:
- A shopping agent serves a customer over a
StorefrontBackend. It searches the catalog, compares Products, fills a Cart, and answers questions about policies. This tutorial builds one. - A merchant agent serves store staff over a
MerchantBackend. It explains performance, maintains listings, manages Inventory, and stages price changes that apply only after someone approves them.
Prerequisites
-
Python 3.13, which is the version the reference implementation is run with.
-
An API Client for your Project with required scopes. Create it with every scope the agent will need, because the scopes of an API Client cannot be changed after you create it. To take payments through Checkout, add
manage_sessionsat the same time. -
An Anthropic API key.
-
A Tax Category on every Product a shopper can buy. Without one, Cart creation fails, and the error appears when a shopper tries to buy rather than when you save the Product.
-
At least a few published Products with a Price in the currency you plan to use.
-
No API Extension on Carts with an unguarded
custom(fields(...))trigger condition. Such a condition cannot be evaluated against a Cart that carries no Custom Object, and it fails every Cart write in the Project rather than only the agent's. Check this before your first Cart write against a shared Project. -
Claude Code, which runs the scaffolding command.
-
The commercetools plugin, installed from its own marketplace. In a Claude Code session, run:
/plugin marketplace add commercetools/commercetools-anthropic-agents /plugin install commercetools-commerce-agent@commercetools-anthropic-agentsThis gives you the/scaffold-commercetools-agentcommand and a Skill calledcommercetools-agent-backend, which loads whenever you edit the generated backend code.
Check your catalog
The scaffolding command asks how your catalog is shaped, and the answers change the code it writes. Look at your Products before you start, so that you can answer accurately:
- Do your Product Variants represent real choices, such as size or color, or near-duplicates? A family whose Variants are identical on every Attribute is duplicate data rather than a set of choices, and the agent should present it as a single Product.
- Which Attributes are searchable? A search filter on an Attribute whose
isSearchableisfalsereturns zero matches without an error, so a shopper asking for a red shirt gets "no results" rather than a configuration error. Check the two or three Attributes a shopper is most likely to name. - Are any Product Discounts active? If so, the agent must read the discounted price rather than the list price, or it quotes the wrong number.
- Which locales are your Product names authored under? Requesting a single locale returns null rather than a fallback when a Product has no value for that exact key, so a Product authored under
enrenders with no title in a storefront runningen-US.
Scaffold the backend
Run the command, and describe what you want to build:
/scaffold-commercetools-agent a shopping agent for my-project-key
The command asks its questions in one message, prefilled from anything it can already see about your Project. Answer with what you found in the previous step. Skip a question to accept its default.
CLAUDE.md, generates the shared commercetools infrastructure and a StorefrontBackend subclass, and runs your linter and type checker over the result.Configure the service
Copy the example environment file the scaffold generates, and fill in your own values:
cp .env.example .env
The price selection variables matter more than they look:
CTP_PROJECT_KEY=my-project-key
CTP_CLIENT_ID=
CTP_CLIENT_SECRET=
CTP_AUTH_URL=
CTP_API_URL=
CT_CURRENCY=USD
CT_COUNTRY=US
CT_LOCALE=en-US
ANTHROPIC_API_KEY=
CT_CURRENCY and CT_COUNTRY drive price selection, and CT_LOCALE drives the name. Each one governs a different part of the response, and neither raises an error when it's missing. Omit the currency or country and Products come back without a price. Omit the locale and they come back without a name. Leave all three unset and a Product Search returns nothing but an id per result. In each case the catalog looks empty or broken rather than misconfigured, which makes this worth checking first when results look wrong.Run the service
Create a virtual environment, install the dependencies, and start the service:
python3.13 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
uvicorn service.main:app --port 8000
The service exposes a session endpoint and a chat endpoint. A session binds the shopper before any conversation happens, which is why no later request carries a customer id:
| Route | Purpose |
|---|---|
POST /api/session | Starts a session. A customer id makes the shopper a member, and no id makes them a guest. |
POST /api/chat | Sends one conversational turn, streamed back as events. |
GET /api/cart | Returns the Cart belonging to the session. |
GET /api/products | Returns the catalog. |
Test the agent
Start a session, and keep the session id it returns:
curl -X POST http://localhost:8000/api/session
Send a turn that asks for something you know is in your catalog, passing the session id as a header:
curl -N -X POST http://localhost:8000/api/chat \
-H "X-Session-Id: <your-session-id>" \
-H "Content-Type: application/json" \
-d '{"message": "I am looking for a blue shirt"}'
The response streams back as events. The agent searches your catalog and replies with the Products it found, including their prices.
Then ask it to add one to the Cart, and read the Cart back:
curl http://localhost:8000/api/cart -H "X-Session-Id: <your-session-id>"
If the agent replies that it found nothing, check price selection and Attribute searchability before you look at the agent. Both fail silently, and both look like an empty catalog.
Add caller authentication
client_credentials, which means the service has no idea who's talking to it beyond the session id it issued.anonymousId of a Cart. Don't put a guest identifier in customerId, which only accepts a registered Customer: commercetools accepts the write and leaves both fields unset, which is difficult to diagnose later.Extend the backend
commercetools-agent-backend Skill loads and applies the rules that keep it correct. It covers platform behaviors that are easy to get wrong because they don't raise an error. For example:name(locale:)returns null rather than a fallback when a Product has no value for that exact locale. ReadnameAllLocalesand fall back across the locales you support.- A missing
availabilityon a ProductVariant means no InventoryEntry exists for it, which isn't the same as the Product being out of stock. - A write that changes a Price must target the
idthat price selection resolved, rather than a reconstruction of which Price should apply.
Further learning
Treat the scaffolded code as a starting point your team reviews, tests, and owns. The defaults come from one real commercetools implementation, and the interview exists so those decisions get checked against your Project instead of inherited silently.