curl --request POST \
--url https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-shop: <x-shop>' \
--data '
{
"strategy_options": {},
"query": "<string>",
"filter": {
"variants": {
"options": [
{
"name": "<string>",
"value": "<string>"
}
],
"is_in_stock": true,
"sku": [
"<string>"
],
"available_for_sale": true
},
"tags": [
"<string>"
],
"excluded_tags": [
"<string>"
],
"vendors": [
"<string>"
],
"product_types": [
"<string>"
],
"collections": [
"<string>"
],
"price": {
"min": 123,
"max": 123
},
"metafields": [
{
"namespace": "<string>",
"key": "<string>",
"value": "<string>"
}
]
},
"facets": [],
"pagination": {
"cursor": "<string>",
"limit": 50
},
"publication_ids": [
"30085840999"
]
}
'import requests
url = "https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top"
payload = {
"strategy_options": {},
"query": "<string>",
"filter": {
"variants": {
"options": [
{
"name": "<string>",
"value": "<string>"
}
],
"is_in_stock": True,
"sku": ["<string>"],
"available_for_sale": True
},
"tags": ["<string>"],
"excluded_tags": ["<string>"],
"vendors": ["<string>"],
"product_types": ["<string>"],
"collections": ["<string>"],
"price": {
"min": 123,
"max": 123
},
"metafields": [
{
"namespace": "<string>",
"key": "<string>",
"value": "<string>"
}
]
},
"facets": [],
"pagination": {
"cursor": "<string>",
"limit": 50
},
"publication_ids": ["30085840999"]
}
headers = {
"x-shop": "<x-shop>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-shop': '<x-shop>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
strategy_options: {},
query: '<string>',
filter: {
variants: {
options: [{name: '<string>', value: '<string>'}],
is_in_stock: true,
sku: ['<string>'],
available_for_sale: true
},
tags: ['<string>'],
excluded_tags: ['<string>'],
vendors: ['<string>'],
product_types: ['<string>'],
collections: ['<string>'],
price: {min: 123, max: 123},
metafields: [{namespace: '<string>', key: '<string>', value: '<string>'}]
},
facets: [],
pagination: {cursor: '<string>', limit: 50},
publication_ids: ['30085840999']
})
};
fetch('https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top', 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://storefront.glood.ai/api/storefront/v3/headless/recommendations/top",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'strategy_options' => [
],
'query' => '<string>',
'filter' => [
'variants' => [
'options' => [
[
'name' => '<string>',
'value' => '<string>'
]
],
'is_in_stock' => true,
'sku' => [
'<string>'
],
'available_for_sale' => true
],
'tags' => [
'<string>'
],
'excluded_tags' => [
'<string>'
],
'vendors' => [
'<string>'
],
'product_types' => [
'<string>'
],
'collections' => [
'<string>'
],
'price' => [
'min' => 123,
'max' => 123
],
'metafields' => [
[
'namespace' => '<string>',
'key' => '<string>',
'value' => '<string>'
]
]
],
'facets' => [
],
'pagination' => [
'cursor' => '<string>',
'limit' => 50
],
'publication_ids' => [
'30085840999'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"x-shop: <x-shop>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top"
payload := strings.NewReader("{\n \"strategy_options\": {},\n \"query\": \"<string>\",\n \"filter\": {\n \"variants\": {\n \"options\": [\n {\n \"name\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"is_in_stock\": true,\n \"sku\": [\n \"<string>\"\n ],\n \"available_for_sale\": true\n },\n \"tags\": [\n \"<string>\"\n ],\n \"excluded_tags\": [\n \"<string>\"\n ],\n \"vendors\": [\n \"<string>\"\n ],\n \"product_types\": [\n \"<string>\"\n ],\n \"collections\": [\n \"<string>\"\n ],\n \"price\": {\n \"min\": 123,\n \"max\": 123\n },\n \"metafields\": [\n {\n \"namespace\": \"<string>\",\n \"key\": \"<string>\",\n \"value\": \"<string>\"\n }\n ]\n },\n \"facets\": [],\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"limit\": 50\n },\n \"publication_ids\": [\n \"30085840999\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-shop", "<x-shop>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top")
.header("x-shop", "<x-shop>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"strategy_options\": {},\n \"query\": \"<string>\",\n \"filter\": {\n \"variants\": {\n \"options\": [\n {\n \"name\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"is_in_stock\": true,\n \"sku\": [\n \"<string>\"\n ],\n \"available_for_sale\": true\n },\n \"tags\": [\n \"<string>\"\n ],\n \"excluded_tags\": [\n \"<string>\"\n ],\n \"vendors\": [\n \"<string>\"\n ],\n \"product_types\": [\n \"<string>\"\n ],\n \"collections\": [\n \"<string>\"\n ],\n \"price\": {\n \"min\": 123,\n \"max\": 123\n },\n \"metafields\": [\n {\n \"namespace\": \"<string>\",\n \"key\": \"<string>\",\n \"value\": \"<string>\"\n }\n ]\n },\n \"facets\": [],\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"limit\": 50\n },\n \"publication_ids\": [\n \"30085840999\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-shop"] = '<x-shop>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"strategy_options\": {},\n \"query\": \"<string>\",\n \"filter\": {\n \"variants\": {\n \"options\": [\n {\n \"name\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"is_in_stock\": true,\n \"sku\": [\n \"<string>\"\n ],\n \"available_for_sale\": true\n },\n \"tags\": [\n \"<string>\"\n ],\n \"excluded_tags\": [\n \"<string>\"\n ],\n \"vendors\": [\n \"<string>\"\n ],\n \"product_types\": [\n \"<string>\"\n ],\n \"collections\": [\n \"<string>\"\n ],\n \"price\": {\n \"min\": 123,\n \"max\": 123\n },\n \"metafields\": [\n {\n \"namespace\": \"<string>\",\n \"key\": \"<string>\",\n \"value\": \"<string>\"\n }\n ]\n },\n \"facets\": [],\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"limit\": 50\n },\n \"publication_ids\": [\n \"30085840999\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"status": "ok",
"serve_id": "7c3f5e8a-2b14-49c1-a7d3-93f4e2bb1c8e",
"strategy": "BESTSELLERS",
"products": [
{
"handle": "uno-usb-c-cable-100w",
"product_id": 8123456789012,
"title": "Uno USB-C to USB-C Cable 100W",
"vendor": "UGREEN",
"product_type": "Cable",
"tags": "cable, usb-c, fast-charge",
"price": 9.34,
"compare_at_price": 14.99,
"image": {
"id": "gid://shopify/ImageSource/33459800441029",
"url": "https://cdn.shopify.com/s/files/.../cable.jpg",
"altText": null,
"width": 1600,
"height": 1600
},
"variants": [],
"options": [],
"metafields": [],
"trending_rank": 3,
"sales_rank": 7
}
],
"pagination": {
"cursor": "eyJzIjpbMC44Mzc3LCI4MTIzNDU2Nzg5MDEyIl0sInNlc3Npb24iOiI1NWRhNDYzOS01MjE2LTRhODItYjJjZS01MWE1NzJmYzM1YzQifQ==",
"hasMore": true,
"total": 327,
"totalRelation": "eq",
"limit": 24
},
"facets": {
"vendor": [
{ "value": "UGREEN", "count": 142 },
{ "value": "Anker", "count": 98 }
],
"price": [
{ "min": 0, "max": 50, "count": 210 },
{ "min": 50, "max": 100, "count": 78 },
{ "min": 100, "max": 250, "count": 39 }
]
}
}
{
"errors": [
{
"message": "\"strategy\" is required",
"path": ["strategy"],
"type": "any.required",
"context": { "label": "strategy", "key": "strategy" }
}
]
}
{
"error": "Invalid authentication"
}
{
"error": "Too many requests, please try again later."
}
Get Top Recommendations
Fetch products by a ranking strategy (bestsellers, new arrivals) with rich criteria filters, full-text query, cursor pagination, and facet aggregations.
curl --request POST \
--url https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-shop: <x-shop>' \
--data '
{
"strategy_options": {},
"query": "<string>",
"filter": {
"variants": {
"options": [
{
"name": "<string>",
"value": "<string>"
}
],
"is_in_stock": true,
"sku": [
"<string>"
],
"available_for_sale": true
},
"tags": [
"<string>"
],
"excluded_tags": [
"<string>"
],
"vendors": [
"<string>"
],
"product_types": [
"<string>"
],
"collections": [
"<string>"
],
"price": {
"min": 123,
"max": 123
},
"metafields": [
{
"namespace": "<string>",
"key": "<string>",
"value": "<string>"
}
]
},
"facets": [],
"pagination": {
"cursor": "<string>",
"limit": 50
},
"publication_ids": [
"30085840999"
]
}
'import requests
url = "https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top"
payload = {
"strategy_options": {},
"query": "<string>",
"filter": {
"variants": {
"options": [
{
"name": "<string>",
"value": "<string>"
}
],
"is_in_stock": True,
"sku": ["<string>"],
"available_for_sale": True
},
"tags": ["<string>"],
"excluded_tags": ["<string>"],
"vendors": ["<string>"],
"product_types": ["<string>"],
"collections": ["<string>"],
"price": {
"min": 123,
"max": 123
},
"metafields": [
{
"namespace": "<string>",
"key": "<string>",
"value": "<string>"
}
]
},
"facets": [],
"pagination": {
"cursor": "<string>",
"limit": 50
},
"publication_ids": ["30085840999"]
}
headers = {
"x-shop": "<x-shop>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-shop': '<x-shop>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
strategy_options: {},
query: '<string>',
filter: {
variants: {
options: [{name: '<string>', value: '<string>'}],
is_in_stock: true,
sku: ['<string>'],
available_for_sale: true
},
tags: ['<string>'],
excluded_tags: ['<string>'],
vendors: ['<string>'],
product_types: ['<string>'],
collections: ['<string>'],
price: {min: 123, max: 123},
metafields: [{namespace: '<string>', key: '<string>', value: '<string>'}]
},
facets: [],
pagination: {cursor: '<string>', limit: 50},
publication_ids: ['30085840999']
})
};
fetch('https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top', 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://storefront.glood.ai/api/storefront/v3/headless/recommendations/top",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'strategy_options' => [
],
'query' => '<string>',
'filter' => [
'variants' => [
'options' => [
[
'name' => '<string>',
'value' => '<string>'
]
],
'is_in_stock' => true,
'sku' => [
'<string>'
],
'available_for_sale' => true
],
'tags' => [
'<string>'
],
'excluded_tags' => [
'<string>'
],
'vendors' => [
'<string>'
],
'product_types' => [
'<string>'
],
'collections' => [
'<string>'
],
'price' => [
'min' => 123,
'max' => 123
],
'metafields' => [
[
'namespace' => '<string>',
'key' => '<string>',
'value' => '<string>'
]
]
],
'facets' => [
],
'pagination' => [
'cursor' => '<string>',
'limit' => 50
],
'publication_ids' => [
'30085840999'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"x-shop: <x-shop>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top"
payload := strings.NewReader("{\n \"strategy_options\": {},\n \"query\": \"<string>\",\n \"filter\": {\n \"variants\": {\n \"options\": [\n {\n \"name\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"is_in_stock\": true,\n \"sku\": [\n \"<string>\"\n ],\n \"available_for_sale\": true\n },\n \"tags\": [\n \"<string>\"\n ],\n \"excluded_tags\": [\n \"<string>\"\n ],\n \"vendors\": [\n \"<string>\"\n ],\n \"product_types\": [\n \"<string>\"\n ],\n \"collections\": [\n \"<string>\"\n ],\n \"price\": {\n \"min\": 123,\n \"max\": 123\n },\n \"metafields\": [\n {\n \"namespace\": \"<string>\",\n \"key\": \"<string>\",\n \"value\": \"<string>\"\n }\n ]\n },\n \"facets\": [],\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"limit\": 50\n },\n \"publication_ids\": [\n \"30085840999\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-shop", "<x-shop>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top")
.header("x-shop", "<x-shop>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"strategy_options\": {},\n \"query\": \"<string>\",\n \"filter\": {\n \"variants\": {\n \"options\": [\n {\n \"name\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"is_in_stock\": true,\n \"sku\": [\n \"<string>\"\n ],\n \"available_for_sale\": true\n },\n \"tags\": [\n \"<string>\"\n ],\n \"excluded_tags\": [\n \"<string>\"\n ],\n \"vendors\": [\n \"<string>\"\n ],\n \"product_types\": [\n \"<string>\"\n ],\n \"collections\": [\n \"<string>\"\n ],\n \"price\": {\n \"min\": 123,\n \"max\": 123\n },\n \"metafields\": [\n {\n \"namespace\": \"<string>\",\n \"key\": \"<string>\",\n \"value\": \"<string>\"\n }\n ]\n },\n \"facets\": [],\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"limit\": 50\n },\n \"publication_ids\": [\n \"30085840999\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-shop"] = '<x-shop>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"strategy_options\": {},\n \"query\": \"<string>\",\n \"filter\": {\n \"variants\": {\n \"options\": [\n {\n \"name\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"is_in_stock\": true,\n \"sku\": [\n \"<string>\"\n ],\n \"available_for_sale\": true\n },\n \"tags\": [\n \"<string>\"\n ],\n \"excluded_tags\": [\n \"<string>\"\n ],\n \"vendors\": [\n \"<string>\"\n ],\n \"product_types\": [\n \"<string>\"\n ],\n \"collections\": [\n \"<string>\"\n ],\n \"price\": {\n \"min\": 123,\n \"max\": 123\n },\n \"metafields\": [\n {\n \"namespace\": \"<string>\",\n \"key\": \"<string>\",\n \"value\": \"<string>\"\n }\n ]\n },\n \"facets\": [],\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"limit\": 50\n },\n \"publication_ids\": [\n \"30085840999\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"status": "ok",
"serve_id": "7c3f5e8a-2b14-49c1-a7d3-93f4e2bb1c8e",
"strategy": "BESTSELLERS",
"products": [
{
"handle": "uno-usb-c-cable-100w",
"product_id": 8123456789012,
"title": "Uno USB-C to USB-C Cable 100W",
"vendor": "UGREEN",
"product_type": "Cable",
"tags": "cable, usb-c, fast-charge",
"price": 9.34,
"compare_at_price": 14.99,
"image": {
"id": "gid://shopify/ImageSource/33459800441029",
"url": "https://cdn.shopify.com/s/files/.../cable.jpg",
"altText": null,
"width": 1600,
"height": 1600
},
"variants": [],
"options": [],
"metafields": [],
"trending_rank": 3,
"sales_rank": 7
}
],
"pagination": {
"cursor": "eyJzIjpbMC44Mzc3LCI4MTIzNDU2Nzg5MDEyIl0sInNlc3Npb24iOiI1NWRhNDYzOS01MjE2LTRhODItYjJjZS01MWE1NzJmYzM1YzQifQ==",
"hasMore": true,
"total": 327,
"totalRelation": "eq",
"limit": 24
},
"facets": {
"vendor": [
{ "value": "UGREEN", "count": 142 },
{ "value": "Anker", "count": 98 }
],
"price": [
{ "min": 0, "max": 50, "count": 210 },
{ "min": 50, "max": 100, "count": 78 },
{ "min": 100, "max": 250, "count": 39 }
]
}
}
{
"errors": [
{
"message": "\"strategy\" is required",
"path": ["strategy"],
"type": "any.required",
"context": { "label": "strategy", "key": "strategy" }
}
]
}
{
"error": "Invalid authentication"
}
{
"error": "Too many requests, please try again later."
}
Overview
The top recommendations endpoint lets headless storefronts fetch products without a seed anchor — unlike/recommendations and /recommendations/automatic, no product_ids are required. It is the right endpoint for:
- Catalog / collection landing pages (“Bestsellers”, “New arrivals”)
- Search results constrained by a strategy (e.g. bestsellers matching “wireless charger”)
- Merchandising widgets that need filtered top-N lists with facet sidebars
/recommendations/automatic — same filter shape, same Joi schema — extended with four additional dimensions (excluded_tags, collections, product_types, price). Those extensions are also accepted by the automatic endpoint going forward.
Authorization: Bearer <shop storefront token> and x-shop: <myshopify domain> on every call. See Get Started → Headless Authentication for token provisioning.Ranking strategies
| Strategy | What it returns |
|---|---|
BESTSELLERS | Products ranked by revenue over the last 7, 15, or 30 days (selectable via strategy_options.sales_time_period, default 7). |
NEW_ARRIVALS | Most recently published products. |
Filter dimensions
filter is fully optional. Each sub-field is independently optional and combined as an AND:
tags/excluded_tags— include / exclude by product tag.vendors— vendor names (exact match).product_types— product type values.collections— collection IDs the product must belong to.price.min/price.max— price range in shop currency.variants.is_in_stock,variants.available_for_sale— variant-level availability (matches any variant).variants.options[]— variant option matches (e.g.Color: Black).variants.sku[]— variant SKU match.metafields[]— match by{namespace, key, value}; requires afilterKeyto exist on the indexed product.
tags, excluded_tags, vendors, product_types, and collections accept either a JSON array of strings or a single comma-separated string. Useful for clients whose query serializers can’t construct arrays from variables. Both forms below are equivalent:{ "filter": { "tags": ["new", "sale", "featured"] } }
{ "filter": { "tags": "new,sale,featured" } }
Text query
Whenquery is provided, a multi_match clause is added across title^3, description, tags, vendor, productType with operator: AND, lenient: true. The strategy sort still wins — products matching the text query are ranked by sales (or recency), not by BM25 relevance. For relevance-first text search, use the AI Search endpoint instead.
Facets
Passfacets: ["vendor", "product_type", "tag", "price"] (any subset) to receive aggregations alongside the products. Each facet returns top values with counts. The price facet returns fixed buckets (0-50, 50-100, 100-250, 250+).
Facet counts are computed using a post-filter model — each facet’s counts ignore that dimension’s filter so a sidebar UI can show “all available vendors” even when the user has selected one. Other filters still apply.
Pagination
Cursor-based, matching the rest of the v3 headless surface. The first request can passpagination.limit (1–100, default 24). Subsequent pages pass the cursor returned in the previous response.
cursor, the filter, query, and strategy must stay identical to the request that produced the cursor — changing them invalidates the sort context and returns incoherent ordering.pagination.total and pagination.totalRelation ("eq" or "gte"). Elasticsearch caps totals at 10,000 by default — when the relation is "gte", the real total is ≥ that value.
Examples
curl -sS -X POST 'https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <shop-storefront-token>' \
-H 'x-shop: shop.myshopify.com' \
-d '{
"strategy": "BESTSELLERS",
"view": "product_details"
}'
curl -sS -X POST 'https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <shop-storefront-token>' \
-H 'x-shop: shop.myshopify.com' \
-d '{
"strategy": "NEW_ARRIVALS",
"view": "product_details",
"query": "wireless charger",
"filter": {
"price": { "min": 20.00, "max": 80.00 },
"variants": { "is_in_stock": true }
},
"facets": ["vendor", "price"],
"pagination": { "limit": 24 }
}'
curl -sS -X POST 'https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <shop-storefront-token>' \
-H 'x-shop: shop.myshopify.com' \
-d '{
"strategy": "BESTSELLERS",
"view": "product_details",
"query": "cable",
"filter": {
"tags": ["holiday-2026"],
"excluded_tags": ["clearance", "discontinued"],
"vendors": ["UGREEN"],
"product_types": ["Cable", "Hub"],
"collections": ["345678901", "456789012"],
"metafields": [
{ "namespace": "custom", "key": "gender", "value": "unisex" }
],
"variants": {
"is_in_stock": true,
"available_for_sale": true,
"options": [{ "name": "Length", "value": "2m" }]
},
"price": { "min": 5.00, "max": 50.00 }
},
"facets": ["vendor", "product_type", "tag", "price"],
"pagination": { "limit": 24 }
}'
curl -sS -X POST 'https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <shop-storefront-token>' \
-H 'x-shop: shop.myshopify.com' \
-d '{
"strategy": "BESTSELLERS",
"strategy_options": { "sales_time_period": 30 },
"view": "product_details",
"filter": { "collections": ["123456789"] },
"pagination": { "limit": 12 }
}'
curl -sS -X POST 'https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <shop-storefront-token>' \
-H 'x-shop: shop.myshopify.com' \
-d '{
"strategy": "BESTSELLERS",
"view": "product_details",
"filter": { "price": { "min": 20.00, "max": 80.00 } },
"pagination": {
"cursor": "eyJzIjpbMTIzLjQ1LCI5ODc2NTQzMjEiXSwic2Vzc2lvbiI6IjU1ZGE0NjM5LTUyMTYtNGE4Mi1iMmNlLTUxYTU3MmZjMzVjNCJ9",
"limit": 24
}
}'
curl -sS -X POST 'https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <shop-storefront-token>' \
-H 'x-shop: shop.myshopify.com' \
-d '{
"strategy": "BESTSELLERS",
"view": "product_details",
"filter": {
"tags": "new,sale,featured",
"excluded_tags": "clearance,discontinued",
"vendors": "UGREEN,Anker",
"product_types": "Cable,Hub",
"collections": "345678901,456789012"
},
"pagination": { "limit": 24 }
}'
curl -sS -X POST 'https://storefront.glood.ai/api/storefront/v3/headless/recommendations/top' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <shop-storefront-token>' \
-H 'x-shop: shop.myshopify.com' \
-d '{
"strategy": "BESTSELLERS",
"view": "product_ids",
"pagination": { "limit": 50 }
}'
curl -sS -X POST 'https://edge.glood.ai/api/edge/storefront/v3/headless/recommendations/top' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <shop-storefront-token>' \
-H 'x-shop: shop.myshopify.com' \
-d '{
"strategy": "BESTSELLERS",
"view": "product_details",
"filter": { "variants": { "is_in_stock": true } },
"facets": ["vendor", "price"],
"pagination": { "limit": 24 }
}'
trending_rank and sales_rank — shop-wide ranks refreshed daily; see the field reference.
{
"status": "ok",
"serve_id": "7c3f5e8a-2b14-49c1-a7d3-93f4e2bb1c8e",
"strategy": "BESTSELLERS",
"products": [
{
"handle": "uno-usb-c-cable-100w",
"product_id": 8123456789012,
"title": "Uno USB-C to USB-C Cable 100W",
"vendor": "UGREEN",
"product_type": "Cable",
"tags": "cable, usb-c, fast-charge",
"price": 9.34,
"compare_at_price": 14.99,
"image": {
"id": "gid://shopify/ImageSource/33459800441029",
"url": "https://cdn.shopify.com/s/files/.../cable.jpg",
"altText": null,
"width": 1600,
"height": 1600
},
"variants": [],
"options": [],
"metafields": [],
"trending_rank": 3,
"sales_rank": 7
}
],
"pagination": {
"cursor": "eyJzIjpbMC44Mzc3LCI4MTIzNDU2Nzg5MDEyIl0sInNlc3Npb24iOiI1NWRhNDYzOS01MjE2LTRhODItYjJjZS01MWE1NzJmYzM1YzQifQ==",
"hasMore": true,
"total": 327,
"totalRelation": "eq",
"limit": 24
},
"facets": {
"vendor": [
{ "value": "UGREEN", "count": 142 },
{ "value": "Anker", "count": 98 }
],
"price": [
{ "min": 0, "max": 50, "count": 210 },
{ "min": 50, "max": 100, "count": 78 },
{ "min": 100, "max": 250, "count": 39 }
]
}
}
{
"errors": [
{
"message": "\"strategy\" is required",
"path": ["strategy"],
"type": "any.required",
"context": { "label": "strategy", "key": "strategy" }
}
]
}
{
"error": "Invalid authentication"
}
{
"error": "Too many requests, please try again later."
}
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
Shopify store URL
"shop.myshopify.com"
Body
Request body
Ranking strategy to apply
BESTSELLERS, NEW_ARRIVALS Response shape for each product entry.
product_details, product_ids Strategy-specific tuning. Currently only BESTSELLERS uses this.
Show child attributes
Show child attributes
Optional free-text query. Applied as a multi_match across title, description, tags, vendor, and product_type. The strategy sort still wins; products matching the text query rank by sales/recency/trending score, not BM25.
Same filter shape as /recommendations/automatic, extended with excluded_tags, collections, product_types, and price.
Show child attributes
Show child attributes
Facet dimensions to return alongside the products. Facets are computed only when this array is non-empty.
vendor, product_type, tag, price Show child attributes
Show child attributes
Optional. Numeric Shopify publication (sales channel) ids. When present, only products published on at least one of these channels are returned and the default "published to the Online Store" gate is replaced by this filter; market and B2B filters still apply. A single id may be sent without the array wrapper. Each id must be one the merchant enabled under Settings → Sales channels; unknown ids return 400. The id is the numeric tail of gid://shopify/Publication/.
50^[0-9]+$["30085840999"]
Response
Top recommendations
ok Unique identifier for this serve.
Echo of the ranking strategy that produced the results.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Present only when the request specified facets. Each requested dimension is a top-level key.
Show child attributes
Show child attributes
Was this page helpful?