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

Base URL

EnvironmentURL
Productionhttps://production-api.shoutaboutus.com
Developmenthttps://development-api.shoutaboutus.com

Endpoint

GET /api/v1/reviews/stats

Authentication

Partner or Account token

  • store_id must 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

ParameterInTypeRequiredDescription
store_idqueryintegerYesThe location to report on.
range_startquerystringNoStart of the window, Y-m-d. Used only together with range_end.
range_endquerystringNoEnd of the window, Y-m-d. Must be on or after range_start.
review_site_idqueryintegerNoCount only this review site's reviews, e.g. 44 for Google.

Request body

None.

Request payload

None.

Response body

The payload is inside data.

FieldTypeDescription
business_namestringThe location's name.
rangeobjectThe dates you sent.
range.startstring or nullrange_start as Y-m-d; null when not sent.
range.endstring or nullrange_end as Y-m-d; null when not sent.
in_rangeobjectFigures for the window. All-time unless both dates are sent.
in_range.total_reviewsintegerReviews that count toward the rating (not off-platform) in the window.
in_range.average_ratingnumber or nullAverage rating in the window. null when nothing counts toward the rating.
in_range.off_platform_countintegerOff-platform reviews in the window, counted separately.
in_range.star_breakdownobjectReviews at each star value, keys "1" to "5". Legacy reviews aren't counted here.
in_range.star_breakdown.1integer1-star reviews.
in_range.star_breakdown.2integer2-star reviews.
in_range.star_breakdown.3integer3-star reviews.
in_range.star_breakdown.4integer4-star reviews.
in_range.star_breakdown.5integer5-star reviews.
lifetimeobjectAll-time figures, whatever dates you send.
lifetime.total_reviewsintegerAll-time reviews that count toward the rating (not off-platform).
lifetime.average_ratingnumber or nullAll-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."
}
StatusMeaning
200The star breakdown for the location.
401The token is missing, expired or invalid.
403The location isn't one your token can see (or doesn't exist).
422store_id is missing, a date isn't Y-m-d, or range_end is before range_start.
429More than 120 requests in a minute from this user.
500Unexpected 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'

Did this page help you?