On this page

For Developers

Integrate ProductIndex into your app or AI agent — your users get AI product search across 700+ synthesized profiles in 23 categories. Your agent gets real-time pricing via the RFQ marketplace: consumer agents can negotiate prices with verified producers on behalf of your users. Integration surfaces: 6 MCP tools, per-product endpoints in HTML / Markdown / JSON-LD, and an A2A-compatible agent card. Free tier available; OAuth 2.1 handles sign-in — clients like Grok and Claude Desktop manage it automatically.

Quick Reference

MCP endpoint POST https://mcp.productindex.ai/sse/
Protocol MCP 2025-11-25 · Streamable HTTP
Auth header Authorization: Bearer <access_token>
Scope mcp
Rate limit 500 requests / day per authenticated user
Authorize URL https://productindex.ai/oauth/authorize/
Token URL POST https://productindex.ai/api/oauth/token/
Client registration CIMD (preferred) or DCR at POST https://productindex.ai/api/oauth/register/
OAuth server metadata /.well-known/oauth-authorization-server.json
MCP descriptor /.well-known/mcp.json
Tools list_categories · list_category_products · get_product · search_products · find_similar · find_retailers
CIMD supported Yes — client_id_metadata_document_supported: true in server metadata

MCP Server

Six tools over Streamable HTTP (MCP 2025-11-25). All requests are POST to https://mcp.productindex.ai/sse/ with a JSON-RPC 2.0 body. OAuth 2.1 Bearer token required on every request.

Endpoint POST https://mcp.productindex.ai/sse/
Protocol MCP 2025-11-25 · Streamable HTTP (POST only)
Auth Authorization: Bearer <access_token> — OAuth 2.1 required
Descriptor /.well-known/mcp.json

MCP Tools

Tool Description
list_categories All 23 categories with product counts. No parameters.
list_category_products Paginated product list for a category. Params: category (required), limit, offset, sort, on_sale, include_discontinued.
get_product Full product profile by slug. Params: category, slug (both required), sections (string array — subset retrieval).
search_products Semantic search via pgvector + Cohere reranking with keyword fallback. Params: query (required), category, min_price, max_price, sort, on_sale, include_discontinued, limit.
find_similar Nearest-neighbour similarity to a known product. Params: category, slug (both required), max_price, limit.
find_retailers Merchants carrying a product — triggers RFQ fanout and returns ranked offers with affiliate-attributed buy links. Params: query (required), product_slug, max_results.

Request / Response Example

Every call is a POST to the same endpoint. Send initialize first, then any tool call.

// 1. Initialize
POST https://mcp.productindex.ai/sse/
Authorization: Bearer <access_token>
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"my-app","version":"1.0"}}}

// 200 OK
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-11-25","capabilities":{"tools":{}},"serverInfo":{"name":"ProductIndex","version":"1.0.0"}}}

// 2. Tool call
POST https://mcp.productindex.ai/sse/
Authorization: Bearer <access_token>
Content-Type: application/json

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_products","arguments":{"query":"espresso machine under $500","limit":5}}}

// 200 OK
{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"..."}]}}

Full setup instructions for Grok, Claude Desktop, Cursor, and Windsurf: MCP Server documentation →

Multi-format content endpoints

Every product and category is available in machine-readable formats for direct RAG ingestion, structured data pipelines, and LLM agents that prefer URL-based retrieval over the MCP server. No authentication required.

Format URL pattern Use case
HTML — product /p/{category}/{slug} Human-readable product page
Markdown — product /p/{category}/{slug}.md LLM-friendly; verdict, review themes, specs, images, where-to-buy. noindex.
JSON-LD — product /p/{category}/{slug}.json Schema.org Product object. noindex.
HTML — category /c/{category} Human-readable category listing with all products
Markdown — category /c/{category}.md Full dump of every product profile in the category as a single document — suitable for bulk RAG ingestion. noindex.

Agent Card (A2A)

ProductIndex publishes a Google Agent-to-Agent (A2A) compatible agent card describing its skills and capabilities in machine-readable JSON. Read automatically by A2A-compatible orchestrators.

Card URL /.well-known/agent.json
Skills Product recommendation · Product lookup · Category browse · Product offers · Request for Quote · What changed
Registry Pending — Google A2A registry and Linux Foundation AI Agent Registry

RFQ Integration — Level 2 Producer Agents

If you operate a retailer or manufacturer and want to receive live Request-for-Quote (RFQ) calls from consumer agents via ProductIndex, register your agent endpoint in the Producer Dashboard → Settings → Agent Integration. ProductIndex will fan out to your endpoint when a consumer agent submits an RFQ for a product you carry.

RFQ Request — What Your Agent Receives

