At a glance
Capabilities
Connecting
auth_url. After they authorize, SocialAPI exchanges the code with Google and redirects the user to your redirect_uri with the connection result. See OAuth flows for the redirect parameters.
If the Google login manages more than one Business Profile, the redirect carries
status=selection_required and a connection_id instead of an immediate account_id. See Google: connecting a login with multiple Business Profiles for the selection steps. This only applies to logins with more than one Profile; a single-Profile login connects directly.You choose one Profile at that point, but you are not limited to it. The login is kept, so its other Profiles can be attributed to your brands later through GET and POST /v1/platforms/google/logins/{loginId}/locations, with no second authorization.Location details
GET /v1/platforms/google/logins/{loginId}/locations returns everything Google publishes about each location, so you do not need a second call to render it. The full schema is in the API reference:
details mirrors Google’s Location resource in full. Beyond the fields above it also carries more_hours (per-department hours such as a drive-through), service_area (where a business without a storefront operates), service_items (services offered, with prices), relationship_data (chain and parent/child locations), ad_phone, opening_date, and the capability flags described below.
place_id is the standard Google Places identifier, so you can join a location to Places, Maps, and Geocoding results. new_review_uri is the short link that opens the review form for that location, useful for review-request campaigns. maps_uri is also promoted to the top level since it is the most commonly used one.
Every field inside
details is omitted when Google returns no value for it, and details itself is absent when Google returns nothing beyond the name and description. A service-area business (a locksmith, a plumber) has no storefront_address and carries service_area instead, and a location can legitimately have no website or phone. Treat every field as optional rather than assuming a fixed shape.has_voice_of_merchant tells you whether the location is in good standing. When it is false the merchant does not currently have control of the profile, and posting or replying will fail until they resolve it in Google Business Profile. When the field is absent entirely, Google told us nothing either way: the boolean flags distinguish a real false from an unknown, so check for presence before treating one as a denial. has_pending_edits and has_google_updated flag edits awaiting review and Google-suggested updates respectively. The can_* flags say which surfaces the location supports, for example can_operate_local_post for publishing and can_have_food_menus for restaurants.Updating a location
PUT /v1/platforms/google/accounts/{id} writes the location’s public profile. Send only the fields you want to change:
regular_hours.periods, labels, additional_phones, and additional_categories each overwrite the whole list, so include every entry you want to keep. Nested objects are the exception: inside storefront_address you can send only postal_code and the rest of the address is untouched.
Not writable: place_id, maps_uri, new_review_uri and the status flags are output-only in Google Business Profile, and language_code is fixed when the location is created (changing it requires deleting and re-creating the location in Google).
Validating before you write
Google has no sandbox, so every write hits a real Business Profile. Passvalidate_only=true to have Google check the change and apply nothing:
"validated": true and an empty data, since nothing was written.
Edits are moderated. A
200 means Google accepted the change for review, not that it is live on Search and Maps. Read the location back to see what is live, and check details.has_pending_edits for edits still under review. Google also allows 10 edits per minute per Business Profile, and states that limit cannot be raised, so pace bulk updates accordingly.Reading samples
List posts
Comments and Q&A
Google Business Profile does not offer a comments or Q&A API. Google discontinued the Business Profile Q&A API on November 3, 2025, with no replacement, and Google Business Profile has never had post-level comments. Reading or answering questions through the API is not available.List reviews
media as Google-hosted URLs. The reply_url field links to the reply page for that review in the Google Business Profile interface.
Reply to a review
state field reports where a reply sits in Google’s moderation:
SocialAPI re-checks a pending reply for you and emits
review.updated once Google settles it, with change set to reply_approved or reply_rejected, so subscribing to that webhook and branching on change is the easiest way to catch the replies that need rewriting. You can also read the review again with GET /v1/inbox/reviews/{account_id} and look at reply.state. A rejected reply also carries reply.policy_violation, passed through exactly as Google sends it:
state entirely, so treat a missing state as “already live”.
Publishing
For the full field reference, media constraints, and error recovery, see Publishing to Google.Profile media
A location’s profile carries its own photos and videos: the logo, the cover image, interior and exterior shots. These are separate from the media attached to a post, and they are what customers see on the listing itself. List them withGET /v1/platforms/google/accounts/{account_id}/media:
media object (url and type) that review photos and post attachments use, plus the category that says where it sits on the profile:
Adding a photo
Add one withPOST /v1/platforms/google/accounts/{account_id}/media. The media array takes exactly one item, in the same {source_type, source} form the publishing endpoints accept, so a photo you already uploaded to your media library works here with no extra step:
category is one of COVER, PROFILE, LOGO, EXTERIOR, INTERIOR, PRODUCT, AT_WORK, FOOD_AND_DRINK, MENU, COMMON_AREA, ROOMS, TEAMS, or ADDITIONAL. PROFILE sets the avatar shown for the location, and LOGO is used as a fallback when no PROFILE photo exists.
Removing a photo
DELETE /v1/platforms/google/accounts/{account_id}/media/{media_id} removes a photo you added. media_id accepts either the bare id or the full resource name from the list response.
Photos your customers posted
Customers can add their own photos to a listing. Those live in a separate, read-only gallery, which you read by passingcontributed=true:
attribution block naming the contributor, and Google requires you to display it exactly as given, without altering or removing it. They also cannot be deleted through the API: a delete returns 403. Use the takedown_url on the item to report one to Google instead.
Google limits a location to 10 edits per minute, and that limit cannot be raised. Adding or deleting several photos in a burst will hit it, so space out bulk changes.
Performance metrics
GET /v1/platforms/google/accounts/{account_id}/insights returns how the location performed day by day: how many people saw it on Google Search and Maps, and how many then called, asked for directions, messaged, booked, ordered, or clicked through to the website.
start_date and end_date are inclusive and formatted YYYY-MM-DD. metric takes a comma-separated list and defaults to every metric:
BUSINESS_IMPRESSIONS_DESKTOP_MAPS, BUSINESS_IMPRESSIONS_DESKTOP_SEARCH, BUSINESS_IMPRESSIONS_MOBILE_MAPS, BUSINESS_IMPRESSIONS_MOBILE_SEARCH, BUSINESS_CONVERSATIONS, BUSINESS_DIRECTION_REQUESTS, CALL_CLICKS, WEBSITE_CLICKS, BUSINESS_BOOKINGS, BUSINESS_FOOD_ORDERS, and BUSINESS_FOOD_MENU_CLICKS.
Search keywords
GET /v1/platforms/google/accounts/{account_id}/search-keywords returns what people searched before seeing the location, aggregated by month over an inclusive YYYY-MM range:
limit is capped at 100 by Google, and cursor pages through the rest.
Push notifications
Google Business Profile has no HTTP webhooks. Events are published to a Google Cloud Pub/Sub topic instead, and SocialAPI runs that topic for you: when you connect a location, we point it at our topic automatically, consume the messages, and deliver them to your own webhook endpoints like every other platform’s events. There is nothing to set up on your side, and no Google Cloud project of your own is required. New reviews arrive asreview.received, carrying the whole review (rating, text, author, attached photos) in data.review, so you do not have to call back for it. A reviewer editing their own review arrives as review.updated with change: "review_edited", which is the same event the reply-moderation outcomes use, so branch on change:
Location-level changes arrive as
account.updated, again with change naming the cause: customer_media_added, google_update_pending, voice_of_merchant_changed, or duplicate_location.
Push lowers latency; it does not replace polling. Google never redelivers a notification that was missed, so a gap in delivery is permanent and reading reviews on a schedule remains the backfill path. Keep your existing sync in place.
Limitations and gotchas
- Local posts include updates, offers, and event posts published through Google Business Profile.
- Account avatars are set at connect time. A Business Profile location has no profile-photo field of its own: the avatar comes from the location’s media gallery, so we read it once when you connect and store it on the account. Changing the
PROFILEphoto in Google later will not update the stored avatar until the account is reconnected. Reading the gallery through the media endpoints always returns the current photos. - Token refresh: Google OAuth tokens expire after 1 hour. SocialAPI handles refresh automatically. If you receive
401withcode: "platform.google.auth", reconnect the account.
Permissions
SocialAPI’s managed Google Cloud OAuth app already requests these scopes on your behalf:https://www.googleapis.com/auth/business.manage. You don’t need to set up a Google Cloud project. See Platform credentials.