---
title: "Run a product tool via the { tool, input } envelope"
method: POST
path: "/api/agent/products"
---

# Run a product tool via the { tool, input } envelope

`POST /api/agent/products`

## Request

- Base URL: `https://wem3.ai`
- URL: `https://wem3.ai/api/agent/products`
- Auth: none declared

Envelope form of the per-tool operations above, kept for existing callers. New integrations should call the per-tool paths instead: one operation per intent, each carrying that tool's own arguments as the whole request body.

## Request body

- union
  - object
    - `tool` 'search_products', required: Searches WEM's catalogue and its connected retailer sources for products matching a query. The query can be a product name or an identifier: a barcode (EAN/UPC/GTIN), an Amazon ASIN, an MPN, a merchant SKU that names one catalogue product, a WEM ID or a wem3.ai/pl/{slug} URL, and several identifiers may be comma-separated. When the query identifies a product WEM holds, a `catalogMatch` block (`catalogMatches` for several) gives that product's retailer offers; a barcode, ASIN, WEM ID or URL match skips the live retailer search, so `products` then holds catalogue offers only. Barcode, ASIN and slug matches are identity-resolved; MPN, SKU and title matches are inferred. Accessories, bundles, other models and listings priced far below the product's other offers are withheld and counted by reason in `filtered`.
    - `input` object
      - `query` string, required: A product name, or an identifier: barcode (EAN/UPC/GTIN), ASIN, MPN, merchant SKU, WEM ID or wem3.ai/pl URL. Several identifiers may be comma-separated.
      - `category` string: Optional. Keeps only live retailer listings whose own category name matches this text exactly; catalogue matches ignore it. Leave it out unless the shopper names a retailer's category.
      - `min_price` number: Lowest price to include, in `currency`. Applies to retailer listings, not to `catalogMatch`.
      - `max_price` number: Highest price to include, in `currency`. Applies to retailer listings, not to `catalogMatch`.
      - `sort_by` 'relevance' | 'price_asc' | 'price_desc' | 'rating': Order of the live retailer listings (default relevance). Not applied when the query identifies a product.
      - `providers` string[]: Retailer sources to search live, e.g. ["amazon", "awin"]. Omit for all. Catalogue matches are not limited by it.
      - `limit` number: How many listings to request from each retailer source (default 10, max 30). The combined list can hold more.
      - `gtin` string: A product barcode (EAN/UPC/GTIN) the host already has. When given, retailer sources are searched by this barcode instead of by the query words.
      - `currency` string: ISO 4217 code for the shopper's market. Default GBP. Results and price filters use this currency.
  - object
    - `tool` 'semantic_search', required: Searches WEM's partner-feed products by meaning, for a plain-language need such as "comfortable shoes for standing all day" or "gift for a 10 year old who likes science". If the description is a product identifier (a barcode, ASIN, MPN, merchant SKU or wem3.ai/pl URL), that product is looked up instead and the reply takes the keyword-search shape. When no products come back, `reason` says why: `index_empty` means nothing matched; `no_embedding_key`, `no_catalogue_client`, `embedding_failed`, `query_failed` and `timed_out` mean the semantic index could not be searched this time, which says nothing about whether such products exist.
    - `input` object
      - `description` string, required: Plain-language description of what the shopper needs.
      - `category` string: Optional. Keeps only products whose feed category matches this text exactly.
      - `provider` string: Optional. Keeps only products from this partner feed, e.g. "awin".
      - `min_price` number: Optional lower price bound, compared with each product's listed price (currencies are not converted).
      - `max_price` number: Optional upper price bound, compared with each product's listed price (currencies are not converted).
      - `limit` number: Max products to return (default 10, max 20).
  - object
    - `tool` 'get_categories', required: Lists the six broad shopping categories WEM covers (electronics, fashion, beauty, home, sports, collectibles), each with example products, the shops WEM has read a price from in the last 14 days (busiest first, with how many shops there are in all) and the default currency (GBP). Use it to help a shopper narrow a vague request. It returns no prices, the category names are labels for the shopper, not filter values, and a shop on the list is not a promise that WEM holds a given product there: compare_offers says which shops WEM has for one product.
    - `input` object
  - object
    - `tool` 'get_product', required: Returns one product's details. Given `provider` and `product_id` from a search result, it returns that listing as its retailer source supplies it (title, price and link, with rating, shipping or features where the source has them); when the source cannot be reached it falls back to WEM's catalogue record of the listing, and an unknown listing is an error. Given `wem_id`, it returns that catalogue product with the retailer offers WEM holds for it.
    - `input` union
      - object
        - `provider` string: Retailer source of the listing, as given in the search result (e.g. "amazon", "awin").
        - `product_id` string: The listing's `id` from the search result.
        - `wem_id` string, required: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
      - object
        - `provider` string, required: Retailer source of the listing, as given in the search result (e.g. "amazon", "awin").
        - `product_id` string, required: The listing's `id` from the search result.
        - `wem_id` string: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
  - object
    - `tool` 'compare_products', required: Lays 2 to 5 listings from earlier search results side by side in `comparison`: each listing's price and currency, and its rating, shipping and features where the retailer source supplies them (many listings carry none). Each item needs the listing's `provider` and its `id` as `product_id`. Listings that cannot be found are left out, and fewer than two found is an error. Prices stay in each listing's own currency.
    - `input` object
      - `products` object[], required: 2 to 5 listings, each with `provider` and `product_id` as given in a search result.
        - `provider` string, required
        - `product_id` string, required
  - object
    - `tool` 'find_lowest_price', required: Picks one listing for a kind of product within the shopper's constraints, from WEM's catalogue and a live retailer search (a current catalogue match answers without the live search). Candidates are first filtered to plausible matches, so an accessory, another size, an out-of-stock listing or one priced far below the product's other offers is not picked. With no `priorities`, or with `cheapest` first, the lowest price wins; `best_rated`, `free_shipping` and `fastest` (has a delivery estimate) are weighed in the order given, where listings carry ratings or delivery details, and can outrank a lower price. WEM's commission is not a factor. `recommendation` is null with a reason when nothing matched confidently, when the matches differ in size, or when only stale prices remain; when `coverage.kind` is `marketplace_only` it is null but `alternatives` still lists the listings. `recommendation.verified` is true when WEM has recently observed that price at the retailer.
    - `input` object
      - `query` string, required: One kind of product or product: a name, barcode, ASIN, WEM ID or wem3.ai/pl URL. A single query, not a list.
      - `max_price` number: Budget cap, in `currency`.
      - `priorities` string[]: What matters most, in order. cheapest: lowest price. best_rated: higher rating. free_shipping: free delivery. fastest: states a delivery estimate. Weighed only where listings carry those details.
      - `currency` string: ISO 4217 code to quote in. Default GBP. Offers in other currencies are withheld, never converted. Pass the shopper's market explicitly — WEM does not infer currency or retailer market from IP.
      - `include_used` boolean: If true, include used and refurbished listings. Default false — a used item is a different good, not a cheaper one.
      - `condition` string: Same effect as include_used: "any", "used" or "refurbished" also includes used and refurbished listings; any other value means new only.
  - object
    - `tool` 'compare_offers', required: Lists the retailer offers WEM's catalogue holds for one product, current prices first and each group cheapest first, with WEM's 90-day price low (null when the product is held only in another currency). The product is found by barcode, catalogue slug or wem3.ai/pl/ URL, WEM ID, or a title (a model name, ASIN, MPN or merchant SKU) that must pass a relevance check; there is no live retailer search. A barcode, slug or WEM ID match is the product itself; a title match is inferred and marked so in `identity`. A marketplace offer priced far below the product's other offers is withheld and counted in `filtered`. When WEM does not hold the product, `found` is false and `nextTool` names search_products with a query.
    - `input` union
      - object
        - `gtin` string, required: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. The strongest identifier.
        - `slug` string: WEM catalogue slug, or a wem3.ai/pl/{slug} URL / host path. Hosts may pass either form.
        - `wem_id` string: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `title` string: Product or model name, or an ASIN, MPN or merchant SKU (e.g. AF400UK). The weakest identifier: used only when no barcode, slug or WEM ID is given, and only if it passes a relevance check; otherwise `found` is false rather than a guess.
        - `currency` string: ISO 4217 code for the shopper's market. Default GBP. Decides which market's offers WEM returns from its catalogue, not just how the answer reads ; WEM does not infer the market from IP. When WEM holds the product only in another currency it says so rather than presenting a foreign listing as the answer.
      - object
        - `gtin` string: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. The strongest identifier.
        - `slug` string, required: WEM catalogue slug, or a wem3.ai/pl/{slug} URL / host path. Hosts may pass either form.
        - `wem_id` string: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `title` string: Product or model name, or an ASIN, MPN or merchant SKU (e.g. AF400UK). The weakest identifier: used only when no barcode, slug or WEM ID is given, and only if it passes a relevance check; otherwise `found` is false rather than a guess.
        - `currency` string: ISO 4217 code for the shopper's market. Default GBP. Decides which market's offers WEM returns from its catalogue, not just how the answer reads ; WEM does not infer the market from IP. When WEM holds the product only in another currency it says so rather than presenting a foreign listing as the answer.
      - object
        - `gtin` string: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. The strongest identifier.
        - `slug` string: WEM catalogue slug, or a wem3.ai/pl/{slug} URL / host path. Hosts may pass either form.
        - `wem_id` string, required: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `title` string: Product or model name, or an ASIN, MPN or merchant SKU (e.g. AF400UK). The weakest identifier: used only when no barcode, slug or WEM ID is given, and only if it passes a relevance check; otherwise `found` is false rather than a guess.
        - `currency` string: ISO 4217 code for the shopper's market. Default GBP. Decides which market's offers WEM returns from its catalogue, not just how the answer reads ; WEM does not infer the market from IP. When WEM holds the product only in another currency it says so rather than presenting a foreign listing as the answer.
      - object
        - `gtin` string: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. The strongest identifier.
        - `slug` string: WEM catalogue slug, or a wem3.ai/pl/{slug} URL / host path. Hosts may pass either form.
        - `wem_id` string: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `title` string, required: Product or model name, or an ASIN, MPN or merchant SKU (e.g. AF400UK). The weakest identifier: used only when no barcode, slug or WEM ID is given, and only if it passes a relevance check; otherwise `found` is false rather than a guess.
        - `currency` string: ISO 4217 code for the shopper's market. Default GBP. Decides which market's offers WEM returns from its catalogue, not just how the answer reads ; WEM does not infer the market from IP. When WEM holds the product only in another currency it says so rather than presenting a foreign listing as the answer.
  - object
    - `tool` 'verify_offer', required: Checks a price someone has claimed for a product against the prices WEM has itself observed at retailers (recent readings, within a small tolerance; not a live quote), and reports the cheapest observed offer. Identify the product by gtin (strongest), slug, wem_id, provider + externalId, or title (weakest, relevance-checked). `retailer` names the shop the claim is about; without it the nearest observed price at any shop is checked. Only offers in the claim's currency are compared. Verdicts: confirmed (WEM observed that price there), price_moved (WEM last observed a different price there), not_at_retailer (WEM has no observed price there, though it may hold a feed price), no_claim (no price given; the offers are returned), unknown_product (the product could not be resolved, or WEM holds no observed price for it in that currency). unknown_product means the claim could not be checked, not that it is false. `lastConfirmedAt` says when WEM last observed a price in the answer, or is null. Each call records an evidence receipt, whose id can be cited later.
    - `input` union
      - object
        - `gtin` string, required: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. Strongest identifier.
        - `slug` string: WEM canonical slug, as in wem3.ai/pl/{slug}.
        - `wem_id` string: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `provider` string: With externalId: the retailer source of a listing that identifies the product, e.g. 'amazon'. To name the shop the claim is about, use `retailer`.
        - `externalId` string: That listing's own id (an ASIN, or the shop's own item number). Use with provider.
        - `title` string: Product title. The weakest identifier: used only when no id is given, and only if it passes a relevance check.
        - `price` number: The price being claimed. Omit to ask only for the observed offers.
        - `currency` string: ISO 4217 code for the claimed price. Default GBP. Only offers in this currency are compared.
        - `retailer` string: The shop the price was claimed at, as a slug or display name. Omit to compare against every shop.
      - object
        - `gtin` string: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. Strongest identifier.
        - `slug` string, required: WEM canonical slug, as in wem3.ai/pl/{slug}.
        - `wem_id` string: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `provider` string: With externalId: the retailer source of a listing that identifies the product, e.g. 'amazon'. To name the shop the claim is about, use `retailer`.
        - `externalId` string: That listing's own id (an ASIN, or the shop's own item number). Use with provider.
        - `title` string: Product title. The weakest identifier: used only when no id is given, and only if it passes a relevance check.
        - `price` number: The price being claimed. Omit to ask only for the observed offers.
        - `currency` string: ISO 4217 code for the claimed price. Default GBP. Only offers in this currency are compared.
        - `retailer` string: The shop the price was claimed at, as a slug or display name. Omit to compare against every shop.
      - object
        - `gtin` string: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. Strongest identifier.
        - `slug` string: WEM canonical slug, as in wem3.ai/pl/{slug}.
        - `wem_id` string, required: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `provider` string: With externalId: the retailer source of a listing that identifies the product, e.g. 'amazon'. To name the shop the claim is about, use `retailer`.
        - `externalId` string: That listing's own id (an ASIN, or the shop's own item number). Use with provider.
        - `title` string: Product title. The weakest identifier: used only when no id is given, and only if it passes a relevance check.
        - `price` number: The price being claimed. Omit to ask only for the observed offers.
        - `currency` string: ISO 4217 code for the claimed price. Default GBP. Only offers in this currency are compared.
        - `retailer` string: The shop the price was claimed at, as a slug or display name. Omit to compare against every shop.
      - object
        - `gtin` string: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. Strongest identifier.
        - `slug` string: WEM canonical slug, as in wem3.ai/pl/{slug}.
        - `wem_id` string: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `provider` string, required: With externalId: the retailer source of a listing that identifies the product, e.g. 'amazon'. To name the shop the claim is about, use `retailer`.
        - `externalId` string, required: That listing's own id (an ASIN, or the shop's own item number). Use with provider.
        - `title` string: Product title. The weakest identifier: used only when no id is given, and only if it passes a relevance check.
        - `price` number: The price being claimed. Omit to ask only for the observed offers.
        - `currency` string: ISO 4217 code for the claimed price. Default GBP. Only offers in this currency are compared.
        - `retailer` string: The shop the price was claimed at, as a slug or display name. Omit to compare against every shop.
      - object
        - `gtin` string: Product barcode: EAN-13, UPC-A, EAN-8 or GTIN-14. Strongest identifier.
        - `slug` string: WEM canonical slug, as in wem3.ai/pl/{slug}.
        - `wem_id` string: WEM ID (W + 10 Crockford characters + check). Active catalogue products only.
        - `provider` string: With externalId: the retailer source of a listing that identifies the product, e.g. 'amazon'. To name the shop the claim is about, use `retailer`.
        - `externalId` string: That listing's own id (an ASIN, or the shop's own item number). Use with provider.
        - `title` string, required: Product title. The weakest identifier: used only when no id is given, and only if it passes a relevance check.
        - `price` number: The price being claimed. Omit to ask only for the observed offers.
        - `currency` string: ISO 4217 code for the claimed price. Default GBP. Only offers in this currency are compared.
        - `retailer` string: The shop the price was claimed at, as a slug or display name. Omit to compare against every shop.
  - object
    - `tool` 'lookup_products', required: Looks up to 20 product identifiers in one call: barcodes (EAN/UPC/GTIN), Amazon ASINs, WEM IDs, catalogue slugs or wem3.ai/pl URLs. Each row has a status: found (WEM's catalogue holds it; the row gives its number of retailer offers, the lowest current price at a named retailer in the shopper's currency, a marketplace low where there is one, and a link to WEM's product page), not_found (WEM does not hold it yet, which says nothing about whether it exists or has a price), unrecognised (not an identifier, such as a product name) or not_checked (not reached in this call, so not a miss). Identifiers beyond 20 are counted in `overLimit`.
    - `input` object
      - `identifiers` string[], required: 1-20 barcodes (EAN-13, UPC-A, EAN-8, GTIN-14), Amazon ASINs, WEM IDs, catalogue slugs or wem3.ai/pl URLs. Mixed kinds are fine; a comma-separated string is also accepted. Duplicates are looked up once. Each entry must be the identifier alone: not a product name, and not a name with a barcode in it.
      - `currency` string: ISO 4217 code for the shopper's market. Default GBP. Lowest prices are quoted in this currency only, never converted; a product WEM holds only in another currency comes back found with lowPrice null and heldInCurrencies set.
  - object
    - `tool` 'get_evidence_receipt', required: Fetches an evidence receipt by its id (wem-evr- followed by 32 hex characters), as issued with a verify_offer result. Returns the receipt's fields: verdict, observed_at, source, amount, currency and amount_minor, identity_method, verifier, standardVersion and issuedAt, with `signed` true and an HMAC `signature` when WEM signed it. It holds the citation, not the product's offers. A receipt issued moments ago may not be fetchable yet.
    - `input` object
      - `id` string, required: Receipt id (wem-evr- followed by 32 hex characters), as returned in a verify_offer result's receipt.id.
  - object
    - `tool` 'search_promotions', required: Lists current promotions (sales and offers) that retailers in WEM's Awin affiliate programmes have published, for the shopper's market. Filter by merchant or by words in the offer. Each row gives the offer, its dates and a tracked link. A promotion is not a price, and it is not a discount on a product unless its terms say it covers that product. Checkout codes are shown only where the retailer's programme lets WEM publish them; other matching promotions are counted by reason in `withheld`, and a withheld code may still exist. An empty result covers only these programmes, not every offer a retailer runs.
    - `input` object
      - `merchant` string: Retailer name, e.g. "iHoverboard". Omit for every retailer.
      - `query` string: Words that must appear in the offer, e.g. "hoverboard" or "free delivery".
      - `currency` string: ISO 4217 code for the shopper's market: GBP (default) or USD. Promotions are regional, so this decides which market's offers are read.
      - `limit` number: Max promotions to return (default 10, max 25).

## Response `200`

Tool result. `success: false` means the tool ran and reported a problem.

- object
  - `success` boolean, required
  - `data` object: Shape depends on the tool. Search-style results carry `products`, an optional `catalogMatch` of identity-resolved offers, and `filtered`, a count by reason of the weak matches withheld — report that count rather than implying the search was exhaustive.
  - `error` string

## Other responses

- `400`: Unknown tool or a malformed body.
- `429`: Burst or daily quota exhausted. Respect `retry-after` — retrying sooner cannot succeed.
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/wem3/apis/wem-price-compare-api.md) · [All operations](https://skmtc.dev/wem3/apis/wem-price-compare-api/llms.txt) · [OpenAPI document](https://skmtc.dev/wem3/apis/wem-price-compare-api/revisions/52e5c33c3f39?raw)
