Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 109 additions & 13 deletions docs/specification/shopping/catalog/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
* **Capability Name:** `dev.ucp.shopping.catalog.search`

Performs a search against the business's product catalog. Supports free-text
queries, filtering by category and price, and pagination.
queries, relational discovery (recommendations and swaps), filtering by
category and price, and pagination.

## Operation

Expand All @@ -37,18 +38,113 @@ queries, filtering by category and price, and pagination.

## Search Inputs

A valid search request MUST include at least one of: a `query` string,
one or more `filters`, or an extension-defined input. When `query` is
omitted, the request represents a browse operation — the business returns
products matching the provided filters without text-relevance ranking.
Extensions MAY define additional inputs (e.g., visual similarity,
product references).

Implementations MUST validate that incoming requests contain at least one
recognized input and SHOULD reject empty or invalid requests with an
appropriate error. Implementations define and enforce their own rules for
input presence and content — for example, requiring `query`, rejecting
empty `query` strings, or accepting filter-only requests for category browsing.
A valid search request **MUST** include at least one of: a `query` string,
Comment thread
amithanda marked this conversation as resolved.
`reference_ids` (paired with `purpose`), a non-`search` `purpose` (such as
contextual `recommendation`), one or more `filters`, or an extension-defined
input. When `query` and `reference_ids` are omitted, a filter-based request
represents a browse operation where the Business returns products matching the
provided filters without text-relevance ranking. Extensions **MAY** define
additional inputs (e.g., visual similarity).

A Business **MUST** validate that incoming requests contain at least one
recognized input and **SHOULD** reject empty or invalid requests with an
appropriate error. A Business defines and enforces its own rules for input
presence and content (for example, requiring `query`, rejecting empty `query`
strings, or accepting filter-only requests for category browsing).

### Purpose and Reference Identifiers

The `purpose` and `reference_ids` fields support relational and intent-specific
catalog discovery:

* **`search`** (default when `purpose` is omitted): Standard free-text search
or filter-based browse.
* **`recommendation`**: Returns complementary, related, or personalized items
anchored to `reference_ids` and/or `context`.
* **`swap`**: Returns functional substitute items for the anchor products or
variants in `reference_ids`.

When processing `purpose` and `reference_ids`, a Business **MUST** enforce the
following rules:

1. **Pairing**: When `reference_ids` is present, `purpose` **MUST** also be
provided (`dependentRequired`) and **MUST NOT** be `search`. When `purpose`
is `search` (or omitted), the request **MUST** include at least one of
`query`, `filters`, or an extension-defined input. When `purpose` is
`swap`, `reference_ids` **MUST** be provided. A Business **MUST** reject
requests that violate these pairing rules. Multiple `reference_ids` are
evaluated jointly; for `swap`, a Platform **SHOULD** supply a single
identifier per request so returned substitutes map to one target item.
2. **Supported Identifiers**: A Business **MUST** support lookup of
`reference_ids` by product ID and variant ID, and **MAY** additionally
support secondary identifiers such as SKU or handle (matching
[Catalog Lookup](lookup.md#supported-identifiers)). When a specific variant
is known (e.g., swapping an unavailable cart item), a Platform **SHOULD**
supply the variant ID so the Business can match variant-level attributes
(such as options, price, and `quantity_unit`). When `reference_ids` is
provided, the Business evaluates the request using the identifiers that
resolve (and **MAY** include informational `not_found` messages for
unresolved identifiers); if none resolve, the Business **MUST** return an
empty `products` array rather than falling back to a general browse.
3. **Self-Exclusion**: The Business **MUST** exclude any product or variant
listed in `reference_ids` from the response. When a variant ID is supplied,
the Business **MUST** exclude its parent product for `recommendation`, and
**SHOULD** exclude its parent product for `swap` unless returning a
distinct substitute variant of that product.
4. **Combination with Query and Filters**: A request **MAY** combine
`reference_ids` with `query` (e.g., a guided swap where the buyer specifies
a preference) and `filters`. All supplied `filters` combine with `AND`
logic to narrow the returned candidate items.
5. **Unsupported Purpose**: A Business that does not support a requested
`purpose` value **MUST** reject the request or return an empty `products`
array with an error in `messages[]`. It **MUST NOT** ignore `purpose` and
fall back to a general browse.

#### Example: Product Swap

Supplying a variant ID (`prod_abc123_size10`) lets the Business find functional
substitutes that match the unavailable variant's options (such as Size 10):

<!-- ucp:example schema=shopping/catalog_search op=search direction=request -->
```json
{
"purpose": "swap",
"reference_ids": ["prod_abc123_size10"],
"context": {
"location": "loc_downtown",
"currency": "USD",
"intent": "looking for comfortable everyday shoes"
},
"filters": {
"price": {
"max": 15000
}
},
"pagination": {
"limit": 5
}
}
```

#### Example: Product Recommendation

`reference_ids` accepts product IDs, variant IDs, or a mix of both (e.g.,
recommending complementary items for a product and variant in the session):

<!-- ucp:example schema=shopping/catalog_search op=search direction=request -->
```json
{
"purpose": "recommendation",
"reference_ids": ["prod_abc123", "var_xyz789"],
"context": {
"address_country": "US",
"currency": "USD"
},
"pagination": {
"limit": 10
}
}
```

## Search Filters

Expand Down
19 changes: 19 additions & 0 deletions source/schemas/shopping/catalog_search.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,27 @@
"$defs": {
"search_request": {
"type": "object",
"description": "Request body for catalog search.",
"properties": {
"query": {
"type": "string",
"description": "Free-text search query."
},
"purpose": {
"type": "string",
"description": "The retrieval purpose for the search request. Well-known values: `search` (general search or filter browse requiring `query`, `filters`, or an extension input; default when omitted), `recommendation` (complementary or related items anchored to `reference_ids` and/or `context`), `swap` (functional substitute items requiring `reference_ids`). Businesses MUST reject or return an empty `products` array with an error message for unsupported values rather than falling back to a general browse.",
"examples": ["search", "recommendation", "swap"]
},
"reference_ids": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"minItems": 1,
"uniqueItems": true,
"description": "Anchor product or variant identifiers for relational discovery. Requires `purpose` (e.g., `recommendation` or `swap`; MUST NOT be `search`). Implementations MUST support product ID and variant ID; MAY support secondary identifiers (SKU, handle, etc.). Referenced items MUST be excluded from the returned products."
},
"context": {
"$ref": "../common/types/context.json"
},
Expand All @@ -28,6 +44,9 @@
"pagination": {
"$ref": "../common/types/pagination.json#/$defs/request"
}
},
"dependentRequired": {
"reference_ids": ["purpose"]
}
},
"search_response": {
Expand Down
Loading