Get reviews for a location

Overview

Get reviews as a paginated list, newest first, each with its response (if any), the location and site it came from, its flag status, and whether you can respond to it. Also returns the average rating and a per-site summary for the reviews in scope.

This is the first call most integrations make. Use it to build a review feed, sync reviews into your own system, or find reviews that still need a response.

Optional filters: store_id or client_location_id for one location; account_id or client_account_id for one account; leave both out for everything under your partner. Also review_site_id, rating (one or several), response status (complete, pending, flagged, and so on, or awaiting_response for reviews with no reply yet), a date range, and a keyword search over reviewer name, review text, and location name. Page size defaults to 10.

Partner tokens use POST /partner/report/review-response/feed and default to everything under the partner. Account tokens use POST /reports/response/feed and default to the account's locations. Same call, different default scope.

To keep your own copy in sync, send updated_since with the time of your last sync, and include_removed: true to also get the reviews removed since then. Each review carries external_review_id, created_at, updated_at and deleted_at. See Keeping your copy in sync.

Returns one entry per review with pagination. Each entry includes response_capabilities telling you whether a manual or AI response is possible right now and, if not, why.

Prerequisites

  • A bearer token. See Authentication.
  • Optional: a location (store_id or client_location_id) or an account (account_id or client_account_id) to narrow the feed.

Base URL

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

Endpoint

POST /api/v1/partner/report/review-response/feed

Authentication

Partner token

  • Without a location or account, the feed covers every location under the partner.
  • store_id, client_location_id, account_id and client_account_id must be inside your own account tree; otherwise 422.
  • Account tokens use POST /api/v1/reports/response/feed, with the same request and response, scoped to the account's own locations.

Rate limit

300 requests per minute, counted per user (the token’s user). See Rate limits.

Request parameters

None.

Request body

