Fetch reviews for one location or your whole account

List the latest reviews for a location, filter to unanswered low ratings, page with cursors, sweep the account, and get notified by webhook.

Reviews are called interactions in the API. Every review from Google, Facebook or Yelp lands in one list per location, and one rollup for the account, so a single integration covers every source you connect.

1. List the latest reviews for one location

GET /locations/{locationId}/reviews is a cursor connection at data.interactions. Results come newest first, and first defaults to 20, so one call is never the full history. The path accepts the base64 id or the plain number.

Latest reviews
curl "https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/reviews?first=10" \-H "Authorization: API $LISTINGSAPI_KEY"
JSON
{  "data": {    "interactions": {      "pageInfo": { "hasNextPage": true, "endCursor": "SW50ZXJhY3Rpb246MV8xNTU0..." },      "edges": [        {          "node": {            "id": "9e26d2a8-a6ed-42ea-8454-47d1c92ea841",            "source": "maps.google.com",            "content": "nice place for family together",            "authorName": "vaibhav nakate",            "rating": 5,            "date": "2019-04-02T22:11:13.036997+00:00",            "responded": false,            "responseCount": 0,            "canRespond": true,            "permalink": "https://maps.google.com/maps?cid=..."          },          "cursor": "SW50ZXJhY3Rpb246MV8xNTU0..."        }      ],      "totalCount": 425    }  }}

Read data.interactions.edges[].node. The id is a plain UUID, not a base64 Relay id, and it is what you pass when you reply. totalCount is the number of matches across the whole result set, not this page. canRespond says whether that source accepts owner replies from the API.

2. Filter to unanswered low ratings

Array filters are JSON strings on the query string: ratingFilters=[1,2] keeps one and two star reviews, and responseStatus=["PENDING"] keeps reviews without an owner reply. The brackets and quotes must be URL-encoded, so the cURL sample uses -G with --data-urlencode, which encodes each value and appends it to the URL for you. The equivalent literal query string is ratingFilters=%5B1%2C2%5D&responseStatus=%5B%22PENDING%22%5D.

Unanswered 1-2 stars
curl -G "https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/reviews" \-H "Authorization: API $LISTINGSAPI_KEY" \--data-urlencode 'ratingFilters=[1,2]' \--data-urlencode 'responseStatus=["PENDING"]' \--data-urlencode 'sortOrder=["NEWEST_FIRST"]' \--data-urlencode 'first=50'

The filters you can combine:

ParameterValuesNotes
siteUrls["maps.google.com"], ["facebook.com"], ["yelp.com"]Hostnames from List review sources for an account.
ratingFilters[1,2] and so onStar ratings to keep.
responseStatus["PENDING"] or ["RESPONDED"]Whether an owner reply exists.
sortOrder["NEWEST_FIRST"], ["OLDEST_FIRST"], ["LAST_RESPONDED"]Default is newest first.
startDate, endDateYYYY-MM-DDPlain strings, not JSON.
searchStringfree textFull-text search on the review body.

3. Page through with cursors

Pass pageInfo.endCursor back as after. Stop when hasNextPage is false or a page returns an empty edges array; a boundary that lands on the oldest review is followed by one empty page. Both SDKs can walk the pages for you.

Next page
curl "https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/reviews?first=50&after=SW50ZXJhY3Rpb246MV8xNTU0..." \-H "Authorization: API $LISTINGSAPI_KEY"

Each request counts against your rate limit, and a 425-review location at first=50 is nine calls. On a 429, wait for Retry-After before the next page. For a scheduled sync, bound the run with startDate and endDate instead of re-reading history. See Rate limits.

4. Sweep the whole account with the rollup

GET /rollup_interactions returns the same nodes across every location the key can see, at data.rollupInteractions, with a locationId on each node. It takes the same filters plus tag, which defaults to all. There is no location filter; group by locationId yourself. Neither SDK wraps this endpoint yet, so the SDK samples call it with requests and fetch.

Account-wide pending
curl -G "https://listingsapi.com/api/v4/rollup_interactions" \-H "Authorization: API $LISTINGSAPI_KEY" \--data-urlencode 'responseStatus=["PENDING"]' \--data-urlencode 'sortOrder=["NEWEST_FIRST"]' \--data-urlencode 'first=50'

Each node has the same shape as step 1 plus a numeric locationId, the databaseId of the store. The rollup's pageInfo may omit endCursor, so take the cursor of the last edge as after; the two values are equivalent.

5. Fetch full details by id

When you have stored ids, GET /reviewDetails returns fresh copies without paging. interactionIds is a JSON array, URL-encoded like the other filters. The response is a plain array at data.interactionDetails.interactions, and each interaction includes its responses.

Details by id
curl -G "https://listingsapi.com/api/v4/reviewDetails" \-H "Authorization: API $LISTINGSAPI_KEY" \--data-urlencode 'interactionIds=["9e26d2a8-a6ed-42ea-8454-47d1c92ea841"]'
JSON
{  "data": {    "interactionDetails": {      "interactions": [        {          "id": "9e26d2a8-a6ed-42ea-8454-47d1c92ea841",          "responded": true,          "responseCount": 1,          "responses": [            {              "id": "2090753a-ece6-4837-8336-8494ad308523",              "content": "Thank you so much for the kind words!",              "interactionStatus": "CONFIRMED"            }          ]        }      ]    }  }}

An id from another account returns 200 with interactionDetails: null and an SY90001 error, so check for null before indexing.

6. Get told instead of polling

With a webhooks URL configured, an interaction.review event fires when a review is ingested or changes. The review fields sit under data.interaction, not directly under data, and data.interaction.id is the same UUID the list returns.

Two cautions. location_id on this event is passed through unnormalized: it can be a numeric string or null, so convert it yourself rather than trusting the type. And the same id arrives again whenever the review changes, so treat the event as a prompt to re-read the review, not as a one-time insert. Delivery is a single attempt with no retry, so keep a periodic sweep from step 4 as the backstop. Setup is in React to events with webhooks.

Next steps