Quickstart
Authenticate, index a product, and run your first search — in three requests. Everything below is server-side; the browser uses a scoped, origin-bound public key instead.
Keep your client_secret on the server. Never ship it to the browser. For storefront calls, use an origin-bound pk_live_ public key that can only search.
Three requests to first results
Exchange your client credentials for a bearer token, index a product, then search. Pick your language:
# 1. Exchange client credentials for a bearer token (server-side only). export TOKEN=$(curl -s https://search.trooply.ai/oauth/token \ -H "Content-Type: application/json" \ -d '{"client_id":"'$CLIENT_ID'","client_secret":"'$CLIENT_SECRET'"}' \ | jq -r .access_token) # 2. Index a product (JSON, image_url is the canonical path). curl -X POST https://search.trooply.ai/v1/products \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"product_id":"SKU-48120","image_url":"https://cdn.shop.com/bag.jpg","metadata":{"name":"Marla Tote","price":189,"category":"Handbags"}}' # 3. Search by text. curl https://search.trooply.ai/v1/search/text \ -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"query":"red tote","limit":10}'
# pip install httpx import httpx, os BASE = "https://search.trooply.ai" with httpx.Client(base_url=BASE, timeout=30) as c: # 1. Auth tok = c.post("/oauth/token", json={ "client_id": os.environ["TROOPLY_CLIENT_ID"], "client_secret": os.environ["TROOPLY_CLIENT_SECRET"], }).raise_for_status().json()["access_token"] h = {"Authorization": f"Bearer {tok}"} # 2. Index c.post("/v1/products", headers=h, json={ "product_id": "SKU-48120", "image_url": "https://cdn.shop.com/bag.jpg", "metadata": {"name": "Marla Tote", "price": 189, "category": "Handbags"}, }).raise_for_status() # 3. Search by text r = c.post("/v1/search/text", headers=h, json={"query": "red tote", "limit": 10}) print(r.json())
// Node 18+ / browsers have fetch built-in. const BASE = "https://search.trooply.ai"; // 1. Auth (server-side only — never ship client_secret to the browser). const tok = (await (await fetch(`${BASE}/oauth/token`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ client_id: process.env.TROOPLY_CLIENT_ID, client_secret: process.env.TROOPLY_CLIENT_SECRET, }), })).json()).access_token; const h = { "Authorization": `Bearer ${tok}`, "Content-Type": "application/json" }; // 2. Index await fetch(`${BASE}/v1/products`, { method: "POST", headers: h, body: JSON.stringify({ product_id: "SKU-48120", image_url: "https://cdn.shop.com/bag.jpg", metadata: { name: "Marla Tote", price: 189, category: "Handbags" }, }), }); // 3. Search by text const r = await fetch(`${BASE}/v1/search/text`, { method: "POST", headers: h, body: JSON.stringify({ query: "red tote", limit: 10 }), }); console.log(await r.json());
Seven endpoints, one afternoon
A minimum viable integration touches just these. Everything else is optional depth.
More endpoints
When you're ready to go deeper:
/v1/search/suggestions— autocomplete as the shopper types./v1/search/feedback— click / purchase signals improve ranking over time./v1/search/similar/{id}— "more like this" on a product page./v1/products/facets— values to populate filter sidebars./v1/search/voice— speech → search for mobile-first stores./v1/search/crop,/multi-image,/fusion— advanced visual shopping flows./v1/ai/search/nl,/v1/ai/search/parse— natural-language filter parsing.
The full OpenAPI reference
Open API reference
Every endpoint, schema, and error, with a live try-it console.