Star rating breakdown
Overview
Get how many reviews fall at each star rating for one location.
Use this for a rating distribution chart.
You'll need a token and the location's id (store_id).
Returns counts per star for the window (in_range), plus the all-time total and rating (lifetime). Send both range_start and range_end to limit in_range to those days; with only one of them, or neither, in_range is all-time too.
Suppressed and deleted reviews are excluded from all counts. Off-platform reviews are left out of total_reviews and star_breakdown and counted separately in off_platform_count. Legacy reviews count toward total_reviews but not toward the per-star buckets.
Prerequisites
- A bearer token. See Authentication.
- The location's id (
store_id).
Base URL
| Environment | URL |
|---|---|
| Production | https://production-api.shoutaboutus.com |
| Development | https://development-api.shoutaboutus.com |
Endpoint
GET /api/v1/reviews/stats
Authentication
Partner or Account token
store_idmust be a location your token can see: any location under the partner for a Partner token, the account's locations for an Account token, or the assigned locations for a user limited to some locations.- A location outside that set returns
403(Store is outside your access scope.). - The response is the same shape for every role.
Rate limit
120 requests per minute, counted per user (the token’s user). See Rate limits.
Request parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
store_id | query | integer | Yes | The location to report on. |
range_start | query | string | No | Start of the window, Y-m-d. Used only together with range_end. |
range_end | query | string | No | End of the window, Y-m-d. Must be on or after range_start. |
review_site_id | query | integer | No | Count only this review site's reviews, e.g. 44 for Google. |
Request body
None.
Request payload
None.
Response body
The payload is inside data.
| Field | Type | Description |
|---|---|---|
business_name | string | The location's name. |
range | object | The dates you sent. |
range.start | string or null | range_start as Y-m-d; null when not sent. |
range.end | string or null | range_end as Y-m-d; null when not sent. |
in_range | object | Figures for the window. All-time unless both dates are sent. |
in_range.total_reviews | integer | Reviews that count toward the rating (not off-platform) in the window. |
in_range.average_rating | number or null | Average rating in the window. null when nothing counts toward the rating. |
in_range.off_platform_count | integer | Off-platform reviews in the window, counted separately. |
in_range.star_breakdown | object | Reviews at each star value, keys "1" to "5". Legacy reviews aren't counted here. |
in_range.star_breakdown.1 | integer | 1-star reviews. |
in_range.star_breakdown.2 | integer | 2-star reviews. |
in_range.star_breakdown.3 | integer | 3-star reviews. |
in_range.star_breakdown.4 | integer | 4-star reviews. |
in_range.star_breakdown.5 | integer | 5-star reviews. |
lifetime | object | All-time figures, whatever dates you send. |
lifetime.total_reviews | integer | All-time reviews that count toward the rating (not off-platform). |
lifetime.average_rating | number or null | All-time average rating. null when nothing counts toward the rating. |
Response payload
{
"data": {
"business_name": "Acme Coffee",
"range": {
"start": "2026-01-01",
"end": "2026-09-30"
},
"in_range": {
"total_reviews": 0,
"average_rating": 4.4,
"off_platform_count": 223,
"star_breakdown": {
"1": 0,
"2": 0,
"3": 0,
"4": 0,
"5": 0
}
},
"lifetime": {
"total_reviews": 0,
"average_rating": 4.21
}
}
}Examples
Success payload
Google, January to September 2026: see Response payload. In this example every review is off-platform, so they're counted in off_platform_count rather than the star buckets.
No dates (?store_id=3007), so in_range is all-time:
{
"data": {
"business_name": "Acme Coffee",
"range": {
"start": null,
"end": null
},
"in_range": {
"total_reviews": 0,
"average_rating": 4.21,
"off_platform_count": 682,
"star_breakdown": {
"1": 0,
"2": 0,
"3": 0,
"4": 0,
"5": 0
}
},
"lifetime": {
"total_reviews": 0,
"average_rating": 4.21
}
}
}Error payload
403 Out of scope
{
"message": "Store is outside your access scope.",
"status": "error",
"errors": []
}422 store_id missing
{
"message": "The store id field is required.",
"errors": {
"store_id": [
"The store id field is required."
]
}
}422 Date not in Y-m-d
{
"message": "The range start field must match the format Y-m-d.",
"errors": {
"range_start": [
"The range start field must match the format Y-m-d."
]
}
}422 range_end before range_start
{
"message": "The range end must be greater than or equal to range start.",
"errors": {
"range_end": [
"The range end must be greater than or equal to range start."
]
}
}429 Too many requests
{
"message": "Too Many Attempts."
}| Status | Meaning |
|---|---|
200 | The star breakdown for the location. |
401 | The token is missing, expired or invalid. |
403 | The location isn't one your token can see (or doesn't exist). |
422 | store_id is missing, a date isn't Y-m-d, or range_end is before range_start. |
429 | More than 120 requests in a minute from this user. |
500 | Unexpected server error. |
Example request
curl --request GET \
--url "https://production-api.shoutaboutus.com/api/v1/reviews/stats?store_id=3007&review_site_id=44&range_start=2026-01-01&range_end=2026-09-30" \
--header 'Authorization: Bearer <bearer-token>' \
--header 'Accept: application/json'Updated 17 days ago
