Get the average star rating score, sentiment, sentiment change, and reviews sentiment distribution for specific product collections in your store.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
Get rating and sentiment metrics for product collections in your store to compare review feedback across collections.
| Property | Value |
|---|---|
| Method | POST |
| Path | /insights/v1/topics/products |
| Full URL | https://api.yotpo.com/insights/v1/topics/products |
| API version | v1 |
| Request and success response format | application/json |
| Authentication | Authorization: Bearer YOUR_ACCESS_TOKEN |
| Path and query parameters | None defined; send inputs in the JSON body |
Authentication and request formatAuthenticate with
Authorization: Bearer YOUR_ACCESS_TOKEN. The Insights API does not accept theX-Yotpo-Tokenheader.Send filters inside the
filterobject, pagination insidepagingand sorting insidesorting. Fields sent at the top level of the body are ignored.
Send a request
| Prerequisite | Action |
|---|---|
| Access token | Generate a token using Yotpo Authentication. |
| Store ID | Find your app key (the identifier for your store). |
| Collection and topic | Choose a collection name from your Yotpo product catalog and a topic to analyze, such as quality. |
- Set
Authorization: Bearer YOUR_ACCESS_TOKENandContent-Type: application/json. - Add your store ID to
filter.app_keyand topic names tofilter.topics. - Add collection names to
filter.product_collectionsto scope the analysis to those collections. - Send the request to
https://api.yotpo.com/insights/v1/topics/products.
The following example uses the collection, topic, and date range supplied in the endpoint specification. Replace the token, store ID, and collection name with your own values.
curl --request POST \
--url 'https://api.yotpo.com/insights/v1/topics/products' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"filter": {
"app_key": "YOUR_STORE_ID",
"topics": ["quality"],
"product_collections": ["Cool Watches"],
"date_range": {
"start_date": "2018-01-11T00:00:00.000Z",
"end_date": "2018-11-12T00:00:00.000Z"
},
"minimum_score": 4,
"exclude_unpublished": false
},
"paging": {
"page": 0,
"per_page": 10
},
"sorting": {
"sorting_field": "yotpo_default_sorting"
}
}' \
--include \
--fail-with-bodyExpect HTTP 200 with the JSON structure shown under Response example. With --fail-with-body, curl returns a nonzero exit status for HTTP errors while retaining the response body. Check the status before processing the body; a 401 body is plain text, not JSON.
Request body
| Field | Type | Required | Description and default |
|---|---|---|---|
filter | object | Yes | Contains the store ID, topics, and review filters. |
paging | object | No | Controls pagination. If omitted, the API returns up to 25 results. |
sorting | object | No | Controls result ordering. The default ordering is not specified. |
Only filter is required at the top level. Within it, app_key and topics are required. Other fields are optional. Unless stated below, the specification does not define a default, length limit, or array-size limit.
Required filter fields
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
filter.app_key | string | Yes | Your store ID (app key). | "YOUR_STORE_ID" |
filter.topics | array of strings | Yes | Topic names to include. | ["quality"] |
The specification requires topics but does not define whether an empty array is accepted. Supply the topic names you want to analyze.
Optional: Filter reviews
| Field | Type | Required | Description and constraints | Example |
|---|---|---|---|---|
filter.date_range | object | No | Date range for the reviews to analyze. | See child fields below. |
filter.date_range.start_date | string | No | Range start in ISO 8601 date-time format. | "2018-01-11T00:00:00.000Z" |
filter.date_range.end_date | string | No | Range end in ISO 8601 date-time format. | "2018-11-12T00:00:00.000Z" |
filter.location | object | No | Filters by reviewer location. | See child fields below. |
filter.location.countries | array of strings | No | Two-letter reviewer country codes. See the country code list. | ["US"] |
filter.location.states | array of strings | No | Reviewer state codes. See the state code list. | ["CA"] |
filter.external_product_ids | array of strings | No | Product IDs (domain keys or SKUs) to include. | ["2063374417974"] |
filter.product_groups | array of strings | No | Product group names as defined in your Yotpo product catalog. | Use your catalog's group names. |
filter.product_collections | array of strings | No | Product collection names as defined in your Yotpo product catalog. | ["Cool Watches"] |
filter.minimum_score | integer | No | Minimum star rating, from 1 through 5. | 4 |
filter.exclude_unpublished | boolean | No | Set to true to exclude unpublished reviews. No default is specified. | false |
Optional: Paginate and sort
| Field | Type | Required | Description and constraints | Example |
|---|---|---|---|---|
paging.page | integer | No | Zero-based page number; minimum 0. No default is specified. | 0 |
paging.per_page | integer | No | Results per page; minimum 1. No maximum or per-field default is specified. Omitting the entire paging object returns up to 25 results. | 10 |
sorting.sorting_field | string | No | One of yotpo_default_sorting, sentiment_score, average_star_rating, positive_reviews, or negative_reviews. yotpo_default_sorting combines sentiment score and number of opinions. | "yotpo_default_sorting" |
sorting.sorting_direction | string | No | Case-sensitive: ASC or DESC. Does not apply to yotpo_default_sorting. | "ASC" |
Responses
| Status | Meaning | Action |
|---|---|---|
200 | Successful request. Returns collection metrics and pagination metadata. | Read product_collections and use paging to determine whether to request another page. |
400 | Bad request. The documented example is {}; no error fields are defined. | Check required fields, nesting, types, rating bounds, and sorting values before retrying. |
401 | Missing or invalid bearer token. The body is the plain string unauthorized. | Check the Authorization header and generate a valid token if necessary. Do not use X-Yotpo-Token. |
These are the status codes defined in the endpoint specification. It does not define additional error codes or error-body formats.
Response fields
| Field | Type | Description |
|---|---|---|
product_collections | array of objects | Collection metrics returned by the request. Handle an empty array without assuming a first result exists. |
product_collections[].product_collections | string | Collection name. |
product_collections[].average_star_rating | number | Average star rating for the collection. |
product_collections[].sentiment_score | number | Collection sentiment score. The specification does not define its scale or calculation. |
product_collections[].sentiment_change | object | Sentiment change value and associated error string. |
product_collections[].sentiment_change.value | number | Sentiment change value. The comparison period and calculation are not defined in the specification. |
product_collections[].sentiment_change.error | string | Error information associated with sentiment change; empty in the success example. |
product_collections[].positive_reviews | integer | Count of positive reviews. |
product_collections[].negative_reviews | integer | Count of negative reviews. |
product_collections[].neutral_reviews | integer | Count of neutral reviews. |
product_collections[].reviews_count | integer | Review count returned for the collection. |
product_collections[].products_in_collection | array of objects | Products in the collection. |
product_collections[].products_in_collection[].product_id | string | Product identifier. |
product_collections[].products_count | integer | Number of products in the collection. |
paging | object | Pagination metadata. |
paging.page | integer | Current page number, starting at 0. |
paging.page_count | integer | Total number of pages. |
paging.per_page | integer | Results per page. |
paging.total | integer | Total number of results. |
The response schema does not mark fields as required. Check that a field is present before reading it, and treat a nonempty sentiment_change.error as information to inspect rather than assuming the change value is usable.
Response example
| Property | Value |
|---|---|
| Status | 200 |
| Content type | application/json |
| Example scope | One result per page, as supplied in the specification; this is separate from the request example's per_page: 10. |
{
"product_collections": [
{
"product_collections": "Cool Watches",
"average_star_rating": 4.882443928847641,
"sentiment_score": 85.60082,
"sentiment_change": {
"value": 0.29634076789936614,
"error": ""
},
"positive_reviews": 3418,
"negative_reviews": 77,
"neutral_reviews": 406,
"reviews_count": 3903,
"products_in_collection": [
{ "product_id": "1850285" },
{ "product_id": "10228864" },
{ "product_id": "24857299" },
{ "product_id": "24857295" },
{ "product_id": "35392356" },
{ "product_id": "35787751" }
],
"products_count": 6
}
],
"paging": {
"page": 0,
"page_count": 6,
"per_page": 1,
"total": 6
}
}Error examples
| Status | Body format | Defined error fields |
|---|---|---|
400 | JSON object | None |
401 | Plain text | Not applicable |
HTTP 400:
{}HTTP 401:
unauthorizedRate limits and troubleshooting
| Response header | Type | Meaning |
|---|---|---|
ratelimit-limit | integer | Maximum requests allowed in the current time window. |
ratelimit-remaining | integer | Requests remaining in the current time window. |
ratelimit-reset | integer | Seconds until the rate limit resets. |
x-ratelimit-limit-minute | integer | Maximum requests allowed per minute. |
x-ratelimit-remaining-minute | integer | Requests remaining in the current minute. |
The specification defines these headers for 200 and 400 responses, but does not specify fixed quota values or a rate-limit error response. Monitor the returned values instead of hard-coding a quota. When ratelimit-remaining reaches 0, pause requests for the number of seconds in ratelimit-reset; also pace requests to avoid exhausting the per-minute allowance.
- Filters appear to have no effect: Move filter fields under
filter. Keep pagination underpagingand sorting undersorting; flat fields are ignored. - The API returns
400: Includefilter.app_keyandfilter.topics. Check ISO 8601 dates,minimum_scorefrom1to5,paging.pageof at least0, andpaging.per_pageof at least1. - The API returns
401: Send the token inAuthorization: Bearer YOUR_ACCESS_TOKEN. Follow Yotpo Authentication to obtain a valid token. - Sort direction has no effect:
sorting_directiondoes not apply toyotpo_default_sorting. For other sorting fields, use uppercaseASCorDESC. - No collections are returned: Handle the empty result without indexing into it, then check your catalog collection names and review filters.
401Missing or invalid bearer token. The body is the plain string unauthorized.
