curl --request GET \
--url https://{base-address}/discovery/search \
--header 'x-environment-id: <x-environment-id>' \
--header 'x-tenant-id: <x-tenant-id>' \
--header 'x-workspace-id: <x-workspace-id>'import requests
url = "https://{base-address}/discovery/search"
headers = {
"x-tenant-id": "<x-tenant-id>",
"x-workspace-id": "<x-workspace-id>",
"x-environment-id": "<x-environment-id>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {
'x-tenant-id': '<x-tenant-id>',
'x-workspace-id': '<x-workspace-id>',
'x-environment-id': '<x-environment-id>'
}
};
fetch('https://{base-address}/discovery/search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{base-address}/discovery/search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-environment-id: <x-environment-id>",
"x-tenant-id: <x-tenant-id>",
"x-workspace-id: <x-workspace-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://{base-address}/discovery/search"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-tenant-id", "<x-tenant-id>")
req.Header.Add("x-workspace-id", "<x-workspace-id>")
req.Header.Add("x-environment-id", "<x-environment-id>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://{base-address}/discovery/search")
.header("x-tenant-id", "<x-tenant-id>")
.header("x-workspace-id", "<x-workspace-id>")
.header("x-environment-id", "<x-environment-id>")
.asString();require 'uri'
require 'net/http'
url = URI("https://{base-address}/discovery/search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-tenant-id"] = '<x-tenant-id>'
request["x-workspace-id"] = '<x-workspace-id>'
request["x-environment-id"] = '<x-environment-id>'
response = http.request(request)
puts response.read_body{
"records": [
{
"id": "<string>",
"name": "<string>",
"sku": "<string>",
"provider_id": "<string>",
"brand": "<string>",
"description": "<string>",
"url": "<string>",
"primary_image_url": "<string>",
"type": "<string>",
"categories": [
"<string>"
],
"category_ids": [
"<string>"
],
"tags": [
"<string>"
],
"calculated_price": 123,
"reviews_count": 123,
"option_color": "<unknown>",
"selected_variant": {
"id": "<string>",
"name": "<string>",
"sku": "<string>",
"provider_id": "<string>",
"brand": "<string>",
"description": "<string>",
"primary_image_url": "<string>",
"categories": [
"<string>"
],
"option_color": "<string>",
"calculated_price": 123
},
"variants_map": [
{
"color": "<string>",
"sku": "<string>",
"price": 123,
"swatch_color": "<string>",
"primary_image_url": "<string>",
"product_url": "<string>"
}
],
"ranking_info": {
"overall_score": 123,
"relevance_score": 123,
"merchandising_score": 123,
"performance_score": 123,
"personalization_score": 123,
"newness_score": 123,
"position": 123,
"source": "<string>",
"result_from": "<string>"
}
}
],
"facets": [
{
"name": "<string>",
"field": "<string>",
"appearance": "<string>",
"values": [
{
"value": "<string>",
"display_value": "<string>",
"count": 123,
"image_url": "<string>",
"color": "<string>",
"min": 123,
"max": 123
}
],
"range": {},
"enable_multi_select": true,
"items_to_show": 123,
"show_count": true,
"show_search_within_facet": true,
"default_collapse_on_desktop": true,
"default_collapse_on_mobile": true,
"display_tooltip": true,
"tooltip": "<string>",
"layout_style": "<string>",
"display_layout": "<string>",
"star_color": "<string>"
}
],
"banners": [
{
"id": "<string>",
"position": 123,
"repeat_on_pagination": true,
"banner": {
"hide_on_desktop": true,
"hide_on_tablet": true,
"hide_on_mobile": true,
"desktop_config": {},
"tablet_config": {},
"mobile_config": {}
}
}
],
"meta": {
"total_count": 123,
"result_source": "<string>",
"did_you_mean": [
"<string>"
],
"corrected_search_term": "<string>",
"auto_spell_correction_applied": true,
"redirect_url": "<string>",
"tagged_attributes": [
{}
],
"merchandising_rules_applied": [
{
"id": "<string>",
"variant_id": "<string>"
}
],
"is_price_filter_dropped": true,
"experiments": {}
}
}{
"Status": "failure",
"Error": {
"message": "<string>",
"name": "<string>",
"code": "<string>"
}
}{
"Status": "failure",
"Error": {
"message": "<string>",
"name": "<string>",
"code": "<string>"
}
}Search Products
Query-string form of product search. Returns the matching products, along with facets, banners, and result metadata.
Every parameter goes in the query string. Structured fields such as facets and filters must be JSON-encoded; a malformed value is silently ignored rather than rejected.
curl --request GET \
--url https://{base-address}/discovery/search \
--header 'x-environment-id: <x-environment-id>' \
--header 'x-tenant-id: <x-tenant-id>' \
--header 'x-workspace-id: <x-workspace-id>'import requests
url = "https://{base-address}/discovery/search"
headers = {
"x-tenant-id": "<x-tenant-id>",
"x-workspace-id": "<x-workspace-id>",
"x-environment-id": "<x-environment-id>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {
'x-tenant-id': '<x-tenant-id>',
'x-workspace-id': '<x-workspace-id>',
'x-environment-id': '<x-environment-id>'
}
};
fetch('https://{base-address}/discovery/search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{base-address}/discovery/search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-environment-id: <x-environment-id>",
"x-tenant-id: <x-tenant-id>",
"x-workspace-id: <x-workspace-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://{base-address}/discovery/search"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-tenant-id", "<x-tenant-id>")
req.Header.Add("x-workspace-id", "<x-workspace-id>")
req.Header.Add("x-environment-id", "<x-environment-id>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://{base-address}/discovery/search")
.header("x-tenant-id", "<x-tenant-id>")
.header("x-workspace-id", "<x-workspace-id>")
.header("x-environment-id", "<x-environment-id>")
.asString();require 'uri'
require 'net/http'
url = URI("https://{base-address}/discovery/search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-tenant-id"] = '<x-tenant-id>'
request["x-workspace-id"] = '<x-workspace-id>'
request["x-environment-id"] = '<x-environment-id>'
response = http.request(request)
puts response.read_body{
"records": [
{
"id": "<string>",
"name": "<string>",
"sku": "<string>",
"provider_id": "<string>",
"brand": "<string>",
"description": "<string>",
"url": "<string>",
"primary_image_url": "<string>",
"type": "<string>",
"categories": [
"<string>"
],
"category_ids": [
"<string>"
],
"tags": [
"<string>"
],
"calculated_price": 123,
"reviews_count": 123,
"option_color": "<unknown>",
"selected_variant": {
"id": "<string>",
"name": "<string>",
"sku": "<string>",
"provider_id": "<string>",
"brand": "<string>",
"description": "<string>",
"primary_image_url": "<string>",
"categories": [
"<string>"
],
"option_color": "<string>",
"calculated_price": 123
},
"variants_map": [
{
"color": "<string>",
"sku": "<string>",
"price": 123,
"swatch_color": "<string>",
"primary_image_url": "<string>",
"product_url": "<string>"
}
],
"ranking_info": {
"overall_score": 123,
"relevance_score": 123,
"merchandising_score": 123,
"performance_score": 123,
"personalization_score": 123,
"newness_score": 123,
"position": 123,
"source": "<string>",
"result_from": "<string>"
}
}
],
"facets": [
{
"name": "<string>",
"field": "<string>",
"appearance": "<string>",
"values": [
{
"value": "<string>",
"display_value": "<string>",
"count": 123,
"image_url": "<string>",
"color": "<string>",
"min": 123,
"max": 123
}
],
"range": {},
"enable_multi_select": true,
"items_to_show": 123,
"show_count": true,
"show_search_within_facet": true,
"default_collapse_on_desktop": true,
"default_collapse_on_mobile": true,
"display_tooltip": true,
"tooltip": "<string>",
"layout_style": "<string>",
"display_layout": "<string>",
"star_color": "<string>"
}
],
"banners": [
{
"id": "<string>",
"position": 123,
"repeat_on_pagination": true,
"banner": {
"hide_on_desktop": true,
"hide_on_tablet": true,
"hide_on_mobile": true,
"desktop_config": {},
"tablet_config": {},
"mobile_config": {}
}
}
],
"meta": {
"total_count": 123,
"result_source": "<string>",
"did_you_mean": [
"<string>"
],
"corrected_search_term": "<string>",
"auto_spell_correction_applied": true,
"redirect_url": "<string>",
"tagged_attributes": [
{}
],
"merchandising_rules_applied": [
{
"id": "<string>",
"variant_id": "<string>"
}
],
"is_price_filter_dropped": true,
"experiments": {}
}
}{
"Status": "failure",
"Error": {
"message": "<string>",
"name": "<string>",
"code": "<string>"
}
}{
"Status": "failure",
"Error": {
"message": "<string>",
"name": "<string>",
"code": "<string>"
}
}facets and filters must be JSON-encoded into the query string; a malformed value is silently ignored rather than rejected, so an encoding mistake looks like the parameter having no effect. To send them as real JSON, use Search Products (POST).Headers
Identifies your organization. Ensures data isolation per tenant.
Identifies the workspace within your organization. Scopes resources to a specific workspace.
Identifies the environment you are targeting. Scopes the call to a specific deployment environment.
Query Parameters
The catalog to search. Every request is scoped to a single catalog.
The shopper's search term. Leave it out to browse instead of search — combine that with category_id or collection_id to list everything in a category or collection.
Locale to run the search in, such as en-us. Determines which localized product content is matched and returned.
Restrict results to a single category, identified by its id in your commerce platform.
Restrict results to a single Experro collection, identified by its Experro collection id.
Restrict results to a single category by name rather than id. Use this when you have the category name but not its id.
Fields to return for each product. Complex/nested field: pass as a JSON-encoded string. Parsed server-side by SearchProductsGetQuery::into_payload_parts.
Free-text name of the field to sort by, for example price.
"price"
Sort direction, paired with sort_by.
asc— lowest to highest.desc— highest to lowest. This is the default.
Case-insensitive; any other value falls back to descending.
asc, desc Body-level user id passed to search_params (distinct from the x-user-id header).
Facet selections used to narrow the search. One entry per faceted field, each shaped { "field": ..., "value": { "value": ..., "min": ..., "max": ... } } — set value.value for a categorical facet, or value.min and value.max for a numeric range facet. Pass as a JSON-encoded string; it is parsed server-side. A malformed value is silently ignored rather than rejected.
Filter criteria applied to the search. Each entry is either a condition { "action": ..., "field": ..., "value": ... } or a nested group { "group": { "operator": "and" | "or", "rules": [ ... ] } }. action is one of equals, not_equals, greater_than, less_than, greater_than_or_equal, less_than_or_equal, contains, or not_contains. A condition value may be a single value, a two-element [min, max] array for a range, or an array of values for membership. Pass as a JSON-encoded string; it is parsed server-side. A malformed value is silently ignored rather than rejected.
Controls how out-of-stock products are treated in results.
Include— included and ranked normally.Exclude— removed from results entirely.Burry— included but ranked lower.
Include, Exclude, Burry Groups variant results by a product attribute for variant and swatch mapping. Each entry is { "name": ..., "field": ... }. Complex/nested field: pass as a JSON-encoded string. Parsed server-side by SearchProductsGetQuery::into_payload_parts.
Computed aggregate values returned per variation group. Each entry is { "name": ..., "aggregation": ..., "field": ..., "value": null }, where aggregation is one of First, Last, Min, Max, Count, Avg, Sum, FieldCount, or ValueCount. Complex/nested field: pass as a JSON-encoded string. Parsed server-side by SearchProductsGetQuery::into_payload_parts.
Forces which variant option is shown as the hero, meaning the default image, for a product. Shaped { "field": ..., "value": ... }. Complex/nested field: pass as a JSON-encoded string. Parsed server-side by SearchProductsGetQuery::into_payload_parts.
Complex/nested field: pass as a JSON-encoded string. Parsed server-side by SearchProductsGetQuery::into_payload_parts.
Response
Success.
The product-search payload. Returned at the top level, with no envelope.
Ranked product records for the current page.
Show child attributes
Show child attributes
Facets generated for the result set. Null when skip_facet_generation is true.
Show child attributes
Show child attributes
Banners to render alongside the results. Null when none apply.
Show child attributes
Show child attributes
Result metadata for the query.
Show child attributes
Show child attributes