The idea
Why Commerce IQ
AI shopping assistants usually fail in one of two ways: they make up products, or they scrape pages that break and go stale. Commerce IQ gives the model real data instead: live offers with prices, sellers, photos, specs and links, returned as clean JSON.
Grounded, not generated
Every product Curio shows is a real offer from the API. The AI only ranks and explains; it never invents items.
Structured by default
Prices, currencies, sellers, images and spec tables come back as fields, so there's no HTML parsing or brittle scrapers.
Many retailers, one call
Big marketplaces, brand stores and specialty shops come back together, often with several offers for the same product.
Fast enough for chat
Responses usually arrive in about half a second, so you can fan out into several queries and still answer quickly.
Market-aware
The region and language fields localize the catalog, currency and sellers, letting one integration serve many countries.
Built for agents
Plain-language queries work as-is, so an LLM planner can send what it decided straight to the API.
5 minutes
Quickstart
- Create a WebIQ / Grounding API key on a profile (App ID) whose Allowed Services include Commerce Beta.
- Keep the key on your server. Never ship it to a browser.
- Send a
POSTwith the key in thex-apikeyheader (one hyphen).
curl -X POST "https://api.microsoft.ai/v3/search/commerce?features=ads3poff" \
-H "x-apikey: $COMMERCE_IQ_API_KEY" \
-H "content-type: application/json" \
-d '{
"query": "wireless headphones",
"maxResults": 50,
"language": "en",
"region": "US"
}'const res = await fetch("https://api.microsoft.ai/v3/search/commerce?features=ads3poff", {
method: "POST",
headers: {
"x-apikey": process.env.COMMERCE_IQ_API_KEY!,
"content-type": "application/json",
},
body: JSON.stringify({ query, maxResults: 50, language: "en", region: "US" }),
});
if (!res.ok) throw new Error(`Commerce IQ ${res.status}: ${await res.text()}`);
const { products } = await res.json();x-apikey. It is not x-api-key, Authorization: Bearer or Ocp-Apim-Subscription-Key. Our first attempts failed with 401 for exactly this reason.Reference
Request
POST https://api.microsoft.ai/v3/search/commerce
| Field | Type | Description |
|---|---|---|
| query* | string | What the shopper wants, in plain language. Keywords work, and so do phrases like “men's slim jeans 34x32” or “quiet espresso machine under $400”. |
| maxResults | number | How many products to return. Curio always asks for 50 to get the widest set to re-rank. |
| language | string | Language code, for example en. |
| region | string | ISO country code, for example US. Sets the catalog, currency and sellers. |
| ?features=ads3poff | query param | Widens the result set. Curio turns it on to see more offers per query. |
Reference
Response
The response is a list of products. Each product holds one or more offers, meaning the same item sold by different sellers. Prices are in minor units (cents).
{
"products": [
{
"offers": [
{
"id": "…",
"name": "Sony WH-1000XM5 Wireless Noise Canceling Headphones",
"description": "…",
"seller": { "name": "Best Buy" },
"price": { "offeredPrice": 32999, "listPrice": 39999, "currency": "USD" },
"images": [{ "url": "https://…" }],
"specifications": [
{ "name": "Brand", "values": ["Sony"] },
{ "name": "Type", "values": ["Headphones"] }
],
"clickUrl": "https://…",
"shippingInfo": "Free shipping",
"condition": "New"
}
]
}
]
}- Discounts: compare
offeredPricewithlistPriceto show a sale. - Price comparison:
offers.lengthshows how widely a product is sold. Curio uses it as a popularity signal. - Specs:
specificationsprovides Brand, Type, sizes and more, ready for filters and fit checks.
Field notes
Patterns we built with Commerce IQ
Situational fan-out
“3-day camping trip in Yosemite” becomes tents, sleeping bags, pads, pillows and cookware. Each category gets its own parallel Commerce IQ call and its own result section.
Rank on top of real data
We score all 50 offers deterministically first, then an LLM re-ranks them and writes a one-line reason per pick. If the AI step fails, the scored list still works.
Personalize the query
Filtering after the fact loses results. Rewriting “jeans” to “men's jeans” for a men's shopper returned far more relevant items than filtering the generic results.
Size-aware variants
With a saved size guide, Curio adds size-specific queries (“pants 44”, “shoes size 12”) to the fan-out and drops listings that don't fit.
Enrich your own data
Imported Gmail receipts often lack photos. A Commerce IQ lookup by name, brand and preferred store adds photos and product links.
Raw mode
An owner-only switch shows the untouched API output in about 2 seconds. It shows how good the grounding is before any harness touches it.
query ─▶ AI planner ─▶ N queries (fan-out, size + department variants)
│ parallel
▼
Commerce IQ × N (50 offers each)
▼
dedupe ─▶ deterministic score ─▶ LLM re-rank + reasons
▼
grouped results · membership pricing · retailer logosSame key
Companion: image search
The same key can call WebIQ image search. Curio falls back to it when Commerce IQ has no photo for an item. It can be limited to a preferred store's domain, for example walmart.com for a Walmart favorites import.
POST https://api.microsoft.ai/v3/search/images
x-apikey: <key>
{ "query": "Great Value whole milk 1 gal", "maxResults": 8, "language": "en", "region": "US" }
→ { "imageResults": [{ "url", "thumbnailUrl", "hostPageUrl", "isAdult" }] }Resilience
Errors & limits
| 401 / 403 | Wrong header or key, or the profile doesn't include Commerce Beta. Check that the header is x-apikey and that the profile's Allowed Services list it. |
| 429 | Rate limited. Back off and retry. Curio pauses background photo matching and keeps live searches running. |
| 5xx | Temporary error. Show a friendly retry. Never show a stale or made-up result. |
Ship it
Best practices
- Keep the key on the server. Make every call from a server function and remove long tokens from logs.
- Ask for 50 and let your model re-rank. A wider candidate set gives the AI step better items to choose from.
- Put personalization in the query (department, size, brand tier), not just in later filtering.
- Run calls in parallel. Fast responses let one question become five searches without the user noticing.
- Plan for degraded mode. Grounded results should still show if your AI layer is down.
- Normalize once. Map the response into your own product type in one module, so changes to the beta schema stay contained.
