How to Reply to Google Business Reviews via API

List and reply to Google Business Profile reviews programmatically — multi-location filtering, star-only reviews, webhooks for new reviews, and reply management.

Which Google API returns reviews?

Two different Google APIs return reviews, and only one of them can reply. A third category — third-party scraping APIs — is not Google at all, but shows up in the same search:

Business Profile APIPlaces APIScraping APIs
Run byGoogleGoogleThird parties
Whose reviewsLocations the authenticated account managesAny place on Google MapsAny place
How manyAll of themA small sample per placeVaries
ReplyYesNoNo
AuthOAuth as the location ownerAPI keyVendor API key
CostFreeMetered by GooglePer request

The question that picks your path is simply whether you own the locations. If you or your customers manage them, the Business Profile API is the only option that can reply, and it is what this guide covers. If you are gathering reviews for places you don’t own — competitor tracking, market research — neither Google API serves that well, which is why scraping vendors rank for this search.

Replying is the dividing line. Nothing outside the Business Profile API can post an owner response, no matter what it costs.

How reviews surface in the API

Google reviews live on a location, not on a post, so they flow through the Profile Comments API rather than the post-level Comments API. A review is a top-level comment; your answer is a reply nested under it.

Postproxy pulls reviews from Google twice a day (06:00 and 18:00 UTC) for every connected google_business profile, and fires a profile_comment.created webhook for each new one — so you don’t poll Google or manage its OAuth scopes.

Prerequisites

  • A Postproxy API key
  • A connected Google Business profile (the connected Google account may manage several locations)

List reviews

Terminal window
curl "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments" \
-H "Authorization: Bearer YOUR_API_KEY"

Results are newest-first by posted_at. Each review carries the reviewer’s name and avatar, your replies in a replies array, and the star rating in platform_data.star_rating.

The list is paginated — per_page defaults to 20 top-level reviews, and page is 1-based. To pull a location’s full review history, walk pages until one comes back short:

Terminal window
curl "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments?per_page=100&page=2" \
-H "Authorization: Bearer YOUR_API_KEY"

Two Google-specific shapes to handle:

  • Star-only reviews — Google allows ratings with no text. body is null but platform_data.star_rating is populated, so don’t skip records on an empty body.
  • Permalink — points at the location’s reviews page on Google, shared by all reviews there. Google’s API doesn’t expose per-review URLs.

What does a review return?

Each review comes back as a comment object. The fields you will actually branch on:

FieldTypeWhat it holds
bodystring | nullReview text. null on star-only reviews
platform_data.star_ratinginteger1–5. Populated even when body is null
platform_data.update_timestringWhen the reviewer last edited it
author_usernamestring | nullReviewer display name. null on your own replies
author_avatar_urlstring | nullReviewer profile image
repliesarrayYour reply, if one exists
statusstringsynced for incoming reviews
posted_atstringSort key — the list is newest-first

Reviews arrive with status: "synced"; the other statuses belong to replies you send. Because update_time moves when a reviewer edits, it is the field to watch if you cache reviews locally — posted_at will not change under you, but the text and rating can.

A review has no per-review URL. If you need to link a human to it, use the location’s metadata.place_id from the placements endpoint to build a Maps link, since Google does not return one.

Multi-location accounts

A google_business profile represents the connected Google account, which may manage multiple locations — including unrelated businesses. Without a filter, the list interleaves reviews from all of them.

Enumerate locations first, then scope by placement_id:

Terminal window
# List locations
curl "https://api.postproxy.dev/api/profiles/PROFILE_ID/placements" \
-H "Authorization: Bearer YOUR_API_KEY"
# Reviews for one location
curl "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments?placement_id=accounts/1234/locations/5678" \
-H "Authorization: Bearer YOUR_API_KEY"

Reply to a review

Terminal window
curl -X POST "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"parent_id": "REVIEW_ID",
"body": "Thanks Jane — glad the espresso landed. See you next week!"
}'

parent_id is required — Google reviews are user-generated, so top-level comments can’t be authored through the API (the request returns 422 without it). It accepts the Postproxy hashid or Google’s native resource path (accounts/X/locations/Y/reviews/Z).

The reply is stored immediately with status: "pending" and external_id: null, then pushed to Google by a background job. A 201 means Postproxy accepted it, not that Google did — the outcome shows up in the status:

StatusMeaning
pendingAccepted, not yet sent to Google
publishedLive on the review
failed_waiting_for_retryGoogle rejected the attempt; another is queued
failedRejected and retries exhausted

On either failure status, error carries a summary and error_details carries the structured platform response — platform_error_code, platform_error_subcode, platform_error_message, plus a postproxy_note with any extra context. Branch on the code rather than matching Google’s message text, which is not stable.

Two request-shape rules worth knowing before you hit them: parent_id is required and its absence returns 422, and replies are the only thing you can create here — a POST without parent_id is not treated as a new review, it is an error.

React to new reviews in real time

Subscribe to profile_comment.created on your webhook endpoint. It fires for newly synced incoming reviews and for your own replies once published. The payload includes placement_id, body, and platform_data.star_rating — enough to route on the spot: thank 5-star reviewers automatically, page a human for anything at 3 stars or below.

The event fires across all locations of the account; filter on data.object.placement_id if you only care about some. For a fully automated pipeline with an LLM drafting the responses, see How to Auto-Respond to Google Reviews with AI.

Update or remove your reply

Google supports one owner reply per review. To remove yours:

Terminal window
curl -X DELETE "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments/REPLY_ID" \
-H "Authorization: Bearer YOUR_API_KEY"

This deletes your reply only — businesses can’t delete the review itself; the original stays.

What the API can and can’t do

ActionSupported
List reviews per locationYes
Read star ratings (incl. star-only reviews)Yes
Filter by location on a multi-location accountYes — placement_id
Reply to a reviewYes
Delete your replyYes
Get a webhook on a new reviewYes — profile_comment.created
Create or delete a reviewNo — reviews are user-generated
Post more than one reply per reviewNo — Google allows one owner reply
Get a per-review permalinkNo — Google returns a location-level URL only
Reply to reviews for a location you don’t manageNo — ownership is the gate

Full object fields and error shapes: Profile Comments API. Publishing local posts, events, and offers to the same profile is covered on the Google Business platform page.

Ready to get started?

Start with our free plan and scale as your needs grow. No credit card required.