Event reference
All 26 Listings API webhook events, grouped by resource, with the exact fields and an example payload for each.
Twenty-six events, grouped by the REST resource they relate to. Every event on
this page is delivered to your single webhooks URL. There is no per-event
subscription, so branch on event and ignore what you don't need.
All of them use the standard payload
except listing.submission, which is called out below. Optional fields inside
data are omitted when empty rather than sent as null.
Index
Listings
Pairs with the Listings endpoints, in particular
GET /locations/{locationId}/listings/premium,
which returns the per-citation syncStatus and listingUrl this event
announces.
listing.submission
Trigger: a citation submission for one location on one directory site reaches a terminal state.
Top level:
Inside data:
{ "event": "listing.submission", "data": { "business_id": 279381, "v4_business_id": "TG9jYXRpb246Mjc5Mzgx", "location_id": "TG9jYXRpb246Mjc5Mzgx", "site": { "id": 42, "name": "Yelp", "url": "https://www.yelp.com" } }, "status": "success", "live_link": "https://www.yelp.com/biz/acme-dental-downtown"}Locations
Location lifecycle, 1:1 with createLocation,
updateLocation and
archiveLocations. Location-scoped:
location_id is always a numeric string.
profile.created
Trigger: a new location is created.
{ "event": "profile.created", "timestamp": "2026-08-25T10:04:00Z", "account_id": 11073, "location_id": "901234", "data": { "source": "api" }}profile.updated
Trigger: an existing location's details are edited.
Debounced to one delivery per location per 60 seconds, on the leading edge.
Edits inside the window are collapsed, not delayed. They never arrive. Treat
changed_fields as a hint about the edit that opened the window, not as a
complete diff.
The event arrives at the start of the window, so reading the location back when it lands shows you only that first edit. Schedule a second read-back once the window has closed, at least 60 seconds later, and reconcile locations on a timer too, since this event gets one delivery attempt and no retry. See recovering from a missed event.
{ "event": "profile.updated", "timestamp": "2026-08-25T10:06:12Z", "account_id": 11073, "location_id": "901234", "data": { "source": "user", "changed_fields": ["name", "phone"] }}profile.deleted
Trigger: a location is archived. This is a soft delete. There is no hard
delete, and an archive can be cancelled with
cancelArchiveLocations, which does not
emit an event.
{ "event": "profile.deleted", "timestamp": "2026-08-25T10:20:44Z", "account_id": 11073, "location_id": "901234", "data": { "source": "user" }}Connected accounts
Google and Facebook connection lifecycle and health, alongside the
Connected Accounts endpoints. Location-scoped.
platform is always google or facebook; other providers do not emit these
events.
connected_account_id is always present as a key, but is null on the two
Google verification events.
connection.location_connected
Trigger: a Google or Facebook listing is linked to a location.
{ "event": "connection.location_connected", "timestamp": "2026-08-25T14:32:10Z", "account_id": 11073, "location_id": "279381", "data": { "platform": "google", "connected_account_id": "ba03bc4b-9f8c-4d3b-8e93-9628034c63cc" }}connection.location_disconnected
Trigger: a Google or Facebook listing is unlinked from a location.
{ "event": "connection.location_disconnected", "timestamp": "2026-08-25T14:35:02Z", "account_id": 11073, "location_id": "279381", "data": { "platform": "google", "connected_account_id": "ba03bc4b-9f8c-4d3b-8e93-9628034c63cc" }}connection.reauth_required
Trigger: the connected account's credentials were invalidated. Nothing will sync for this connection until someone re-authorizes it.
{ "event": "connection.reauth_required", "timestamp": "2026-08-25T14:40:18Z", "account_id": 11073, "location_id": "279381", "data": { "platform": "google", "connected_account_id": "ba03bc4b-9f8c-4d3b-8e93-9628034c63cc", "reason": "Google credentials are invalid. Please reconnect." }}connection.listing_inaccessible
Trigger: the connected account can no longer reach the location's listing.
Distinct from reauth_required: the credentials may still be perfectly valid,
but access to that particular listing was removed.
{ "event": "connection.listing_inaccessible", "timestamp": "2026-08-25T14:42:55Z", "account_id": 11073, "location_id": "279381", "data": { "platform": "facebook", "connected_account_id": "cf12de77-2211-4a09-b7c1-0a6f3b2e91aa", "reason": "No longer has access to this listing." }}connection.google_verification_verified
Trigger: a location's Google Business Profile passes verification.
{ "event": "connection.google_verification_verified", "timestamp": "2026-08-25T14:50:00Z", "account_id": 11073, "location_id": "279381", "data": { "platform": "google", "connected_account_id": null }}connection.google_verification_failed
Trigger: a Google Business Profile verification reaches a terminal failure. No REST call starts one; the status itself is readable, as above.
Only terminal states emit an event: VERIFIED fires the _verified event,
and SUSPENDED or DUPLICATE (failure_type rejected) and
ERROR_WHILE_FETCHING (transient) fire this one. The in-progress states
(PENDING_VERIFICATION, UNDER_REVIEW, NOT_VERIFIED, NOT_CONNECTED)
produce no event at all, so absence of an event is not a signal. Poll
googleVerificationStatus on a location read while a verification is in
flight.
{ "event": "connection.google_verification_failed", "timestamp": "2026-08-25T14:52:31Z", "account_id": 11073, "location_id": "279381", "data": { "platform": "google", "connected_account_id": null, "failure_type": "rejected", "reason": "This profile is suspended." }}Reviews
Reviews and responses, alongside the Reviews endpoints including respond, edit response and archive response.
Reviews in the Social category are filtered out and never delivered.
interaction.review
Trigger: a review is ingested or changes.
{ "event": "interaction.review", "timestamp": "2026-08-25T09:12:44Z", "account_id": 11073, "location_id": "279381", "data": { "interaction": { "id": "6f8a1d20-3e11-4a55-9f7d-2b0c9e5a4471", "type": "Review", "content": "Friendly staff and no waiting.", "rating": 5, "title": null, "author_name": "Dana R.", "author_avatar": "https://lh3.googleusercontent.com/a/example", "date": "2026-08-25T08:58:02Z", "source": "google.com", "permalink": "https://maps.google.com/example-review", "category": "Review", "interaction_status": "unread", "parent_id": null, "interaction_request_id": "3c1e9b74-88a2-4d0e-9c31-77a1f0be5d92" } }}interaction.response
Trigger: a response to a review is posted, edited, or archived. The same
shape as interaction.review, with two differences: type is Response, and
parent_id points at the review being responded to.
All the other fields listed under
interaction.review are present with the same meaning.
{ "event": "interaction.response", "timestamp": "2026-08-25T09:30:07Z", "account_id": 11073, "location_id": "279381", "data": { "interaction": { "id": "b2d7c095-5f43-4e21-8a10-6d9c3f77e208", "type": "Response", "content": "Thanks Dana, see you next time!", "rating": null, "author_name": "Acme Dental Downtown", "date": "2026-08-25T09:29:55Z", "source": "google.com", "permalink": "https://maps.google.com/example-review", "category": "Review", "interaction_status": "responded", "parent_id": "6f8a1d20-3e11-4a55-9f7d-2b0c9e5a4471", "interaction_request_id": "3c1e9b74-88a2-4d0e-9c31-77a1f0be5d92" } }}Posts
Google Business Profile local posts, alongside the Posts
endpoints. Location-scoped, location_id is a numeric string.
The four events share one data shape; the optional fields differ. All
optional fields are omitted when empty.
local_post.created
Trigger: a post item is created and queued for submission to Google. It is not live yet.
{ "event": "local_post.created", "timestamp": "2026-08-25T11:02:00Z", "account_id": 11073, "location_id": "279381", "data": { "post_id": 88421, "post_item_id": 5512309, "post_type": "STANDARD" }}local_post.published
Trigger: Google accepted the post and it is live.
{ "event": "local_post.published", "timestamp": "2026-08-25T11:06:41Z", "account_id": 11073, "location_id": "279381", "data": { "post_id": 88421, "post_item_id": 5512309, "post_type": "STANDARD", "post_external_id": "accounts/123/locations/456/localPosts/789" }}local_post.rejected
Trigger: Google rejected the post, or submitting it failed.
{ "event": "local_post.rejected", "timestamp": "2026-08-25T11:07:15Z", "account_id": 11073, "location_id": "279381", "data": { "post_id": 88421, "post_item_id": 5512310, "post_type": "OFFER", "rejection_reason": "Rejected" }}local_post.deleted
Trigger: the post item is deleted.
{ "event": "local_post.deleted", "timestamp": "2026-08-25T15:40:09Z", "account_id": 11073, "location_id": "279381", "data": { "post_id": 88421, "post_item_id": 5512309, "post_type": "STANDARD", "post_external_id": "accounts/123/locations/456/localPosts/789" }}Social
Brand-level social publishing and connection lifecycle, alongside the Social endpoints. Nine events: five for posts, four for connections.
account_id and timestamp are present as normal. IDs inside data are the
same plain UUIDs the REST API uses, sent as strings.
social_post.created
Trigger: a social post is created. Create only — an edit to an existing post does not re-emit.
{ "event": "social_post.created", "timestamp": "2026-09-28T14:02:11Z", "account_id": 62570, "location_id": null, "data": { "post_id": "c47a1e58-2b93-4f10-a6d7-58e0c9b12345", "social_profile_id": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "status": "scheduled", "created_by": 40122, "platform_ids": [1, 2, 4] }}social_post.published
Trigger: the post went fully live. This event is emitted only on a complete
success: at least one channel published and no channel errored. A partial
publish does not emit it — that path emits
social_post.failed instead.
{ "event": "social_post.published", "timestamp": "2026-10-02T13:30:07Z", "account_id": 62570, "location_id": null, "data": { "post_id": "c47a1e58-2b93-4f10-a6d7-58e0c9b12345", "social_profile_id": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "status": "published", "published_on": "2026-10-02T13:30:04", "items": [ { "platform": "instagram", "social_platform_id": 2, "connected_account_id": "b81d5b3c-4a90-4f6a-9c11-71e0dd2fa4a7", "published_url": "https://www.instagram.com/p/CxYz1234abc/", "vendor_post_id": "18029384756012345", "status": "success" } ] }}social_post.failed
Trigger: publishing failed. This is a delivery failure, distinct from an editorial rejection. It fires at the terminal retry, so it is not emitted while the post still has attempts left.
items carries only the channels that errored, so a post that published on
two platforms and failed on a third arrives here with one item.
{ "event": "social_post.failed", "timestamp": "2026-10-02T13:34:55Z", "account_id": 62570, "location_id": null, "data": { "post_id": "c47a1e58-2b93-4f10-a6d7-58e0c9b12345", "social_profile_id": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "status": "failed", "items": [ { "platform": "linkedin", "social_platform_id": 4, "status": "error", "reason": "Authorization expired", "vendor_error": "The access token is no longer valid." } ] }}social_post.rejected
Trigger: an approval workflow rejected the post. Editorial, not delivery: the post never reached a platform.
{ "event": "social_post.rejected", "timestamp": "2026-09-29T09:11:03Z", "account_id": 62570, "location_id": null, "data": { "post_id": "e08b2d97-6f14-4c22-b7a5-9d3e1f6c4a70", "social_profile_id": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "status": "rejected", "rejection_reason": "Please use the updated product name." }}social_post.deleted
Trigger: the post was archived, whether through
POST /social/posts/cancel or by the scheduled
archival sweep. It fires only on a real transition, so re-archiving an already
archived post emits nothing.
{ "event": "social_post.deleted", "timestamp": "2026-09-30T16:20:41Z", "account_id": 62570, "location_id": null, "data": { "post_id": "e08b2d97-6f14-4c22-b7a5-9d3e1f6c4a70", "social_profile_id": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "status": "archived", "archived_at": "2026-09-30T16:20:39" }}social_connection.connected
Trigger: a brand channel became active, either a first connection or a
reconnection of one that had been archived. is_reconnect distinguishes the two.
{ "event": "social_connection.connected", "timestamp": "2026-09-27T11:05:22Z", "account_id": 62570, "location_id": null, "data": { "social_profile_id": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "connected_account_id": "b81d5b3c-4a90-4f6a-9c11-71e0dd2fa4a7", "platform": "instagram", "display_name": "Jenny Home", "is_reconnect": false }}social_connection.disconnected
Trigger: the channel was deliberately removed with a disconnect call. It is emitted only when the channel really was archived, so a disconnect that failed does not produce a false event.
{ "event": "social_connection.disconnected", "timestamp": "2026-10-04T08:47:10Z", "account_id": 62570, "location_id": null, "data": { "social_profile_id": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "connected_account_id": "b81d5b3c-4a90-4f6a-9c11-71e0dd2fa4a7", "platform": "instagram", "display_name": "Jenny Home" }}social_connection.archived
Trigger: the channel was lost involuntarily — the platform invalidated the
token, or a reconciliation pass found the channel no longer reachable. Nobody
asked for this, which is what separates it from disconnected.
{ "event": "social_connection.archived", "timestamp": "2026-10-06T02:15:33Z", "account_id": 62570, "location_id": null, "data": { "social_profile_id": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "connected_account_id": "2d4e6f80-1c33-4b7a-8e05-9a1b2c3d4e5f", "platform": "facebook", "display_name": "Jenny Home & Co.", "reason": "Access token has been invalidated by the platform." }}Review analytics
Scheduled review roll-ups, one event per location per period.
Both events share one data shape:
A location with no activity in the period emits nothing, but so does a
location whose snapshot never made it. A missing snapshot is ambiguous, and
for this family the benign reading is the least likely one. It can mean: no
activity; a delivery that failed or timed out (there is one attempt and no
retry); delivery gated off because the account lacks the webhooks entitlement,
has no configured URL, or is unverified or blocked; or, most likely here, the
per-minute cap dropping part of the burst as rate_limited.
Never record a zero on the strength of an absent snapshot. Reconcile against
GET /locations/{locationId}/review-analytics-overview
for the same period, and if that read fails too, report the period as
unavailable rather than as zero.
review_analytics.daily_snapshot
Trigger: the daily roll-up job, once per location per day.
{ "event": "review_analytics.daily_snapshot", "timestamp": "2026-08-25T02:00:00Z", "account_id": 11073, "location_id": "279381", "data": { "period": "2026-08-24", "granularity": "daily", "total_reviews": 1240, "new_reviews_in_period": 3, "average_rating": 4.6667, "previous_average_rating": 5.0 }}review_analytics.weekly_snapshot
Trigger: the weekly roll-up job, once per location per week. period is
the first day of the week being summarized.
{ "event": "review_analytics.weekly_snapshot", "timestamp": "2026-08-24T02:00:00Z", "account_id": 11073, "location_id": "279381", "data": { "period": "2026-08-17", "granularity": "weekly", "total_reviews": 1237, "new_reviews_in_period": 18, "average_rating": 4.6123, "previous_average_rating": 4.5901 }}Events you may receive but should not build on
The platform emits other families: review campaigns, rankings, social post
boosts, social ad-account status changes, AI post ideas, and Google Business
Profile ownership. They have no published REST endpoint in the Listings API, they are
not documented here, and their shapes are not covered by any compatibility
guarantee. Because there is one URL and no per-event subscription, your handler
should ignore any event it does not recognize and still return 200.