ProductIndex calls your registered offer endpoint with a JSON-RPC 2.0 POST request:

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "id": "<rfq_session_uuid>",
  "params": {
    "message": {
      "messageId": "<uuid>",
      "role": "user",
      "parts": [{ "kind": "text", "text": "Request for quote: Baratza Encore ESP, qty 1, ship to CA 94103" }],
      "metadata": {
        "skill": "respond-to-rfq",
        "rfq_id": "<rfq_session_uuid>",
        "product_slug": "coffee-grinders/baratza-encore-esp",
        "quantity": 1,
        "delivery_region": "CA-US",
        "deadline_iso": "2026-06-01T12:00:00Z",
        "requestor": "https://productindex.ai/.well-known/agent.json"
      }
    }
  }
}
Field Type Description
metadata.product_slug string Canonical ProductIndex slug for the requested product
metadata.quantity integer Units requested (default 1)
metadata.delivery_region string Postal region in STATE-COUNTRY format (e.g. CA-US)
metadata.deadline_iso ISO 8601 Latest acceptable delivery date (optional)

RFQ Response — What You Must Return

Respond with a JSON object (not JSON-RPC envelope — bare object only) within 4 seconds:

{
  "price_usd": 169.99,
  "list_price_usd": 189.99,
  "in_stock": true,
  "estimated_shipping_days": 3,
  "shipping_cost_usd": 0,
  "offer_id": "<uuid>",
  "offer_expires_at": "2026-06-01T12:00:00Z",
  "claim_url": "https://yourstore.com/cart?offer=<uuid>",
  "terms": "Free returns within 30 days"
}
Field Required Description
price_usd Yes Your offered price in USD
in_stock Yes Boolean — false causes your offer to be deprioritized
claim_url Yes URL consumer agent can redirect to for purchase. Must be https://.
offer_expires_at Yes ISO 8601 — when the quoted price expires. Max 24 hours from now.
shipping_cost_usd No Shipping cost (0 for free shipping). Omit if unknown — you will rank lower.
list_price_usd No Original MSRP if your offer is discounted
estimated_shipping_days No Business days to deliver. Omit if unknown.
terms No Short return/warranty/conditions string shown to consumer

Offers are ranked by total cost (price_usd + shipping_cost_usd). Out-of-stock offers are demoted regardless of price. Responses that arrive after 4 seconds are dropped.

Authentication

Every RFQ call from ProductIndex carries authentication headers so your server can verify the request is genuine. Choose a scheme, generate your own secret, and register it in the Producer Dashboard → Settings → Agent Integration. ProductIndex encrypts and stores the secret — it is never returned after registration.

Scheme You generate Headers sent by ProductIndex How to verify
Bearer token Any secret string ≥ 16 chars (use a random token) Authorization: Bearer <your-token> Compare header value against your stored token with a constant-time comparison
HMAC-SHA256 A random signing secret ≥ 16 chars (32+ bytes of entropy recommended) X-ProductIndex-Signature: <hex>
X-ProductIndex-Timestamp: <unix_seconds>
Recompute HMAC and compare — see spec below

Generating a secret

// Node.js — generate a cryptographically random secret
import { randomBytes } from "crypto";
const secret = randomBytes(32).toString("hex"); // 64-char hex string
console.log(secret); // paste this into the dashboard

Go to Producer Dashboard → Settings → Agent Integration, select your auth type, paste your secret, and save. ProductIndex will use it to sign all outbound RFQ calls to your endpoint from that point forward.

HMAC Verification

Signature is HMAC-SHA256(secret, "${timestamp}.${rawBodyString}") — the Unix timestamp in seconds, a literal period, then the raw request body string exactly as received. Reject requests where |now - timestamp| > 300 seconds (5-minute replay window).

// Node.js verification example
import { createHmac, timingSafeEqual } from "crypto";

