> ## Documentation Index
> Fetch the complete documentation index at: https://docs.preezie.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Search for products

> Search the tenant's product catalogue using natural language.

Search the tenant's product catalogue using a natural-language request. The endpoint selects the product-search intent automatically, so you do not send an `intent` field.

## When to use this endpoint

Use Search when the shopper describes the products they want, including attributes such as category, colour, size, price, use case, or style.

## Request example

```bash theme={null}
curl --no-buffer --request POST \
  "$PREEZIE_API_URL/api/operation/search" \
  --header "Authorization: Bearer $PREEZIE_OPERATION_TOKEN" \
  --header "Tenantid: $PREEZIE_TENANT_ID" \
  --header "Content-Type: application/json" \
  --data '{
    "sessionId": "session-123",
    "visitorId": "visitor-456",
    "content": "Show me lightweight black running shoes",
    "requestOrigin": "Operation",
    "pageSize": 12,
    "operationHideAiMessage": false,
    "operationReturnFullProductInfo": false,
    "chatMetadata": {
      "websiteUrl": "https://shop.example.com/collections/running"
    }
  }'
```

### Important request fields

| Field                     | Description                                          |
| ------------------------- | ---------------------------------------------------- |
| `content`                 | Required natural-language product request.           |
| `pageSize`                | Optional maximum number of product results.          |
| `sessionId`               | Reuse for related requests in the same conversation. |
| `visitorId`               | Stable identifier for the shopper.                   |
| `chatMetadata.websiteUrl` | Optional context from the current storefront page.   |

## Streaming response

The response uses `text/event-stream`. Read every `data:` line as an independent JSON message:

```text theme={null}
data: {"chatStream":"I found several products that match your request."}

data: {"data":{"responseType":"ProductSearch","responsePayload":[{"id":"product-123"}],"hasMoreProducts":false,"total":1}}

```

Set `operationHideAiMessage` to `true` to omit `chatStream` messages. Set `operationReturnFullProductInfo` to `true` to return full product objects instead of ID-only objects in `responsePayload`.


## OpenAPI

````yaml openapi/preezie-api.json POST /api/operation/search
openapi: 3.1.0
info:
  title: preezie API
  version: 0.1.0
  description: >-
    API reference for product discovery operations and generated product-page
    content. Core Intent responses are streamed as server-sent events (SSE); FAQ
    and Highlights responses use JSON.
servers: []
security: []
tags:
  - name: Core intents
    description: >-
      Run a specific product-discovery intent without sending an intent value in
      the request body.
  - name: Product content
    description: Retrieve generated product FAQs and highlights for product detail pages.
paths:
  /api/operation/search:
    post:
      tags:
        - Core intents
      summary: Search for products
      description: >-
        Searches the tenant's product catalogue using the natural-language
        `content` in the request. The endpoint streams product data and, unless
        disabled, an AI-generated message as server-sent events.
      operationId: searchProducts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CoreIntentRequest'
            example:
              sessionId: session-123
              visitorId: visitor-456
              content: Show me lightweight black running shoes
              requestOrigin: Operation
              productIds: []
              pageSize: 12
              operationHideAiMessage: false
              operationReturnFullProductInfo: false
              chatMetadata:
                websiteUrl: https://shop.example.com/collections/running
      responses:
        '200':
          $ref: '#/components/responses/CoreIntentStream'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/TenantNotFound'
      security:
        - bearerAuth: []
          tenantId: []
components:
  schemas:
    CoreIntentRequest:
      type: object
      required:
        - content
      properties:
        sessionId:
          type: string
          description: Conversation session identifier. Reuse it for related requests.
          example: session-123
        visitorId:
          type: string
          description: Stable identifier for the shopper or visitor.
          example: visitor-456
        websiteUrl:
          type: string
          format: uri
          deprecated: true
          description: >-
            Legacy top-level URL field. Use `chatMetadata.websiteUrl` for the
            current page context.
        chatMetadata:
          $ref: '#/components/schemas/ChatMetadata'
        content:
          type: string
          minLength: 1
          description: Natural-language request that guides the selected operation.
          example: Show me lightweight black running shoes
        requestOrigin:
          type: string
          enum:
            - Operation
          default: Operation
          description: Source of the request. Use `Operation` for these endpoints.
        productIds:
          type: array
          description: >-
            Explicit product identifiers consumed by operations such as
            comparison. For similarity and bundling, identify the base product
            with `chatMetadata.productId` instead.
          items:
            type: string
          default: []
        pageSize:
          type: integer
          minimum: 1
          description: >-
            Maximum number of product results requested. When omitted, the
            tenant's configured default is used.
        operationHideAiMessage:
          type: boolean
          default: false
          description: >-
            When `true`, suppresses `chatStream` events and returns only
            non-chat stream events.
        operationReturnFullProductInfo:
          type: boolean
          default: false
          description: >-
            When `false`, products in a conversation response payload are
            reduced to `{"id": "..."}` objects. When `true`, the full product
            objects are returned.
    ChatMetadata:
      type: object
      description: Optional context from the current product or page.
      properties:
        productId:
          type: string
          description: Current product identifier.
        variantId:
          type: string
          description: Current product variant identifier.
        title:
          type: string
          description: Current product or page title.
        websiteUrl:
          type: string
          format: uri
          description: URL of the current storefront page.
  responses:
    CoreIntentStream:
      description: >-
        A server-sent event stream. Each message is written as `data: <JSON>`
        followed by a blank line. The JSON payload contains one response key.
        `operationHideAiMessage` removes `chatStream` events;
        `operationReturnFullProductInfo` controls whether product payloads
        contain IDs only or full product objects.
      headers:
        Cache-Control:
          description: Disables caching of the event stream.
          schema:
            type: string
            example: no-cache
        X-Accel-Buffering:
          description: Disables proxy buffering so events reach the client immediately.
          schema:
            type: string
            example: 'no'
      content:
        text/event-stream:
          schema:
            type: string
            description: >-
              A sequence of SSE messages whose data values follow the
              `StreamEvent` schema.
          example: >+
            data: {"chatStream":"I found several products that match your
            request."}


            data:
            {"data":{"responseType":"ProductSearch","sessionId":"session-123","visitorId":"visitor-456","responsePayload":[{"id":"product-123"}],"hasMoreProducts":false,"total":1}}

    BadRequest:
      description: >-
        The operation could not be completed because the downstream AI request
        was invalid.
    Unauthorized:
      description: >-
        The operation token is missing, invalid, expired, or belongs to a
        different tenant.
    Forbidden:
      description: >-
        The `Tenantid` header is missing, the tenant is inactive, or the tenant
        has exceeded its usage allowance.
      content:
        text/plain:
          schema:
            type: string
          example: Tenant ID Invalid.
    TenantNotFound:
      description: No tenant exists for the supplied `Tenantid` value.
      content:
        text/plain:
          schema:
            type: string
          example: 'Tenant tenant-123 not found #000'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        A short-lived HS256 operation token. Its `tenantId` claim must exactly
        match the `Tenantid` header. Mint this token on a trusted server; never
        expose the tenant signing credential in browser code.
    tenantId:
      type: apiKey
      in: header
      name: Tenantid
      description: >-
        The preezie tenant identifier. This value identifies the catalogue and
        is not a secret.

````