Performance by location
Overview
Get a row per location with its reviews, responses, rating, and response rate for the period.
Use this for a leaderboard or to find locations that need attention.
You'll need a partner token and a date range; sortable.
Returns one row per location, a page at a time.
Prerequisites
- A Partner bearer token. See Authentication.
- A date range:
range_startandrange_end, bothY-m-d H:i:s. - Optional: a
store_idoraccount_id(or your ownclient_location_id/client_account_id) to narrow the report. Leave them out to cover every location under your partner.
Base URL
| Environment | URL |
|---|---|
| Production | https://production-api.shoutaboutus.com |
| Development | https://development-api.shoutaboutus.com |
Endpoint
POST /api/v1/partner/report/review-response/by-location
Authentication
Partner token
- Only Partner tokens can call it.
- Which locations are covered:
store_id(one location) if sent, otherwiseaccount_id(that account's locations), otherwise every location under your partner.client_location_idandclient_account_idare used whenstore_idandaccount_idaren't sent. - When the user behind the token is limited to some locations, only those are covered.
- Every id you send must be inside your own tree: a location or account under your partner. Anything else is rejected with
422.
Rate limit
120 requests per minute, counted per user (the token’s user). See Rate limits.
Request parameters
None.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
range_start | string | Yes | Start of the date range, as Y-m-d H:i:s. |
range_end | string | Yes | End of the date range, as Y-m-d H:i:s. |
store_id | integer | No | One location to report on. Must exist and be inside your tree. |
account_id | integer | No | One account under your partner (an account id, not a location). Must exist and be inside your tree. |
client_location_id | string | No | Your own id for a location. Used in place of store_id when store_id isn't sent. Max 255 characters; must be inside your tree. |
client_account_id | string | No | Your own id for an account. Used in place of account_id when account_id isn't sent. Max 255 characters; must be inside your tree. |
sort_field | string | No | Column to sort by. Default location_name. |
sort_by | string | No | Sort direction. Default ASC. |
search_field | string | No | Field to search. Only location_name. |
search_value | string | No | Text to look for in the location's name, storeid or client_location_id. Used only with search_field. |
limit | integer | No | Rows per page, 10 to 100. Values below 10 are raised to 10; above 100 returns 422. Default 10. |
page | integer | No | Page number. Default 1. |
Request payload
{
"range_start": "2026-01-01 00:00:00",
"range_end": "2026-09-30 23:59:59",
"account_id": 5994,
"sort_field": "total_reviews",
"sort_by": "desc",
"limit": 10,
"page": 1
}Response body
data is an array with one row per location that has reviews in the range. links and meta carry the pagination.
| Field | Type | Description |
|---|---|---|
data | array of objects | One row per location that has reviews in the range. |
data[].id | integer | The location's id (store_id). |
data[].location_name | string | The location's name, followed by - and its client_location_id (or its storeid when there's no client_location_id). |
data[].total_reviews | integer | Reviews dated within the range. |
data[].total_responses | integer | Responses submitted to the location's reviews in the range. |
data[].avg_resp_time | number | Average time to respond, in days, to 2 decimals. 0 when there are no responses. |
data[].avg_rating | number | Average star rating of the reviews in the range, to 2 decimals. |
data[].response_rate | number | Percentage of the location's reviews in the range that have a response (failed responses aren't counted), to 2 decimals. |
links | object | Links to the other pages. |
links.first | string | URL of the first page. |
links.last | string | URL of the last page. |
links.prev | string or null | URL of the previous page, or null on the first page. |
links.next | string or null | URL of the next page, or null on the last page. |
meta | object | Pagination details. |
meta.current_page | integer | The current page. |
meta.from | integer or null | Position of the first row on this page, or null when the page is empty. |
meta.last_page | integer | The last page number. |
meta.links | array of objects | Page links, for building a pager. |
meta.links[].url | string or null | URL of that page, or null. |
meta.links[].label | string | Label for the link: a page number, « Previous or Next ». |
meta.links[].page | integer or null | The page number, or null for a previous/next link that has no page. |
meta.links[].active | boolean | Whether this is the current page. |
meta.path | string | The endpoint URL, without the page query. |
meta.per_page | integer | Rows per page. |
meta.to | integer or null | Position of the last row on this page, or null when the page is empty. |
meta.total | integer | Total rows across all pages. |
Response payload
{
"data": [
{
"id": 3007,
"location_name": "Acme Coffee - docs-test-loc-001",
"total_reviews": 120,
"total_responses": 108,
"avg_resp_time": 1.5,
"avg_rating": 4.44,
"response_rate": 90.0
}
],
"links": {
"first": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location?page=1",
"last": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"page": null,
"active": false
},
{
"url": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location?page=1",
"label": "1",
"page": 1,
"active": true
},
{
"url": null,
"label": "Next »",
"page": null,
"active": false
}
],
"path": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location",
"per_page": 10,
"to": 1,
"total": 1
}
}Examples
Success payload
See Response payload.
No location has reviews in the range:
{
"data": [],
"links": {
"first": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location?page=1",
"last": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": null,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"page": null,
"active": false
},
{
"url": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location?page=1",
"label": "1",
"page": 1,
"active": true
},
{
"url": null,
"label": "Next »",
"page": null,
"active": false
}
],
"path": "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location",
"per_page": 10,
"to": null,
"total": 0
}
}Error payload
422 Date range missing
{
"message": "The range start field is required. (and 1 more error)",
"errors": {
"range_start": [
"The range start field is required."
],
"range_end": [
"The range end field is required."
]
}
}422 Wrong date format
{
"message": "The range start field must match the format Y-m-d H:i:s.",
"errors": {
"range_start": [
"The range start field must match the format Y-m-d H:i:s."
]
}
}422 Account outside your tree
{
"message": "The selected account id does not belong to your company hierarchy.",
"errors": {
"account_id": [
"The selected account id does not belong to your company hierarchy."
]
}
}422 Location doesn't exist
{
"message": "The selected store id is invalid. (and 1 more error)",
"errors": {
"store_id": [
"The selected store id is invalid.",
"The selected store id does not belong to your company hierarchy."
]
}
}422 Unknown sort field or direction
{
"message": "The selected sort field is invalid. (and 1 more error)",
"errors": {
"sort_field": [
"The selected sort field is invalid."
],
"sort_by": [
"The selected sort by is invalid."
]
}
}422 limit above 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."
}| Status | Meaning |
|---|---|
200 | One row per location, a page at a time. |
401 | The token is missing, expired or invalid. |
422 | A date is missing or not Y-m-d H:i:s, an id doesn't exist or is outside your tree, sort_field, sort_by or search_field isn't an allowed value, or limit is above 100. |
429 | More than 120 requests in a minute from this user. |
500 | Unexpected server error. |
Example request
curl --request POST \
--url "https://production-api.shoutaboutus.com/api/v1/partner/report/review-response/by-location" \
--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-09-30 23:59:59", "account_id": 5994, "sort_field": "total_reviews", "sort_by": "desc", "limit": 10, "page": 1}'Updated 17 days ago
Did this page help you?
