Text Search: Submit Feedback
curl --request POST \
--url https://app.uselayers.com/api/storefront/v1/search/feedback \
--header 'Accept: <accept>' \
--header 'Content-Type: <content-type>' \
--header 'X-Storefront-Access-Token: <x-storefront-access-token>' \
--data '
{
"search_id": "<string>",
"rating": "<string>",
"text_feedback": "<string>",
"product_feedback": [
{
"product_id": 123,
"rating": "<string>",
"feedback": "<string>"
}
],
"identity": {
"deviceId": "<string>",
"sessionId": "<string>",
"customerId": "<string>",
"companyLocationId": "<string>"
}
}
'import requests
url = "https://app.uselayers.com/api/storefront/v1/search/feedback"
payload = {
"search_id": "<string>",
"rating": "<string>",
"text_feedback": "<string>",
"product_feedback": [
{
"product_id": 123,
"rating": "<string>",
"feedback": "<string>"
}
],
"identity": {
"deviceId": "<string>",
"sessionId": "<string>",
"customerId": "<string>",
"companyLocationId": "<string>"
}
}
headers = {
"X-Storefront-Access-Token": "<x-storefront-access-token>",
"Content-Type": "<content-type>",
"Accept": "<accept>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Storefront-Access-Token': '<x-storefront-access-token>',
'Content-Type': '<content-type>',
Accept: '<accept>'
},
body: JSON.stringify({
search_id: '<string>',
rating: '<string>',
text_feedback: '<string>',
product_feedback: [{product_id: 123, rating: '<string>', feedback: '<string>'}],
identity: {
deviceId: '<string>',
sessionId: '<string>',
customerId: '<string>',
companyLocationId: '<string>'
}
})
};
fetch('https://app.uselayers.com/api/storefront/v1/search/feedback', 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://app.uselayers.com/api/storefront/v1/search/feedback",
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([
'search_id' => '<string>',
'rating' => '<string>',
'text_feedback' => '<string>',
'product_feedback' => [
[
'product_id' => 123,
'rating' => '<string>',
'feedback' => '<string>'
]
],
'identity' => [
'deviceId' => '<string>',
'sessionId' => '<string>',
'customerId' => '<string>',
'companyLocationId' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Accept: <accept>",
"Content-Type: <content-type>",
"X-Storefront-Access-Token: <x-storefront-access-token>"
],
]);
$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://app.uselayers.com/api/storefront/v1/search/feedback"
payload := strings.NewReader("{\n \"search_id\": \"<string>\",\n \"rating\": \"<string>\",\n \"text_feedback\": \"<string>\",\n \"product_feedback\": [\n {\n \"product_id\": 123,\n \"rating\": \"<string>\",\n \"feedback\": \"<string>\"\n }\n ],\n \"identity\": {\n \"deviceId\": \"<string>\",\n \"sessionId\": \"<string>\",\n \"customerId\": \"<string>\",\n \"companyLocationId\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Storefront-Access-Token", "<x-storefront-access-token>")
req.Header.Add("Content-Type", "<content-type>")
req.Header.Add("Accept", "<accept>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.uselayers.com/api/storefront/v1/search/feedback")
.header("X-Storefront-Access-Token", "<x-storefront-access-token>")
.header("Content-Type", "<content-type>")
.header("Accept", "<accept>")
.body("{\n \"search_id\": \"<string>\",\n \"rating\": \"<string>\",\n \"text_feedback\": \"<string>\",\n \"product_feedback\": [\n {\n \"product_id\": 123,\n \"rating\": \"<string>\",\n \"feedback\": \"<string>\"\n }\n ],\n \"identity\": {\n \"deviceId\": \"<string>\",\n \"sessionId\": \"<string>\",\n \"customerId\": \"<string>\",\n \"companyLocationId\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.uselayers.com/api/storefront/v1/search/feedback")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Storefront-Access-Token"] = '<x-storefront-access-token>'
request["Content-Type"] = '<content-type>'
request["Accept"] = '<accept>'
request.body = "{\n \"search_id\": \"<string>\",\n \"rating\": \"<string>\",\n \"text_feedback\": \"<string>\",\n \"product_feedback\": [\n {\n \"product_id\": 123,\n \"rating\": \"<string>\",\n \"feedback\": \"<string>\"\n }\n ],\n \"identity\": {\n \"deviceId\": \"<string>\",\n \"sessionId\": \"<string>\",\n \"customerId\": \"<string>\",\n \"companyLocationId\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "01HZY7K2M8N9P4Q5R6S7T8U9V0",
"search_id": "01HZY7J9ZV6K2T3M6P4FJ3F2QG",
"recorded": true
}
Text Search
Text Search: Submit Feedback
Search Feedback API endpoint to submit qualitative shopper feedback — thumbs up/down, free-form text, and per-product ratings — for a specific search.
POST
/
search
/
feedback
Text Search: Submit Feedback
curl --request POST \
--url https://app.uselayers.com/api/storefront/v1/search/feedback \
--header 'Accept: <accept>' \
--header 'Content-Type: <content-type>' \
--header 'X-Storefront-Access-Token: <x-storefront-access-token>' \
--data '
{
"search_id": "<string>",
"rating": "<string>",
"text_feedback": "<string>",
"product_feedback": [
{
"product_id": 123,
"rating": "<string>",
"feedback": "<string>"
}
],
"identity": {
"deviceId": "<string>",
"sessionId": "<string>",
"customerId": "<string>",
"companyLocationId": "<string>"
}
}
'import requests
url = "https://app.uselayers.com/api/storefront/v1/search/feedback"
payload = {
"search_id": "<string>",
"rating": "<string>",
"text_feedback": "<string>",
"product_feedback": [
{
"product_id": 123,
"rating": "<string>",
"feedback": "<string>"
}
],
"identity": {
"deviceId": "<string>",
"sessionId": "<string>",
"customerId": "<string>",
"companyLocationId": "<string>"
}
}
headers = {
"X-Storefront-Access-Token": "<x-storefront-access-token>",
"Content-Type": "<content-type>",
"Accept": "<accept>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Storefront-Access-Token': '<x-storefront-access-token>',
'Content-Type': '<content-type>',
Accept: '<accept>'
},
body: JSON.stringify({
search_id: '<string>',
rating: '<string>',
text_feedback: '<string>',
product_feedback: [{product_id: 123, rating: '<string>', feedback: '<string>'}],
identity: {
deviceId: '<string>',
sessionId: '<string>',
customerId: '<string>',
companyLocationId: '<string>'
}
})
};
fetch('https://app.uselayers.com/api/storefront/v1/search/feedback', 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://app.uselayers.com/api/storefront/v1/search/feedback",
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([
'search_id' => '<string>',
'rating' => '<string>',
'text_feedback' => '<string>',
'product_feedback' => [
[
'product_id' => 123,
'rating' => '<string>',
'feedback' => '<string>'
]
],
'identity' => [
'deviceId' => '<string>',
'sessionId' => '<string>',
'customerId' => '<string>',
'companyLocationId' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Accept: <accept>",
"Content-Type: <content-type>",
"X-Storefront-Access-Token: <x-storefront-access-token>"
],
]);
$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://app.uselayers.com/api/storefront/v1/search/feedback"
payload := strings.NewReader("{\n \"search_id\": \"<string>\",\n \"rating\": \"<string>\",\n \"text_feedback\": \"<string>\",\n \"product_feedback\": [\n {\n \"product_id\": 123,\n \"rating\": \"<string>\",\n \"feedback\": \"<string>\"\n }\n ],\n \"identity\": {\n \"deviceId\": \"<string>\",\n \"sessionId\": \"<string>\",\n \"customerId\": \"<string>\",\n \"companyLocationId\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Storefront-Access-Token", "<x-storefront-access-token>")
req.Header.Add("Content-Type", "<content-type>")
req.Header.Add("Accept", "<accept>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.uselayers.com/api/storefront/v1/search/feedback")
.header("X-Storefront-Access-Token", "<x-storefront-access-token>")
.header("Content-Type", "<content-type>")
.header("Accept", "<accept>")
.body("{\n \"search_id\": \"<string>\",\n \"rating\": \"<string>\",\n \"text_feedback\": \"<string>\",\n \"product_feedback\": [\n {\n \"product_id\": 123,\n \"rating\": \"<string>\",\n \"feedback\": \"<string>\"\n }\n ],\n \"identity\": {\n \"deviceId\": \"<string>\",\n \"sessionId\": \"<string>\",\n \"customerId\": \"<string>\",\n \"companyLocationId\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.uselayers.com/api/storefront/v1/search/feedback")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Storefront-Access-Token"] = '<x-storefront-access-token>'
request["Content-Type"] = '<content-type>'
request["Accept"] = '<accept>'
request.body = "{\n \"search_id\": \"<string>\",\n \"rating\": \"<string>\",\n \"text_feedback\": \"<string>\",\n \"product_feedback\": [\n {\n \"product_id\": 123,\n \"rating\": \"<string>\",\n \"feedback\": \"<string>\"\n }\n ],\n \"identity\": {\n \"deviceId\": \"<string>\",\n \"sessionId\": \"<string>\",\n \"customerId\": \"<string>\",\n \"companyLocationId\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "01HZY7K2M8N9P4Q5R6S7T8U9V0",
"search_id": "01HZY7J9ZV6K2T3M6P4FJ3F2QG",
"recorded": true
}
This endpoint allows you to capture user feedback on search results, including overall ratings, text feedback, and product-specific feedback. When feedback is submitted, the endpoint retrieves the cached search data (if still available) and stores the original search query, expanded queries, and intent modifier actions alongside the feedback for analysis.
Authorization
string
required
Token-based authentication header in the form of
<YOUR_LAYERS_TOKEN>. Same requirements as the Search API.Headers
string
default:"application/json"
required
string
default:"application/json"
required
Body
string
required
ULID identifier of the search to provide feedback on. This should be the
search_id returned from the Prepare Search endpoint.string
Overall rating for the search results. Must be one of:
"positive"- Thumbs up, results were helpful"negative"- Thumbs down, results were not helpful
string
Free-form text feedback from the shopper. Maximum 2000 characters.
array
object
User identity information for tracking and personalization. Automatically managed by the Storefront Pixel; required for headless integrations.
Show Properties
Show Properties
string
Persistent browser identifier that remains constant across sessions. Used to recognize returning visitors for long-term personalization. Automatically generated and managed by the Storefront Pixel.
string
Temporary session identifier. Typically corresponds to the Shopify session ID and expires after inactivity or when the browser is closed.
string
Shopify customer ID for authenticated users. Only present when the customer is signed in to their account.
string
Shopify B2B company location GID (e.g.
gid://shopify/CompanyLocation/123456789) for the authenticated buyer. Layers resolves the catalog assigned to the company location and uses it to scope results: only products in the catalog are returned, prices come from the catalog’s price list, and excluded collections return 404. Omit for retail (DTC) traffic.When you pass companyLocationId, you must also pass the buyer’s customerId. Layers verifies with Shopify that the customer belongs to the company that owns the location before resolving the catalog; unauthorized or unauthenticated requests return a 403. See B2B catalogs.Validation rules
search_idis required and must be a valid ULIDratingmust be either"positive"or"negative"if providedtext_feedbackhas a maximum length of 2000 charactersproduct_feedbackis an array where each item must include:product_id(required whenproduct_feedbackis provided)ratingmust be"positive"or"negative"if providedfeedbackhas a maximum length of 500 characters
- At least one of
rating,text_feedback, orproduct_feedbackshould be provided, though all fields are technically optional
Behavior
- Returns HTTP 201 (Created) when feedback is successfully recorded
- Attempts to retrieve cached search data using the provided
search_id - If cached data is available (within 15 minutes of the original search), captures:
- Original search query
- Expanded queries used for search
- Intent modifier actions applied
- If cached data is not available (expired or invalid
search_id), feedback is still recorded but without the search context - Stores identity information (
sessionIdandcustomerId) if provided
Response
201 Created
string
ULID identifier for the created feedback record.
string
The search ID that was provided in the request.
boolean
Always
true when feedback is successfully recorded.{
"id": "01HZY7K2M8N9P4Q5R6S7T8U9V0",
"search_id": "01HZY7J9ZV6K2T3M6P4FJ3F2QG",
"recorded": true
}
Error conditions
- 401 Unauthorized: Missing or invalid
X-Storefront-Access-Token - 402 Payment Required: The store is suspended. Every storefront API request returns this status until the suspension is lifted
- 422 Unprocessable Entity: Invalid body or validation errors
Example usage
Basic rating feedback
const response = await fetch('https://app.uselayers.com/api/storefront/v1/search/feedback', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Storefront-Access-Token': 'your-token-here'
},
body: JSON.stringify({
search_id: '01HZY7J9ZV6K2T3M6P4FJ3F2QG',
rating: 'positive'
})
});
const data = await response.json();
console.log(data);
// { id: "01HZY7K2M8N9P4Q5R6S7T8U9V0", search_id: "01HZY7J9ZV6K2T3M6P4FJ3F2QG", recorded: true }
Feedback with text and identity
const response = await fetch('https://app.uselayers.com/api/storefront/v1/search/feedback', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Storefront-Access-Token': 'your-token-here'
},
body: JSON.stringify({
search_id: '01HZY7J9ZV6K2T3M6P4FJ3F2QG',
rating: 'negative',
text_feedback: 'The results were not relevant to my search.',
identity: {
sessionId: 'session-123',
customerId: 'customer-456'
}
})
});
const data = await response.json();
Product-specific feedback
const response = await fetch('https://app.uselayers.com/api/storefront/v1/search/feedback', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Storefront-Access-Token': 'your-token-here'
},
body: JSON.stringify({
search_id: '01HZY7J9ZV6K2T3M6P4FJ3F2QG',
product_feedback: [
{
product_id: 123,
rating: 'positive'
},
{
product_id: 456,
rating: 'negative',
feedback: 'Not what I was looking for'
}
]
})
});
const data = await response.json();
Next steps
- Use this endpoint in conjunction with the Prepare Search and Search endpoints to create a complete search experience with feedback collection
- Analyze collected feedback to improve search relevance and user experience
Was this page helpful?