Malachyte Portal/Product Listing 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
  • Flexible retrieval via pagination and infinite scroll
  • Frontend-driven execution with backend-managed intelligence
  • Collection-governed behavior with merchandising, 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/plpReturns the ranked product grid for a Shopify collection
POST /v1/plp/filterApplies filters to an existing PLP result set
POST /v1/plp/sortApplies a sort order to an existing PLP result set

POST /v1/plp

Returns the ranked product grid for a Shopify collection, including pinning, banner injection, and ranking layers.

Request Body Fields

FieldTypeRequiredDescription
collection_idstringYesShopify Collection ID
strategy_namestringYesAlways "plp"
knumberConditionallyRequired for first request or large-k mode
from_portalbooleanYesMust be false for end-user traffic
log_responsebooleanYesMust be true for attribution
visitor_idstring (UUID)YesPersistent identifier for analytics

Example Request

POST /v1/plp

{
  "collection_id": "gid://shopify/Collection/123456789",
  "strategy_name": "plp",
  "k": 24,
  "from_portal": false,
  "log_response": true,
  "visitor_id": "3e92322a-d473-4c81-ab80-82dba7c31e65"
}

Response

The response includes:

  • Ranked products with merchandising rules applied
  • Pinned products in their designated positions
  • Injected banners at their configured slots
  • Available filters from allowed_filter_attributes
  • Pagination metadata for subsequent requests

Pagination & Infinite Scroll

PLPs support pagination and infinite scroll using the same pattern as Search.

First Request

Option A — Payload-driven

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

Option B — Query-driven

  • Include page and size in the query string
  • Do not include k in the request body

Subsequent Requests

For infinite scroll or pagination:

POST /v1/plp?page=2&size=24

{
  "collection_id": "gid://shopify/Collection/123456789",
  "strategy_name": "plp",
  "from_portal": false,
  "log_response": true,
  "visitor_id": "3e92322a-d473-4c81-ab80-82dba7c31e65"
}

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


POST /v1/plp/filter

Applies filters to an existing PLP result set. Mirrors /v1/search/filter but is collection-scoped and whitelist-enforced.

Request Fields

FieldTypeDescription
resultsarrayCurrent PLP result set (or opaque reference)
filtersobjectFilters to apply

Behavior

  • Filters are validated against allowed_filter_attributes (post-reconciliation)
  • Filter application occurs within the bounds of the collection dataset
  • Invalid filters (not in whitelist) are rejected

Example Request

POST /v1/plp/filter

{
  "results": "plp_result_reference_id",
  "filters": {
    "color": ["Black", "White"],
    "size": ["M", "L"]
  }
}

POST /v1/plp/sort

Applies a sort order to an existing PLP result set. Mirrors /v1/search/sort.

Supported Sort Orders

ValueDescription
RECOMMENDEDDefault relevance/ranking score
A_ZAlphabetical (A to Z)
Z_AAlphabetical (Z to A)
HIGH_LOWPrice: High to Low
LOW_HIGHPrice: Low to High
NEW_OLDNewest to Oldest
OLD_NEWOldest to Newest

Example Request

POST /v1/plp/sort

{
  "results": "plp_result_reference_id",
  "sort": "LOW_HIGH"
}

[!NOTE] Sorting must not override dataset-shaping rules (Hide / Only Show) nor explicit positional controls (Pinning). Pinned products remain in position regardless of sort order.


Filter API (Portal)

Display (Read)

GET /collections/:id/filters

Returns candidate attributes and allowed filter attributes for a collection.

Steps:

  1. Compute candidateAttributes from collection products
  2. Read allowed_filter_attributes
  3. Reconcile (remove dead attributes)
  4. Return both arrays

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.

Steps:

  1. Compute candidateAttributes
  2. Filter submitted array against candidates
  3. Save as new allowed_filter_attributes
  4. Return updated array

Attribution & Identity

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

  • log_response = true — Enables full attribution tracking across views, clicks, and conversions
  • visitor_id — A persistent identifier (UUID) ensuring consistent identity and accurate analytics across sessions