# Browsing, filters and reviews

> Browse a shop by collection and price, read ratings and reviews, and list the collections, through UCP, MCP and WebMCP.

Source: https://storeware.ai/docs/agents/browse-and-reviews

An agent can search a shop with a question, and it can also browse: list what the shop has on sale in a collection or a price range, a page at a time. Every product it is shown carries its rating and the collections it is in, and the reviews behind the rating can be read in full. The same filters and the same values work on every door.

## Categories are collection handles

A category is one of the shop's collections, named by its handle: the last part of its address, as in `/collections/knitwear`. A product's `categories` lists the collections it is in, and a filter on `categories` matches a product in any of the ones named. Handles are stable and are not translated, so they are safe to store. List them with `list_collections`.

On UCP, each entry is `{ "value": "knitwear", "taxonomy": "merchant" }`, and the filter takes the `value`.

## Filters

| Filter       | Takes                                                                                                                    |
| ------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `categories` | A list of collection handles, at most 50. A product in any of them matches.                                              |
| `price`      | `min`, `max` or both, in minor units of the currency asked for (2500 is 25.00). A product matches when any variant does. |

Both must hold when both are given. The price filter reads the shop's own price in that currency, or in the shop's currency when none was asked for; a product with no price in that currency does not match. A handle that names no collection matches nothing and comes back as a warning, so a typo is not mistaken for an empty shelf.

## Browsing and paging

Send filters without a query to browse. The answer lists what is on sale and matches, ordered by handle, with prices and stock read live. An empty `filters` object lists everything on sale.

A browse pages with a cursor. Pass back the cursor you were given to read the next page; it is opaque, so do not build one. A search with a query answers one ranked page and gives no cursor. Filters on a search narrow its results.

## Ratings and reviews

A product's `rating` is the average of the reviews the merchant approved, on a scale of 1 to 5, with how many there are. It is left out when there are none. Reviews that are waiting for the merchant, or that were rejected, are never counted or served.

`get_reviews` reads them, newest first, a page at a time (up to 50). Each review has its stars, a title, the words, the name the reviewer signed with as the shop shows it, the date, and `verified_purchase`, which is true only when the purchase was proved against an order. No email address or account is ever included. Reviews are read only for a product the shop has on sale.

## On UCP

Two capabilities of Storeware's own are declared on the shop's profile, each with its schema at `https://api.storeware.ai/schemas/ucp/2026-11-11/<name>.json`. Both are read only, so any agent key may use them and no shopper needs to be linked.

| Job                    | REST, under `/api/ucp/v1`   | MCP tool           | Capability                          |
| ---------------------- | --------------------------- | ------------------ | ----------------------------------- |
| Search or browse       | `POST /catalog/search`      | `search_catalog`   | `dev.ucp.shopping.catalog.search`   |
| A product's reviews    | `POST /catalog/reviews`     | `get_reviews`      | `ai.storeware.shopping.reviews`     |
| The shop's collections | `POST /catalog/collections` | `list_collections` | `ai.storeware.shopping.collections` |

`POST /catalog/search` takes `filters` and `pagination` as UCP defines them, and answers with `pagination`: `has_next_page`, and a `cursor` when there is one. The query may be left out when there are filters. A page holds 10 products unless `pagination.limit` says otherwise, and at most 50.

```http
POST /api/ucp/v1/catalog/search
UCP-Agent: profile="https://platform.example/profile.json"
Authorization: Bearer <agent key>
Content-Type: application/json

{
  "filters": { "categories": ["knitwear"], "price": { "max": 5000 } },
  "context": { "currency": "GBP" },
  "pagination": { "limit": 20 }
}
```

`get_reviews` takes `product_id` (the product's `id` from the catalog, or its handle) and `pagination`, and answers with `rating`, `distribution` (how many gave each star), `reviews` and `pagination`, whose `total_count` is the number of approved reviews.

Lookup and `get_product` take a product's `id`, a variant's `id` (both as search returns them), or the product's handle. A lookup answers each product once, with only the variants your ids led to: a variant id brings that variant, and a product id or handle brings the one the shop would show first. Each of those variants lists the ids that reached it under `inputs`, with `match` set to `exact` or `featured`. Ask `get_product` for every variant. Given a variant id, `get_product` leads with that variant and takes its options as the choice.

A shop quotes in the currencies it sells in. Ask for another in `context.currency` and the answer comes in the shop's own currency, with a warning coded `ai.storeware.currency_not_sold` saying which one.

Every product on a search, lookup or product answer carries `rating`, `categories`, its `options`, and `list_price_range` when something is reduced. `get_product` also takes `selected` and `preferences`: it leads with the variant that fits what was chosen, says the full choice under `selected`, and marks each option value `exists` and `available` against it. When nothing fits every choice, the choices ranked last in `preferences` are given up first.

Over A2A, the same tools are DataParts naming the tool, as for [Ask](https://storeware.ai/docs/agents/ask).

## On the shop's MCP server

At `/mcp`, `search_products` takes `filters` in the same shape and a `cursor`. With filters and no query it browses, and `next_cursor` reads the next page. Each result carries `rating` and `categories`, as do `get_product` and `compare_products`. `get_reviews` takes a product `handle`, with `limit` and `cursor`. `list_collections` takes nothing.

## In the shopper's browser

The WebMCP `search_products` tool takes `filters` and `cursor` too, and browses without a query; `nextCursor` reads the next page. Prices and the price filter are in the shopper's own currency. Each result carries `rating` and `categories`. `list_collections` lists the collections, each with its address on the shop. See [WebMCP](https://storeware.ai/docs/agents/webmcp).
