Malachyte Portal/Pages

API

API reference for the Product Listing Pages Engine

PLP API — Design Overview

Purpose

The PLP API powers collection-based product listing pages while supporting:

  • Accurate attribution across views, clicks, and conversions with background engagement logging
  • Category-scoped listing & search allowing default category browsing or in-category keyword searches
  • Dynamic filtering & sorting directly in the listing request
  • Flexible retrieval via single large-k retrieval, payload-driven pagination, or query-driven pagination / infinite scroll
  • Frontend-driven execution with backend-managed intelligence and component strategy resolution
  • Collection-governed behavior with merchandising rules, pinning, and banner injection

Core Endpoints

PLP runtime behavior mirrors Malachyte Search's endpoint pattern, but is collection-governed and routed through PLP-specific endpoints.

EndpointDescription
POST /v1/listing/{category_id}Lists or searches products for a given category/collection with optional filters, sort order, and pagination

POST /v1/listing/{category_id}

Lists products for a given category.

By default, the endpoint queries all results for the specified category. If a query string is provided in the request body, it returns products in that category matching the string after executing data retrieval, pre-search category filtering, scoring, and sequencing operations. Filters and sort order can be applied directly in the request payload. The endpoint also asynchronously logs engagement views and impressions in the background.

Path Parameters

ParameterTypeRequiredDescription
category_idstringYesThe category or Shopify collection identifier to list/search products for.

Query Parameters

ParameterTypeRequiredDescription
pageintegerOptionalFor paginated results, the page number to retrieve (1-indexed).
sizeintegerOptionalFor paginated results, the number of items per page.

Request Body Fields

FieldTypeRequiredDescription
search_component_idstring (UUID)YesThe UUID of the search component configured in Malachyte that defines the search logic, strategy, and ranking rules. It's available via the portal.
visitor_idstring (UUID)YesPersistent unique identifier for anonymous or authenticated visitors, used for session continuity and attribution.
querystringOptionalSearch query to filter products within the category.
kintegerConditionallyNumber of items to return. Required for Large-k mode or payload-driven pagination.
search_filtersFilter[]OptionalList of Filter objects to apply during search / listing retrieval.
sort_orderstring (SortOrder)OptionalSort order to apply to the results. Default is "RECOMMENDED".
return_filtersbooleanOptionalWhether to return assigned filter values, search filter definitions, and facet options in the response. Defaults to true.
user_idstringOptionalThe unique identifier of the authenticated user. Should be left blank if the user is unauthenticated.

Filtering in the Listing Request

You can pass structured filters directly to POST /v1/listing/{category_id} via search_filters.

Filter Object Structure

Each filter object conforms to the following schema:

FieldTypeRequiredDescription
jsonpathstringOptionalJSONPath expression for querying nested JSON metadata/facts.

Supported Comparison Operators

OperatorDescriptionExample Values / Usage
JSONPATHEvaluates a JSONPath query against item facts{"key": "facts", "jsonpath": "$.specs.waterproof", "values": [true], "comparison": "JSONPATH"}

Supported Sort Orders

Sort ValueDescription
RECOMMENDEDDefault relevance/ranking score computed by the strategy (Default)
A_ZAlphabetical (A to Z)
Z_AReverse Alphabetical (Z to A)
HIGH_LOWPrice: High to Low
LOW_HIGHPrice: Low to High
NEW_OLDRelease/Updated date: Newest to Oldest
OLD_NEWRelease/Updated date: Oldest to Newest

Example Requests

1. Category Listing with Filters and Sort Order

Retrieve products in a collection filtered by color and price range, sorted by price low to high:

POST /v1/listing/123456789

{
  "search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
  "visitor_id": "3e92322a-d473-4c81-ab80-82dba7c31e65",
  "k": 24,
  "sort_order": "LOW_HIGH",
  "search_filters": [
    {
      "key": "color",
      "values": ["Black", "Navy"],
      "comparison": "EQUAL"
    },
    {
      "key": "price",
      "values": [50.0, 200.0],
      "comparison": "BETWEEN"
    }
  ],
  "return_filters": true
}

