Malachyte Portal/Search

Search API

API reference for Malachyte Search

Purpose

The Search API powers shopper-facing search while supporting:

  • Accurate attribution across search, clicks, and conversions.
  • Flexible retrieval via either large-k retrieval or pagination.
  • Frontend-driven execution with backend-managed intelligence.

Note

Flexible Implementation Search can be implemented in two ways:

  1. A fallback when an existing search fails.
  2. A full replacement for an existing search engine.

Capabilities

  • Built-in filtering and sorting in the same /v1/search/component call
  • Typo-tolerant fuzzy matching
  • Synonym handling and redirect logic to recover poor or uncommon queries (see Synonyms)

Search behavior is configured in the Portal, so it can be changed without frontend code changes or redeploys. Queries can be tested in the Search Playground.


Authentication

Every request must include the API key in the request header.

HeaderTypeDescription
x-api-keystringMalachyte API key
Content-Typestringapplication/json

Base URL: https://api-yoursite.malachyte.com (the client's Malachyte contact provides the exact URL for each store).


Endpoint

POST /v1/search/component

Retrieval Modes (Choose Exactly One)

Important

Exactly one retrieval model must be selected per search session. Mixing parameters between these modes will result in an error.


Option 1: Large-k Mode (Single Full Result Set)

Use this to get the entire result set in a single response.

Rules:

  • k must be provided in the request body.
  • Pagination parameters (page, size) are not allowed.
  • No follow-up page requests.

Example Request: POST /v1/search/component

