{"name":"TheShop Connected Agents API","version":"v1","docs":"/docs/AGENT-API.md","currency":{"code":"MUR","display":"Rs","note":"Every amount is in Mauritian rupees; catalogue prices include VAT."},"auth":{"scheme":"Authorization: Bearer agk_<64 hex>","obtain":"Any signed-in customer creates keys at /account/agents, or an OAuth client obtains one through the endpoints under `oauth` (the access token IS a key). Any HTTP client works — no OpenAI/Anthropic dependency.","revocation":"Keys stop resolving the moment the owner revokes them."},"oauth":{"metadata":"/.well-known/oauth-authorization-server","resourceMetadata":"/.well-known/oauth-protected-resource","authorize":"/oauth/authorize","token":"/oauth/token","register":"/oauth/register (dynamic client registration — public clients, PKCE S256 required)","tokenLifetime":"Access tokens are agent keys: long-lived, no refresh token, revocable by the customer at /account/agents."},"mcp":{"endpoint":"/api/agent/mcp","transport":"Streamable HTTP, stateless, JSON responses (POST only).","tools":"my_agent_key, my_delivery_defaults, search_products, list_products, set_cart_item, list_orders, get_order, place_order — each mirrors a v1 endpoint below; only tools the key's scopes allow are listed.","note":"A tool call resolves the key twice (endpoint + handler) and so counts 2 requests against the per-key limits.","toolsRevision":"2026-09-07T10:30:00Z","toolsChangelog":[{"at":"2026-09-07T06:31:00Z","summary":"New tool my_delivery_defaults. place_order no longer needs deliveryMethod, addressId/collectStoreId or contactPhone: omitted fields (or the value \"default\") reuse the customer's last order."},{"at":"2026-09-07T06:55:00Z","summary":"my_agent_key names the account holder (masked email) and says what this connection is."},{"at":"2026-09-07T10:30:00Z","summary":"my_agent_key lists what changed since you connected; get_order explains payment in plain words and, with paymentLink: true, returns a fresh payment link for an unpaid online order."}],"staleClients":"MCP clients keep their own copy of tools/list from the moment the connector was added. my_agent_key.whatsNew lists changes since a connection was made. To refresh — Claude: Customize → Connectors → TheshopAgent → ⋮ → Refresh tools list (or Disconnect, then Connect), then start a new chat. ChatGPT: Settings → Connectors → reconnect TheShop."},"scopes":{"catalogue:read":"Browse and search products, categories, availability.","cart:write":"Stage items in the customer's cart.","orders:read":"Read the customer's orders and their statuses.","orders:create":"Place orders, inside the spending ceilings below."},"ceilings":{"perOrder":"Server-enforced at placement. Exceeding it returns 409 AGENT_PER_ORDER_CAP_EXCEEDED with {cap, total}.","monthly":"UTC calendar month, atomic at placement. Exceeding it returns 409 AGENT_MONTHLY_CAP_EXCEEDED with {cap, spentThisMonth, remaining}."},"ordering":{"endpoint":"POST /api/agent/v1/orders","idempotency":"clientRequestId is REQUIRED (1-40 chars: letters, digits, . _ -). Reuse the same value when retrying; a replay returns the original order with idempotentReplay: true.","quoteConfirm":"Send expectedTotal with the total you showed the customer. A drifted server total returns 409 TOTAL_MISMATCH with a full breakdown — re-quote and retry.","payment":"Agents place orders; a human completes payment. paymentMethodType \"online\" returns a checkoutUrl payment link to hand to the customer; wallet methods create the order awaiting payment with transfer instructions.","deliveryDefaults":"deliveryMethod, addressId or collectStoreId, and contactPhone are optional for agents: omitted fields — or the value \"default\" — are filled from the customer's last non-cancelled order (then the default address / profile phone). Nothing reusable → 400 DELIVERY_DETAILS_NEEDED {missing}. Replies carry delivery {method, phone (masked to its last 2 digits), address {id, label, city}, collectStore, defaultsApplied} and nextSteps — never a full phone or street. GET /api/agent/v1/me/delivery-defaults shows them ahead of time.","paymentStatus":"GET /api/agent/v1/orders/{orderNumber} returns paid, statusSummary, paymentSummary and nextStep in plain words (a paid online order keeps status \"pending\" until picking starts — read paid/paymentSummary, not status). Add ?paymentLink=1 (orders:create) to receive a fresh payment link for an unpaid online order; 2 per 5 minutes per order."},"endpoints":[{"method":"GET","path":"/api/agent/v1","auth":"none","purpose":"This index."},{"method":"GET","path":"/api/agent/v1/me","auth":"any scope","purpose":"Key self-check: account holder (name, masked email), label, scopes, caps, month-to-date spend, remaining budget, connectedSince, whatsNew (tool changes since the connection + how to refresh) and, for orders:create keys, the masked delivery defaults."},{"method":"GET","path":"/api/agent/v1/me/delivery-defaults","auth":"orders:create","purpose":"What place_order reuses when delivery fields are omitted: last-used method, address (label + town), collection store, phone masked to its last 2 digits."},{"method":"GET","path":"/api/agent/v1/catalogue/products","auth":"catalogue:read","purpose":"Product list/filter/search. Same parameters as the public /api/products."},{"method":"GET","path":"/api/agent/v1/catalogue/search","auth":"catalogue:read","purpose":"Search with suggestions. Same parameters as the public /api/search."},{"method":"POST","path":"/api/agent/v1/cart","auth":"cart:write","purpose":"Set the quantity of a product in the customer cart ({productId, quantity}; 0 removes)."},{"method":"GET","path":"/api/agent/v1/orders","auth":"orders:read","purpose":"List the customer's orders, newest first (limit, before cursor)."},{"method":"GET","path":"/api/agent/v1/orders/{orderNumber}","auth":"orders:read","purpose":"One order, for payment/status polling: paid, statusSummary, paymentSummary, nextStep. ?paymentLink=1 (orders:create) adds a fresh payment link for an unpaid online order."},{"method":"POST","path":"/api/agent/v1/orders","auth":"orders:create","purpose":"Place an order. Body matches the storefront checkout contract; items[] is authoritative; delivery fields may be omitted (see ordering.deliveryDefaults)."}],"rateLimits":{"perKey":"60 requests/minute, 2000/day.","orders":"2 placement attempts/minute per key.","onLimit":"429 with Retry-After."},"errors":["KEY_REQUIRED","KEY_UNRECOGNIZED","KEY_REVOKED","PILOT_DISABLED","SCOPE_MISSING","RATE_LIMITED","IDEMPOTENCY_KEY_REQUIRED","AGENT_PER_ORDER_CAP_EXCEEDED","AGENT_MONTHLY_CAP_EXCEEDED","TOTAL_MISMATCH","DELIVERY_DETAILS_NEEDED","PAYMENT_LINK_NEEDS_ORDERS_CREATE","ORDER_NOT_FOUND","preview_locked"],"notes":["While the storefront is in early-access preview, order placement returns 403 preview_locked for customers' keys; browsing and key management still work.","Product data never includes internal SKUs or ERP codes — reference products by id, slug, and name."]}