function verifyProductIndexRequest(secret, req) {
  const timestamp = parseInt(req.headers["x-productindex-timestamp"], 10);
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${req.rawBody}`)
    .digest("hex");
  // Use timingSafeEqual to prevent timing attacks
  return timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-productindex-signature"]));
}

Agent Card Requirement

Your agent card (at /.well-known/agent.json on your verified domain) must declare the respond-to-rfq skill. Minimum declaration:

{
  "skills": [{
    "id": "respond-to-rfq",
    "description": "Responds to price quote requests with current pricing, availability, and shipping terms"
  }]
}

ProductIndex fetches and validates this card when you register your agent card URL. The card must be on the same domain as your verified producer organization.

ProductIndex derives your RFQ endpoint from your agent card URL by taking the domain root and appending /message:send. If your card is at https://mystore.com/.well-known/agent.json, ProductIndex will POST RFQ requests to https://mystore.com/message:send. Your server must expose a POST /message:send route at the domain root.

Timeout and Error Handling

Return HTTP 200 with a valid JSON response body within 4 seconds. If you cannot fulfill the RFQ (out of stock, product not carried), return HTTP 200 with {"in_stock": false, "price_usd": 0, "claim_url": "", "offer_expires_at": ""} rather than a non-200 status. Repeated timeouts or errors degrade your integration status and reduce your ranking priority.

LLM Text Files

Static files formatted for LLM context windows and RAG pipelines, following the llms.txt convention. No authentication required.

File Contents
llms.txt MCP server reference + index of all products with one-line verdicts. Start here.
llms-full.txt Full text of every product profile — suitable for offline RAG ingestion. Large file.

Discovery Endpoints

Standard .well-known paths for automated discovery by agents and OAuth clients. All public — no authentication required.

Path Purpose
/.well-known/mcp.json MCP descriptor — tool schemas and per-client config blocks
/.well-known/agent.json A2A agent card — skills, capabilities, and MCP extension pointer
/.well-known/oauth-authorization-server.json OAuth 2.1 authorization server metadata (RFC 8414) — includes all endpoint URLs, supported grant types, CIMD support flag
/.well-known/oauth-protected-resource.json OAuth protected resource metadata (RFC 9728)

Client Authorization — CIMD

ProductIndex supports Client ID Metadata Documents (CIMD) — a stateless alternative to OAuth Dynamic Client Registration (DCR) being standardized in MCP SEP-991 and a companion IETF draft. Instead of pre-registering a client and receiving an opaque client ID, your app hosts a static JSON file at a stable HTTPS URL. That URL is the client ID — no registration step, no database entry on our side.

How it works

Host a JSON file at any stable HTTPS URL on your domain. That URL becomes your client_id. When you send an OAuth authorization request, ProductIndex fetches the document, validates that the client_id field inside it exactly matches the URL it was fetched from, then uses your redirect_uris list to verify the redirect_uri in your request.

{
  "client_id": "https://yourapp.example.com/oauth/client.json",
  "client_name": "Your App Name",
  "client_uri": "https://yourapp.example.com",
  "redirect_uris": [
    "https://yourapp.example.com/oauth/callback"
  ],
  "grant_types": ["authorization_code"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}

Then start the OAuth flow using that URL as client_id:

GET https://productindex.ai/oauth/authorize/
  ?client_id=https://yourapp.example.com/oauth/client.json
  &redirect_uri=https://yourapp.example.com/oauth/callback
  &response_type=code
  &code_challenge=<S256 PKCE challenge>
  &code_challenge_method=S256
  &scope=mcp
  &state=<random state>

Requirements

Requirement Detail
URL scheme https:// only — no http://, no localhost URLs
client_id self-reference The client_id field inside the JSON must exactly match the URL it was fetched from
Required fields client_id, client_name, redirect_uris (non-empty array)
Auth method token_endpoint_auth_method: "none" — public clients with PKCE only
Response size Must be under 64 KB
Fetch timeout 5 seconds — serve the file from a CDN or static host

ProductIndex caches valid CIMD documents for 5 minutes and invalid results for 1 minute. Private IP ranges, loopback addresses, and link-local addresses are blocked before fetch (SSRF protection).

Traditional DCR

If your client cannot host a static HTTPS file (e.g., a CLI tool or local app), register via Dynamic Client Registration at POST /api/oauth/register/. DCR issues an opaque UUID as the client_id. CIMD is preferred for web apps and server-side integrations.

OAuth 2.1 + PKCE Flow

Complete flow for obtaining an access token. All clients are public (token_endpoint_auth_method: none) — PKCE is the only security mechanism, no client secret is issued or required.

Step 1 — Generate PKCE pair

// Generate a cryptographically random code_verifier (43–128 URL-safe chars)
const verifier = base64url(crypto.randomBytes(32));

// Derive code_challenge
const challenge = base64url(crypto.createHash('sha256').update(verifier).digest());

Step 2 — Redirect user to authorization endpoint

GET https://productindex.ai/oauth/authorize/
  ?response_type=code
  &client_id=<your-client-id>
  &redirect_uri=<your-registered-redirect-uri>
  &code_challenge=<challenge>
  &code_challenge_method=S256
  &scope=mcp
  &state=<random-csrf-token>

User signs in (or is auto-approved if they previously granted this client). ProductIndex redirects to your redirect_uri with ?code=<auth_code>&state=<state>.

Step 3 — Exchange code for tokens

POST https://productindex.ai/api/oauth/token/
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=<auth_code_from_redirect>
&redirect_uri=<same-redirect-uri>
&client_id=<same-client-id>
&code_verifier=<verifier>

// 200 OK
{
  "access_token": "<token>",
  "token_type": "Bearer",
  "expires_in": 86400,
  "refresh_token": "<refresh_token>"
}

Step 4 — Call the MCP server

POST https://mcp.productindex.ai/sse/
Authorization: Bearer <access_token>
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}

Step 5 — Refresh an expired token

POST https://productindex.ai/api/oauth/token/
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=<refresh_token>
&client_id=<same-client-id>

// 200 OK — new access_token and refresh_token issued; old refresh_token revoked
Response header Value
X-RateLimit-Remaining Requests remaining today
X-RateLimit-Reset Unix timestamp when the daily quota resets

Rate limits

OAuth 2.1 with PKCE is required for all requests. AI clients like Grok and Claude Desktop handle the sign-in flow automatically — connect once and they manage token refresh.

Tier Limit How to activate
Authenticated (free) 500 requests / day OAuth 2.1 — clients like Grok and Claude Desktop handle sign-in automatically

Remaining quota and reset time are returned on every response as X-RateLimit-Remaining and X-RateLimit-Reset headers.

Questions

For integration questions or to report an issue with the API: hello@productindex.ai