{
"query": "White Dress",
"search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
"k": 500,
"visitor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Option 2: Pagination Mode

Used for paged results or infinite scroll.

First Request (Choose One)

Option A — Query-driven

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

Example Request: POST /v1/search/component?page=1&size=20

{
"query": "White Dress",
"search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
"visitor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Option B — Payload-driven

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

Example Request: POST /v1/search/component

{
"query": "White Dress",
"search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
"k": 20,
"visitor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Subsequent Requests

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

Example Request:

POST /v1/search/component?page=2&size=20

{
"query": "White Dress",
"search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
"visitor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Pagination Details

Pagination Parameters

Use these query parameters in Pagination Mode (Option A):

ParameterTypeBehavior
pageIntegerWhich page of results to return. Pages start at 1.
sizeIntegerHow many results to return per page.

For example, with size=40, page=1 returns results 1–40 and page=2 returns results 41–80 (for example, when the shopper clicks "Page 2" or "Load more").

Total Result Count

The search response can include a total count of matching results, which can be used for display text like "Showing 41–80 of 312 results."

{
"strategy_name": "search",
"total_results": 312,
"results": [...]
}
  • Estimated before filters: The count is calculated before any filters (price, size, color, etc.) are applied, so a filtered search may show a higher total than the number of results that can actually be paged through.
  • Capped at 10,000: Very broad searches will report a maximum of 10,000 results.

Important

Treat the total count as an estimate when filters are active. Use it for display text, not to calculate the exact number of pages.

Pagination Depth

Search ranks a fixed number of top results. Within that depth, results stay in a consistent order across pages.

Note

If a shopper pages beyond the ranking depth, the order of results may shift. In practice few shoppers go that deep (for example, 500+ results in).

Implementation Checklist

StepActionPurpose
1Send page=1 with the chosen sizeLoad the first page
2Increase page by 1 for each new pageLoad the next set of results
3Keep size the same across pagesKeep pages consistent
4Use the total count for display text onlyAvoid errors when filters are active

Request Body Fields

FieldTypeRequiredDescription
querystringYesSearch term entered by the shopper.
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)YesIdentifier for the shopper's current session, used for attribution and analytics. Keep it the same for the whole session.
kintegerConditionallyNumber of items to return. Required for Large-k mode or the first request in Pagination Option B.
search_filtersFilter[]OptionalList of Filter objects to apply to the results. Uses the same Filter object as the PLP API.
catalogintegerOptionalThe catalog identifier. Only needed if the store has more than one catalog (for example, two storefronts or brands under one Malachyte account). Leave it out otherwise. The client's Malachyte contact provides the value.
sort_orderstring (SortOrder)OptionalSort order to apply to the results. Default is "RECOMMENDED". See Supported Sort Orders below.
return_filtersbooleanOptionalWhether to return assigned filter values, search filter definitions, and facet options in the response. Defaults to true.
allow_empty_querybooleanOptionalWhether to return results when query is an empty string.
user_idstringOptionalThe unique identifier of the logged-in shopper. It stays the same across sessions. Leave blank if the shopper isn't logged in.

Filtering and Sorting

Filtering and sorting are handled within the POST /v1/search/component call described above.

  • Filtering: pass search_filters in the request body. Search uses the same Filter object as PLP. See Filtering in the Listing Request for the full structure and supported operators.
  • Sorting: pass sort_order in the request body. If it's left out, results use RECOMMENDED.

Supported Sort Orders

ValueDescription
RECOMMENDEDExisting relevance score (default)
A_ZAlphabetical (A → Z)
Z_AAlphabetical (Z → A)
HIGH_LOWPrice: High → Low
LOW_HIGHPrice: Low → High
NEW_OLDNewest → Oldest
OLD_NEWOldest → Newest

Example Request (filtered by color, sorted by price, low to high): POST /v1/search/component

{
"query": "White Dress",
"search_component_id": "7b6c5432-e89b-12d3-a456-426614174000",
"visitor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"k": 20,
"sort_order": "LOW_HIGH",
"search_filters": [
{
"key": "color",
"values": ["White"],
"comparison": "EQUAL"
}
],
"return_filters": true
}

Example Response

A trimmed response (2 of 83 results):

{
  "strategy_name": "search",
  "results": [
    { "score": 0.97, "facts": { "product_id": 123456 } },
    { "score": 0.96, "facts": { "product_id": 234567 } }
  ],
  "total_results": 83,
  "assigned_filter_values": {},
  "search_filters": []
}
  • results: the matching products, in ranked order. Each has a score and its product data in facts.
  • facts: the product fields set up for the search component. Some setups return only product_id, and the storefront looks up the rest of the product details itself.
  • total_results: the estimated number of matches. See Total Result Count.
  • assigned_filter_values / search_filters: filled in only when return_filters is true.

Error Responses

Errors return the matching HTTP status code and a JSON body with a detail message:

{
"detail": "Search component request must include a search_component_id"
}
Status CodeDescriptionReason
400 Bad RequestMalformed requestsearch_component_id is missing ("Search component request must include a search_component_id"), query is missing ("Malformed request: query missing"), or both user_id and visitor_id are missing ("Malformed request: user_id and visitor_id missing").
400 Bad RequestUnknown search componentThe search_component_id doesn't match a search component in the Portal ("Unknown Search Component: <id>").
404 Not FoundNo results foundNo matching products were found, or all results were filtered out ("No search results found: All candidates filtered, try loosening filter criteria.").
422 Unprocessable EntityValidation errorInvalid request payload or parameter types (for example, a string sent for k).
500 Internal Server ErrorUnexpected errorAn unexpected server error occurred ("internal_server_error").
503 Service UnavailableService unavailableMalachyte couldn't process the request right now. Retry the request; if the error persists, contact Malachyte.

Note

A 404 means the search ran but returned no results. Treat it as an empty result set (for example, show a "No results" message) rather than a failure.


Attribution & Identity

Tip

Data Integrity & Tracking These fields are essential for measuring search performance and ROI.

  • visitor_id: A UUID that identifies the shopper's current session. Keep it the same for the whole session.
  • user_id: Identifies a logged-in shopper and stays the same across sessions.

Testing in the Playground

Paginated results can be previewed in the Search Playground in the Portal. See Search Playground for how it works.