One function call, before checkout. It returns yes or no, and a reason you can show the user.
# pip install shelfprotocol from shelfprotocol import lookup, can_buy profile = lookup("acme-coffee.example") ok, why = can_buy(profile, amount_usd=40) # → (True, "OK: $40.00 is within the $250.00 autonomous limit.")
Defaults to the hosted registry at api.shelfprotocol.com. Point at
a self-hosted one with the SHELF_URL environment variable.
False with a reason.
You have to opt out deliberately to get anything else.# pip install "shelfprotocol[langchain]" from langchain.agents import create_agent from shelfprotocol.langchain_tools import get_tools agent = create_agent(model, tools=get_tools())
# pip install "shelfprotocol[crewai]" from crewai import Agent from shelfprotocol.crewai_tools import get_tools buyer = Agent(role="Purchasing agent", goal="...", tools=get_tools())
Both expose the same five tools: shelf_lookup,
shelf_search, shelf_can_buy, shelf_catalog,
shelf_products. The shelf_ prefix keeps them from colliding with the
generic search tool most agent stacks already carry — pass
get_tools(prefix="") if you'd rather have the bare names.
shelf_can_buy has no require_verified argument at all, so a
manipulated prompt can't talk an agent into skipping domain verification. Deliberate opt-out
stays available in code you write yourself, via the SDK's can_buy() directly.crewai pins mcp~=1.28, which
contradicts the [mcp] extra's mcp>=2.0, so
shelfprotocol[mcp,crewai] won't resolve. Either extra alone is fine — the CrewAI
adapter and the MCP server are two routes to the same tools.
# pip install "shelfprotocol[mcp]" { "mcpServers": { "shelfprotocol": { "command": "shelfprotocol-mcp" } } }
Drop that into Claude Desktop, Claude Code, or any other MCP client and it can check the registry before buying anything, without you writing any code.
Public, unauthenticated, no key required for reads. Browsable at api.shelfprotocol.com/docs.
| Endpoint | What it does |
|---|---|
GET /v1/merchants/{domain} | One merchant's full profile |
GET /v1/search | Find merchants by name, category, protocol, verified status |
GET /v1/products | Search products across every merchant |
GET /v1/merchants/{domain}/catalog | One merchant's cached catalog |
GET /v1/stats | Registry totals |
POST /v1/merchants | Register a merchant |
POST /v1/merchants/{domain}/claim | Take ownership of an imported listing |
POST /v1/merchants/{domain}/verify | Complete the DNS TXT check |
Most store owners should use the five-minute version instead. This is the raw call.
# 1. host this at https://yourdomain.com/.well-known/shelf.json { "shelf_version": "0.1", "merchant": { "name": "Your Store", "domain": "yourdomain.com" }, "agent_policy": { "agents_allowed": true, "max_autonomous_order_usd": 250 }, "checkout": { "protocol": "AP2" }, "catalog": { "feed_url": "https://yourdomain.com/shelf-catalog.json" } } # 2. register it curl -X POST https://api.shelfprotocol.com/v1/merchants -d @shelf.json # 3. add the returned DNS TXT record, then verify curl -X POST https://api.shelfprotocol.com/v1/merchants/yourdomain.com/verify \ -H "X-Api-Key: $SHELF_API_KEY"
Full schema in spec/SPEC.md.
If a store is listed and doesn't want to be, removal is unconditional — no questions, no retention pitch. Email luis@signalall.com or open an issue. Acknowledged within one business day, gone within five.
Removal is permanent rather than a delete: the domain goes on a suppression list the importer checks before it makes any request, so a later bulk import can't quietly put the store back.