Start with the product and retailer scope
Your agent needs somewhere to buy a replacement keyboard. product-search returns ranked purchase candidates, with a buy link attached to each result. It costs 0.02 USDC per call through x402 on Base mainnet.
Send a JSON body to the product-search POST endpoint:
{
"query": "Logitech MX Keys S keyboard graphite",
"retailer": "bestbuy.com",
"num_results": 5
}
query is the required input. Write the product name and the details that distinguish the item you want. A model number helps keep an agent from choosing an accessory with similar wording.
The optional retailer input scopes the search to a domain. Returned URLs are checked against that scope, too. Omit it when you're looking across retailers.
num_results defaults to 10 and accepts a requested count from 1 to 20. Treat that count as a ceiling: filtering can leave fewer candidates. Keep the query short. The endpoint enforces a 300-character limit after adding the retailer scope.
Want headphones under $200? Put that phrase in query, then check the returned candidates against the budget yourself. There's no separate price-filter field.
Read each result as a purchase candidate
Here's an illustrative result object. The retailer and price below are fictional, so this isn't a live offer:
{
"rank": 1,
"title": "Wireless keyboard, graphite",
"buy_url": "https://shop.example/products/wireless-keyboard",
"retailer": "shop.example",
"snippet": "Wireless keyboard in graphite. $89.99. Add to cart.",
"price": "$89.99"
}
The response puts these objects in a results array. Each field gives your agent a different piece of evidence:
titleidentifies the candidate as described in the search result. Compare it with the requested model before putting it on a shortlist.buy_urlis the link your agent can open for the next check. Preserve it in the recommendation so the buyer can reach the same page.retaileris the hostname from that link, with a leadingwww.removed. It identifies the destination domain; a marketplace seller's identity still needs checking on the page.snippetsupplies the result's descriptive text. Use it for context, while keeping claims tied to what the text actually says.pricecontains a detected dollar amount as a string, ornullwhen none is found. Detection recognizes$andUSDamounts in the title or snippet.
And rank records the candidate's position in the returned list. It doesn't certify the cheapest offer.
Keep detected prices separate from checkout totals
A detected $89.99 gives your agent an amount to investigate. The endpoint doesn't independently verify that price or product availability.
Keep that distinction visible. A shopping card can say “Detected price: $89.99” and attach the buy link. Before purchase, check the selected variant and its current price on the retailer's page. Shipping and tax belong in the final budget calculation.
But a missing price doesn't mean the item is free. Preserve null as unknown, and decide whether opening the listing is worth another step.
The response also includes degraded and note. A true degraded value indicates that candidates were removed by the purchase or retailer-scope checks. An empty results array means the call returned no qualifying candidates. Your agent shouldn't turn that into a claim that the product doesn't exist.
Route shopping requests to a bounded next step
Use product-search when the requested output is a shortlist with purchase links. For general research about a product category, route to a general web search endpoint.
So a request like “Find this keyboard at Best Buy” becomes the scoped JSON call above. Your agent can inspect each title, then open a matching buy_url to verify the offer before presenting it.
Keep the search payment separate from purchase authorization. The 0.02 USDC pays for the endpoint call. If your workflow can place orders, get the required approval against the checked item and checkout total before submitting one.