FieldTypeRequiredDescription
range_startstringNoStart of the review-date window, Y-m-d H:i:s. Use with range_end.
range_endstringNoEnd of the window, Y-m-d H:i:s. When both dates are sent and limit is left out, every matching review is returned in one response, without paging.
limitintegerNoPage size, 10–100. Default 10. Values below 10 are raised to 10; above 100 returns 422. Eligible partners default to 25, and a larger value is lowered to 25 without an error.
pageintegerNoThe page to return, from 1.
sort_fieldstringNoSort by review_date, rating, rate (same as rating), reviewer, created_at, updated_at, response_date or store_name. Applied only with sort_by. Default order: review_date, newest first.
sort_bystringNoasc or desc.
typestringNoreport or download.
store_idintegerNoOnly this location. Must exist and be inside your account tree.
client_location_idstringNoYour own id for the location, instead of store_id. Up to 255 characters.
account_idintegerNoOnly this account's locations. Must be an active account inside your account tree.
client_account_idstringNoYour own id for the account, instead of account_id. Up to 255 characters.
is_pdfintegerNo0 or 1. 1: logo URLs point at the API host instead of the CDN.
review_site_idintegerNoOnly reviews from this review site.
ratingarray of integersNoOnly these star ratings, e.g. [4, 5]. A single number is accepted too.
statusstringNoOnly reviews whose response is complete, pending, error, flagged or removed; or awaiting_response: reviews with no response yet that the location may respond to under its plan (the same set as the dashboard's Awaiting Response count).
searchstringNoMatches part of the reviewer or customer name, the review text or title, the job id, or the location name. Up to 255 characters.
created_sincestringNoOnly reviews we collected at or after this time, UTC, Y-m-d H:i:s. Compares against created_at.
updated_sincestringNoOnly reviews that changed at or after this time, UTC, Y-m-d H:i:s. Compares against updated_at; with include_removed, also matches reviews removed at or after it. Send the time of your last sync to get only what changed. A change is a new review, an edit to its rating, text, reviewer name or date, a moderation change (for example hidden or suppressed), a removal or a restore. A new or changed reply, or a change to a removal request (flag), doesn't count: those arrive as response_* and flag_* webhooks.
include_removedbooleanNotrue to also return reviews removed on our side, with deleted_at set. Off by default. Not the same as status=removed, which filters on the review site reporting the review gone.
📘

Keeping your copy in sync. Send the time your last sync started as updated_since, with include_removed: true, and sort by updated_at oldest first so new changes can't shift the pages you haven't read yet:

{ "store_id": 3007, "updated_since": "2026-10-08 09:55:00", "include_removed": true, "sort_field": "updated_at", "sort_by": "asc", "limit": 100, "page": 1 }

Page through to meta.last_page. Update each review by its id, and delete the ones with deleted_at set. Start each sync a few minutes before the last one started, so a difference between your clock and ours can't skip a change; reviews you already have just come back again. Don't send range_start or range_end with it: those filter on the review's own date, not on when it changed. Replies and removal-request (flag) changes don't change updated_at, so take those from webhooks.

Request payload

{
  "range_start": "2026-01-01 00:00:00",
  "range_end": "2026-12-31 23:59:59",
  "account_id": 5994,
  "review_site_id": 44,
  "rating": [
    4,
    5
  ],
  "status": "awaiting_response",
  "search": "clean",
  "limit": 10,
  "page": 1,
  "sort_field": "review_date",
  "sort_by": "desc"
}

Response body

The reviews are in a top-level data array, next to links, meta, avg_rating and kpi_by_publisher. links and meta are left out when the result isn't paged (both dates sent, no limit).

📘

How ratings work. rating is always a whole number from 0 to 5. 0 means the review has no star rating.

  • Sites that rate out of 5 come through as they are. A decimal rating, such as 4.5, is rounded to the nearest whole star.
  • Sites that rate out of 10 (Booking.com, Agoda, Expedia, Hotels.com, Orbitz, Travelocity, Trip.com, HolidayCheck and HomeStars) are halved to a 0–5 score, then rounded to the nearest whole star. The lowest they come through as is 1. For example, 8.6/10 becomes 4.3, which comes through as 4.
  • Facebook recommendations without stars count as 5 (recommends) or 1 (doesn't recommend).
  • The site's original score and scale aren't included.
On the site (out of 10)rating
1 or 21
3 or 42
5 or 63
7 or 84
9 or 105

Because of rounding, nearby scores can share a rating: 8.0 and 8.6 both come through as 4.

FieldTypeDescription
dataarray of objectsOne entry per review, newest first by default.
data[].idintegerThe review's id (review_id).
data[].external_review_idstring or nullThe review site's own id for this review, as we collected it, or null.
data[].review_urlstring or nullA link to this review on the review site, or null. Given when the site provides a link to the individual review; for sites that don't (for example Facebook, or Google connected through Google sign-in) it's null. The location's page on the site is store_reviewsite.url.
data[].created_atstring or nullWhen we collected the review (ISO 8601, UTC).
data[].updated_atstring or nullWhen the review last changed on our side (ISO 8601, UTC): collected, edited, moderated, removed or restored. A new or changed reply, or a flag change, doesn't update it.
data[].deleted_atstring or nullWhen the review was removed (ISO 8601, UTC). Always null unless include_removed is sent.
data[].source_platformstringThe site the review came from, e.g. google.
data[].reviewobjectThe review.
data[].review.idintegerThe review's id.
data[].review.reviewerstringThe reviewer's name as shown on the site.
data[].review.ratingnumberThe star rating, a whole number from 0 to 5. 0 when the review has no rating. Sites that rate out of 10 are converted; see How ratings work under Response body.
data[].review.messagestringThe review text. "" when the review is a rating only.
data[].review.review_datestring or nullWhen the review was posted (ISO 8601), or null if unknown.
data[].reviewsiteobjectThe review site.
data[].reviewsite.idintegerThe review site's id (review_site_id).
data[].reviewsite.namestringThe review site's name, e.g. Google.
data[].reviewsite.linkstringThe site's home page.
data[].reviewsite.review_site_logostringURL of the site's logo.
data[].reviewsite.review_site_colorstringThe site's brand colour, e.g. #4285F4.
data[].reviewsite.auth_typestring or nullHow the site connects: oauth, cookie, credential, default, restapi, or null. See List supported review sites.
data[].reviewsite.scraping_enabledbooleanWhether reviews can be collected from this site.
data[].reviewsite.posting_enabledbooleanWhether responses can be posted to this site.
data[].storeobjectThe location.
data[].store.idintegerThe location's id (store_id).
data[].store.namestringThe location's name, followed by - and your client_location_id (or its storeId label) when it has one.
data[].store.slugstringThe location's URL slug.
data[].store.addressstringThe location's address: street, city and state.
data[].store_reviewsiteobjectThe connection between the location and the site.
data[].store_reviewsite.idinteger or nullThe connection's id (store_review_site_id).
data[].store_reviewsite.urlstring or nullThe site's review URL for the location.
data[].store_reviewsite.landing_page_urlstring or nullThe landing page URL used in review requests.
data[].store_reviewsite.connection_statusstring or nullThe stored connection state, e.g. connected or Disconnected, or null.
data[].store_reviewsite.is_connectedbooleanWhether the site is connected for this location.
data[].flagarray of objectsStatus chips for the response and any removal flag, in display order. Empty when there is nothing to show.
data[].flag[].flagstringThe chip label, e.g. complete or Flagged — Pending Review.
data[].flag[].titlestringWhat the chip means, in plain language.
data[].flag[].statusColorstringsuccess, warning or error.
data[].flag[].iconstringIcon name for the chip.
data[].flag[].linksarray of objectsOnly on some chips: where to fix the problem.
data[].flag[].links[].namestringLink label, e.g. Edit Review Site.
data[].flag[].links[].urlstringLink URL in the Shout About Us web app.
data[].planstringThe plan name recorded with the latest update to the response, or "".
data[].review_flagobject or nullThe removal flag on this review, or null.
data[].review_flag.review_idintegerThe review's id.
data[].review_flag.reasonstringWhy the review was flagged.
data[].review_flag.flag_statusstringpending, submitted_to_platform, approved_removed or denied.
data[].review_flag.flag_datestringWhen it was flagged (ISO 8601).
data[].review_flag.flag_reason_detailstring or nullThe extra detail given when flagging, or null.
data[].review_flag.reason_identifierstring or nullThe flag reason category, e.g. Low quality information.
data[].is_flaggablebooleanWhether you can flag this review for removal now.
data[].flag_statusstringnone when not flagged, otherwise pending, submitted_to_platform, approved_removed or denied.
data[].flag_detailsobject or nullThe flag, or null when not flagged.
data[].flag_details.reasonstringWhy the review was flagged.
data[].flag_details.reason_identifierstring or nullThe flag reason category.
data[].flag_details.flag_reason_detailstring or nullThe extra detail given when flagging.
data[].flag_details.flag_datestring or nullWhen it was flagged (ISO 8601).
data[].response_capabilitiesobjectWhether a response can be sent now.
data[].response_capabilities.manualbooleanWhether you can write and send a response.
data[].response_capabilities.aibooleanWhether you can send an AI-drafted response.
data[].response_capabilities.reasonstring or nullWhy not, when either is false, e.g. no_store_plan, dormant_tier, pre_response_cutoff, past_response_window_expired, past_response_quota_reached or past_response_unavailable. Otherwise null.
data[].responseobject or nullThe response to the review, or null when there is none.
data[].response.idintegerThe response's id.
data[].response.statusstringWhere the response is: e.g. complete (posted), pending (in the posting queue), or why it wasn't posted, e.g. login_error. The flag chip explains it.
data[].response.public_contentsstring or nullThe response text posted on the site.
data[].response.private_contentsstring or nullThe private part of the response, or null.
data[].response.response_datestring or nullWhen the response was made, or null.
data[].response.deletedobject or nullSet when the response was removed from the site, otherwise null.
data[].response.deleted.delete_onstringWhen it was removed.
data[].response.deleted.statusstringThe removal status.
linksobjectPaging links.
links.firststringURL of the first page.
links.laststringURL of the last page.
links.prevstring or nullURL of the previous page, or null.
links.nextstring or nullURL of the next page, or null.
metaobjectPaging details.
meta.current_pageintegerThis page.
meta.frominteger or nullPosition of the first review on this page.
meta.last_pageintegerThe last page.
meta.linksarray of objectsPage links for a pager.
meta.links[].urlstring or nullThe page's URL.
meta.links[].labelstringThe link label.
meta.links[].pageinteger or nullThe page number.
meta.links[].activebooleantrue for this page.
meta.pathstringThe endpoint's URL.
meta.per_pageintegerReviews per page.
meta.tointeger or nullPosition of the last review on this page.
meta.totalintegerReviews across all pages.
avg_ratingnumberAverage rating of all the reviews in scope, over all time (not narrowed by the date range or the other filters), to 2 decimal places. Refreshed every 10 minutes.
kpi_by_publisherarray of objectsOne entry per review site with reviews in scope, narrowed by the date range and rating. Empty when there are no locations in scope.
kpi_by_publisher[].review_site_idintegerThe review site's id.
kpi_by_publisher[].review_site_namestringThe review site's name.
kpi_by_publisher[].review_site_colorstring or nullThe site's brand colour.
kpi_by_publisher[].ratingnumber or nullAverage rating on the site, to 1 decimal place, or null.
kpi_by_publisher[].total_reviewsintegerNumber of reviews on the site.
kpi_by_publisher[].was_bridgedbooleantrue when rating is a blended rating rather than a simple average of the reviews.

Response payload

{
  "data": [
    {
      "id": 265997,
      "external_review_id": "ChdDSUhNMG9nS0VJQ0FnSUM0bnRlM21BRRAB",
      "review_url": null,
      "created_at": "2026-09-23T10:31:02+00:00",
      "updated_at": "2026-09-23T10:31:02+00:00",
      "deleted_at": null,
      "source_platform": "google",
      "review": {
        "id": 265997,
        "reviewer": "Jane Smith",
        "rating": 4,
        "message": "Busy, but clean.",
        "review_date": "2026-09-23T10:09:39.000000Z"
      },
      "reviewsite": {
        "id": 44,
        "name": "Google",
        "link": "http://maps.google.com",
        "review_site_logo": "https://d2ny6zb7otrnhl.cloudfront.net/static/images/img-google.png",
        "review_site_color": "#4285F4",
        "auth_type": "oauth",
        "scraping_enabled": true,
        "posting_enabled": true
      },
      "store": {
        "id": 3007,
        "name": "Acme Coffee - docs-test-loc-001",
        "slug": "acme-coffee",
        "address": "1 George St, Sydney, NSW"
      },
      "store_reviewsite": {
        "id": 8784,
        "url": "https://www.google.com/maps/place/Wynyard/@-33.8648805,151.2065622,1523m/data=!3m1!1e3!4m6!3m5!1s0x6b12ae40e6fcf9eb:0x45845f7ff56e0d1!8m2!3d-33.86594!4d151.2061!16s%2Fg%2F1262gn7v0?entry=ttu&g_ep=EgoyMDI2MDkyMC4wIKXMDSoASAFQAw%3D%3D",
        "landing_page_url": "https://www.google.com/maps/place/Wynyard/@-33.8648805,151.2065622,1523m/data=!3m1!1e3!4m6!3m5!1s0x6b12ae40e6fcf9eb:0x45845f7ff56e0d1!8m2!3d-33.86594!4d151.2061!16s%2Fg%2F1262gn7v0?entry=ttu&g_ep=EgoyMDI2MDkyMC4wIKXMDSoASAFQAw%3D%3D",
        "connection_status": "Disconnected",
        "is_connected": false
      },
      "flag": [],
      "plan": "",
      "review_flag": null,
      "is_flaggable": true,
      "flag_status": "none",
      "flag_details": null,
      "response_capabilities": {
        "manual": true,
        "ai": true,
        "reason": null
      },
      "response": null
    },
    {
      "id": 279309,
      "external_review_id": "ChZDSUhNMG9nS0VJQ0FnSURyeWZqd0dREAE",
      "review_url": null,
      "created_at": "2026-09-27T01:02:44+00:00",
      "updated_at": "2026-09-28T14:48:21+00:00",
      "deleted_at": null,
      "source_platform": "google",
      "review": {
        "id": 279309,
        "reviewer": "John Smith",
        "rating": 4,
        "message": "",
        "review_date": "2026-09-27T00:22:21.000000Z"
      },
      "reviewsite": {
        "id": 44,
        "name": "Google",
        "link": "http://maps.google.com",
        "review_site_logo": "https://d2ny6zb7otrnhl.cloudfront.net/static/images/img-google.png",
        "review_site_color": "#4285F4",
        "auth_type": "oauth",
        "scraping_enabled": true,
        "posting_enabled": true
      },
      "store": {
        "id": 3007,
        "name": "Acme Coffee - docs-test-loc-001",
        "slug": "acme-coffee",
        "address": "1 George St, Sydney, NSW"
      },
      "store_reviewsite": {
        "id": 8784,
        "url": "https://www.google.com/maps/place/Wynyard/@-33.8648805,151.2065622,1523m/data=!3m1!1e3!4m6!3m5!1s0x6b12ae40e6fcf9eb:0x45845f7ff56e0d1!8m2!3d-33.86594!4d151.2061!16s%2Fg%2F1262gn7v0?entry=ttu&g_ep=EgoyMDI2MDkyMC4wIKXMDSoASAFQAw%3D%3D",
        "landing_page_url": "https://www.google.com/maps/place/Wynyard/@-33.8648805,151.2065622,1523m/data=!3m1!1e3!4m6!3m5!1s0x6b12ae40e6fcf9eb:0x45845f7ff56e0d1!8m2!3d-33.86594!4d151.2061!16s%2Fg%2F1262gn7v0?entry=ttu&g_ep=EgoyMDI2MDkyMC4wIKXMDSoASAFQAw%3D%3D",
        "connection_status": "Disconnected",
        "is_connected": false
      },
      "flag": [
        {
          "flag": "Flagged — Pending Review",
          "title": "This review is in the queue to be flagged for removal from the review site. (Review is off-topic, contains ads, or is gibberish or repetitive)",
          "statusColor": "warning",
          "icon": "fa-regular:flag"
        }
      ],
      "plan": "",
      "review_flag": {
        "review_id": 279309,
        "reason": "Review is off-topic, contains ads, or is gibberish or repetitive",
        "flag_status": "pending",
        "flag_date": "2026-09-28T14:48:21.000000Z",
        "flag_reason_detail": "Duplicate of an earlier review.",
        "reason_identifier": "Low quality information"
      },
      "is_flaggable": true,
      "flag_status": "pending",
      "flag_details": {
        "reason": "Review is off-topic, contains ads, or is gibberish or repetitive",
        "reason_identifier": "Low quality information",
        "flag_reason_detail": "Duplicate of an earlier review.",
        "flag_date": "2026-09-28T14:48:21+00:00"
      },
      "response_capabilities": {
        "manual": true,
        "ai": true,
        "reason": null
      },
      "response": null
    }
  ],
  "links": {
    "first": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/feed?page=1",
    "last": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/feed?page=69",
    "prev": null,
    "next": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/feed?page=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 69,
    "links": [
      {
        "url": null,
        "label": "« Previous",
        "page": null,
        "active": false
      },
      {
        "url": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/feed?page=1",
        "label": "1",
        "page": 1,
        "active": true
      },
      {
        "url": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/feed?page=2",
        "label": "2",
        "page": 2,
        "active": false
      },
      {
        "url": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/feed?page=2",
        "label": "Next »",
        "page": 2,
        "active": false
      }
    ],
    "path": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/feed",
    "per_page": 10,
    "to": 10,
    "total": 682
  },
  "avg_rating": 4.21,
  "kpi_by_publisher": [
    {
      "review_site_id": 44,
      "review_site_name": "Google",
      "review_site_color": "#4285F4",
      "rating": 4.2,
      "total_reviews": 682,
      "was_bridged": false
    }
  ]
}

Examples

Success payload

See Response payload.

Error payload

422 Invalid values

{
  "message": "The range start field must match the format Y-m-d H:i:s. (and 3 more errors)",
  "errors": {
    "range_start": [
      "The range start field must match the format Y-m-d H:i:s."
    ],
    "sort_field": [
      "The selected sort field is invalid."
    ],
    "status": [
      "The selected status is invalid."
    ],
    "rating.0": [
      "The rating.0 field must be an integer."
    ]
  }
}

422 Location outside your tree

{
  "message": "The selected store id does not belong to your company hierarchy.",
  "errors": {
    "store_id": [
      "The selected store id does not belong to your company hierarchy."
    ]
  }
}

422 Account doesn't exist or is outside your tree

{
  "message": "The selected account id is invalid. (and 1 more error)",
  "errors": {
    "account_id": [
      "The selected account id is invalid.",
      "The selected account id does not belong to your company hierarchy."
    ]
  }
}

422 limit over 100

{
  "message": "The limit field must not be greater than 100.",
  "errors": {
    "limit": [
      "The limit field must not be greater than 100."
    ]
  }
}

429 Too many requests

{
  "message": "Too Many Attempts."
}
StatusMeaning
200A page of reviews, with the average rating and per-site summary.
401The token is missing, expired or invalid.
422A value is invalid, a location or account is outside your tree, or limit is over 100.
429More than 300 requests in a minute from this user.
500Unexpected server error.

Example request

curl --request POST \
  --url "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/feed" \
  --header 'Authorization: Bearer <bearer-token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{"range_start": "2026-01-01 00:00:00", "range_end": "2026-12-31 23:59:59", "account_id": 5994, "review_site_id": 44, "rating": [4, 5], "status": "awaiting_response", "search": "clean", "limit": 10, "page": 1, "sort_field": "review_date", "sort_by": "desc"}'

Did this page help you?