2. In-Category Search with Filtering

Search within the collection "123456789", filtered by size:

POST /v1/listing/123456789

{
  "search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
  "visitor_id": "3e92322a-d473-4c81-ab80-82dba7c31e65",
  "query": "",
  "k": 24,
  "search_filters": [
    {
      "key": "size",
      "values": ["L", "XL"],
      "comparison": "EQUAL"
    }
  ]
}

3. Paginated Request with Filters

POST /v1/listing/123456789?page=2&size=24

{
  "search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
  "visitor_id": "3e92322a-d473-4c81-ab80-82dba7c31e65",
  "search_filters": [
    {
      "key": "color",
      "values": ["Black"],
      "comparison": "EQUAL"
    }
  ]
}

Response (RecommendationsResponse)

When return_filters=true, the response includes product results, merchandising metadata, and available filter facet statistics:

{
  "strategy_name": "plp",
  "total_results": 42,
  "results": [
    {
      "score": 0.94,
      "facts": {
        "id": "1001",
        "title": "Classic Cotton Blazer",
        "price": 120.0,
        "color": "Black",
        "size": "L"
      }
    }
  ],
  "assigned_filter_values": {
    "color": ["Black", "Navy"],
    "price": [50.0, 200.0]
  },
  "options": [
    {
      "key": "color",
      "values_w_stats": {
        "Black": 24,
        "Navy": 18,
        "White": 12
      },
      "assigned_filter_values": ["Black", "Navy"]
    },
    {
      "key": "size",
      "values_w_stats": {
        "S": 10,
        "M": 22,
        "L": 19,
        "XL": 8
      },
      "assigned_filter_values": []
    }
  ]
}

Error Responses

Status CodeDescriptionReason
400 Bad RequestMalformed requestMissing category_id in path or missing search_component_id in the request body.
404 Not FoundNo results foundNo matching products found or all candidate products were filtered out.
422 Unprocessable EntityValidation errorInvalid request payload or parameter types.

Pagination & Infinite Scroll

Product Listing Pages support flexible retrieval modes matching the Search workflow:

Pagination & Infinite Scroll

First Request (Choose One)

Option A — Query-driven (preferred)

  • Include page and size in the URL query parameters.
  • Do not include k in the request body.

POST /v1/listing/123456789?page=1&size=24

{
  "search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
  "visitor_id": "3e92322a-d473-4c81-ab80-82dba7c31e65"
}

Option B — Payload-driven

  • Pass k in the request body.
  • Do not include query parameters in the URL.

POST /v1/listing/123456789

{
  "search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
  "visitor_id": "3e92322a-d473-4c81-ab80-82dba7c31e65",
  "k": 24
}

Subsequent Requests

For infinite scroll or subsequent pages, pass page and size query parameters:

POST /v1/listing/123456789?page=2&size=24

{
  "search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
  "visitor_id": "3e92322a-d473-4c81-ab80-82dba7c31e65"
}

Subsequent page requests retrieve additional slices of the same shaped dataset. Pinning, banners, and ranking are already applied and remain consistent across pages.

Filter Configuration API (Portal)

Display (Read)

GET /collections/:id/filters

Returns candidate attributes and allowed filter attributes for a collection.

Response:

{
  "candidateAttributes": ["color", "size", "material", "price", "vendor"],
  "allowed_filter_attributes": ["color", "size", "price"]
}

Edit (Write)

PUT /collections/:id/filters

Updates the allowed filter attributes for a collection.


Attribution & Identity

[!TIP] Data Integrity & Tracking These fields are essential for measuring PLP performance and ROI.

  • visitor_id — A persistent identifier (UUID) ensuring consistent visitor identity and accurate analytics across sessions.