# Klatchit — full reference for agents > Klatchit is a US marketplace where independent sellers list competing > offers against a shared product catalog. Every listing is one seller's offer on > a canonical product: prices, conditions, and stores differ, the product does > not. Payments go direct to the seller of the chosen offer. This file is the long form of https://klatchit-gold.vercel.app/llms.txt. The endpoint sections below are generated from the same schemas the server validates with, so they cannot drift from the implementation. Machine-readable equivalent: https://klatchit-gold.vercel.app/api/public/v1/openapi.json Base URL: https://klatchit-gold.vercel.app/api/public/v1 Authentication: none. No key, no account, no OAuth. ## Conventions - Success responses are `{ "data": ..., "meta": ... }`. `meta.request_id` correlates with the `X-Request-Id` response header — quote it in bug reports. - All money is an INTEGER number of CENTS in USD. A field ending `_cents` is never a decimal: `4999` means $49.99. - A PRODUCT is addressed by its `slug`, which is also its canonical page https://klatchit-gold.vercel.app/p/{slug}. An OFFER is addressed by its `listing_id`, which identifies one seller's offer — not the product. - Inventory depth is never exposed. An offer reports a boolean `in_stock`. - Timestamps are RFC 3339 / ISO-8601 in UTC. - Reads are shared-cacheable: `Cache-Control: public, s-maxage=60` (300s for the category tree). `POST /cart-links` is always `no-store`. - Send a descriptive `User-Agent` identifying your agent and a contact. ## Errors Every failure is `{ "error": { "type", "code", "message", "param"?, "request_id" } }` with the matching HTTP status. - 400 invalid_request_error / validation_error — bad or missing parameters; `param` names the offending field, and a multi-issue failure adds an `errors` array of `{ param, message }`. - 404 invalid_request_error / resource_missing — no such publicly listed resource. A product that exists but is not public answers 404 identically, so this endpoint is not an existence oracle. - 429 rate_limit_error / rate_limited — see Rate limits. - 500 api_error / internal_error — retry with backoff. Never carries detail. ## Rate limits Limits are PER CLIENT IP (first `X-Forwarded-For` hop), applied as a token bucket: burst up to the capacity, then a steady refill. Buckets are per endpoint, so search and product lookups do not compete. - Catalog endpoints (/search, /products/{slug}, /categories): burst 30, refill 5/second. - POST /cart-links: burst 10, refill 1/second. - MCP (/api/mcp/mcp): burst 30, refill 5/second, in its own bucket. A 429 carries `Retry-After` in seconds. Honour it; do not retry tighter. These are current operating values, not a contractual guarantee. ## Endpoints ### GET /api/public/v1/search Search the public catalog Full-text + faceted product search over purchasable offers. Identical ranking, filtering, and facet counts to the site's own /search page. Each result carries an absolute product-detail URL (`/p/{slug}`) you can fetch via GET /products/{slug}. Parameters: - q (query, string, optional) — Free-text query; omit to browse. - category (query, string, optional) — Category slug; scopes the search to that subtree. - brand (query, array, optional) — Brand slugs. Repeatable, or comma-separated. - condition (query, array, optional) — Offer conditions. Repeatable, or comma-separated. - price_min_cents (query, integer, optional) - price_max_cents (query, integer, optional) - sort (query, enum("relevance"|"price_asc"|"price_desc"|"newest"), optional, default "relevance") - page (query, integer, optional, default 1) - page_size (query, integer, optional, default 24) — Results per page. Values above 60 are clamped, not rejected; the effective value is echoed in meta.page_size. Responses: - 200 — A page of product cards plus facet counts. data: array id: string slug: string title: string url: string image_url: string|null brand: object|null slug: string|null name: string category_breadcrumb: array slug: string name: string min_price_cents: integer|null currency: string offer_count: integer rating_avg: number|null rating_count: integer meta: object page: integer page_size: integer total: integer page_count: integer facets: object category: array ... brand: array ... condition: array ... price: array ... request_id: string - 400 — Error envelope (see Errors below). - 429 — Rate limited — see Retry-After. - default — Error envelope (see Errors below). ### GET /api/public/v1/products/{slug} Retrieve a product and its purchasable offers The full public product record: attributes, images, brand, GTIN/MPN, category breadcrumb, and every currently purchasable offer (cheapest first) with the buy-box winner identified. Inventory depth is never exposed — an offer reports a boolean `in_stock`. A product that is not publicly listed returns 404. Parameters: - slug (path, string, required) — The product slug, as it appears in /p/{slug}. Responses: - 200 — The product. data: object id: string slug: string title: string description: string|null url: string brand: object|null slug: string|null name: string category_breadcrumb: array slug: string name: string gtin: string|null mpn: string|null attributes: object images: array url: string alt: string|null width: integer|null height: integer|null rating_avg: number|null rating_count: integer currency: string min_price_cents: integer|null offers: array listing_id: string price_cents: integer list_price_cents: integer currency: string condition: enum("new"|"like_new"|"very_good"|"good"|"acceptable"|"refurbished"|"used"|"for_parts") condition_label: string store_name: string store_slug: string in_stock: boolean on_sale: boolean buy_box_listing_id: string|null meta: object request_id: string - 404 — Error envelope (see Errors below). - 429 — Rate limited — see Retry-After. - default — Error envelope (see Errors below). ### GET /api/public/v1/categories Retrieve the active category tree Every active category as a nested tree. Use a node's `slug` as the `category` parameter on /search; `path` is the materialised ltree path (e.g. `electronics.audio.headphones`). Responses: - 200 — The category tree. data: array slug: string name: string path: string children: array slug: string name: string path: string children: array ... meta: object count: integer request_id: string - 429 — Rate limited — see Retry-After. - default — Error envelope (see Errors below). ### POST /api/public/v1/cart-links Create a cart link for a human to open Mint a short-lived link that puts specific offers into the cart of whoever OPENS it. This is a handoff, not a purchase: it takes no payment, places no order, reserves no stock, and creates no cart on our side — it returns a URL for a person to open in their own browser, where the items appear in their own cart to review and check out themselves. There is no API for buying on a shopper's behalf. Identify each line by the `listing_id` of one offer from GET /products/{slug} (a listing_id picks one seller's offer, not the product). Quantities are 1-99 and up to 20 lines; a repeated listing_id has its quantities summed. Lines that are not purchasable right now are dropped and reported in `rejected` — a generic reason only. If nothing is purchasable the response is a 400 whose error object carries the same `rejected` list. The link expires in 7 days, and price and availability are re-checked when it is opened, so nothing here is a price guarantee. Responses are never cached. Request body (application/json, required): items: array — Listings to prefill, 1-20 lines. listing_id: string (uuid) quantity: integer Responses: - 200 — The cart link. data: object url: string expires_at: string accepted: integer rejected: array listing_id: string reason: enum("unavailable"|"insufficient_stock") meta: object request_id: string - 400 — Error envelope (see Errors below). - 429 — Rate limited — see Retry-After. - default — Error envelope (see Errors below). ## MCP server The same catalog is available over the Model Context Protocol. - Endpoint: https://klatchit-gold.vercel.app/api/mcp/mcp - Transport: streamable HTTP, `POST` only. A `GET` is answered 405 by design — the server is STATELESS, so there is no session id to carry and no event stream to hold open. Build one server instance per request. - Authentication: none. No cookie is read; the trust level is identical to the anonymous JSON API above. - Tools: - `search_products` (read-only) — args: q, category, brand[], condition[], max_price_cents, page. Returns product cards + facet counts. - `get_product` (read-only) — args: slug. Returns full detail plus every purchasable offer, each with its `listing_id`. - `get_categories` (read-only) — no args. Returns the active category tree. - `create_cart_link` — args: items[{ listing_id, quantity }]. Mints the handoff link described below. It is NOT a purchase. Connect from a client config: { "mcpServers": { "klatchit": { "type": "http", "url": "https://klatchit-gold.vercel.app/api/mcp/mcp" } } } From Claude: Settings -> Connectors -> Add custom connector, paste https://klatchit-gold.vercel.app/api/mcp/mcp. There is no authentication step. From the MCP inspector (`npx @modelcontextprotocol/inspector`): transport "Streamable HTTP", same URL. ## Cart links: the handoff to a human 1. Find offers with `GET /search`, then `GET /products/{slug}`, and collect the `listing_id` of each chosen offer. 2. `POST /cart-links` with 1-20 lines, quantity 1-99 each. A repeated `listing_id` has its quantities summed. 3. Lines that are not purchasable right now are DROPPED and reported in `rejected` with a coarse reason (`unavailable` or `insufficient_stock`) — a precise reason would leak non-public seller state. Read `accepted` before claiming success. If nothing is purchasable the response is a 400 whose error object carries the same `rejected` list. 4. Give the returned `url` to your user and tell them to open it. The items appear in THEIR cart, in their own browser, for them to review and pay for. 5. The link expires in 7 days (`expires_at`), and price and availability are re-checked when it is opened. Quote prices as current, never guaranteed. ## Buying There is no way to buy through this API, by design. `POST /cart-links` mints a link that a PERSON opens in their own browser to find the chosen offers waiting in their own cart, which they then review and pay for themselves. It takes no payment, places no order, and reserves no stock, and price and availability are re-checked when the link is opened. Hand the link to your user; never report a purchase you have not made. ## What is exposed Exactly what an anonymous visitor can see: publicly listed products, active categories, public prices, and purchasable offers. Seller-internal data — inventory counts, contact details, order and payout information — is not available through any public endpoint or MCP tool. The authenticated seller API (https://klatchit-gold.vercel.app/developers) is a separate surface with its own keys and is not described here. ## More - Index: https://klatchit-gold.vercel.app/llms.txt - Human documentation: https://klatchit-gold.vercel.app/developers/public - OpenAPI 3.1: https://klatchit-gold.vercel.app/api/public/v1/openapi.json - Product feed (Google Shopping XML): https://klatchit-gold.vercel.app/feeds/google-shopping - Crawling rules: https://klatchit-gold.vercel.app/robots.txt - Terms: https://klatchit-gold.vercel.app/legal