Event reference
All 18 Listings API webhook events, grouped by resource, with the exact fields and an example payload for each.
Eighteen 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 envelope
except listing.submission, which is called out below. Optional fields inside
data are omitted when empty rather than sent as null.
Index
| Event | Resource | Fires when |
|---|---|---|
listing.submission | Listings | A citation submission to a directory site resolves |
profile.created | Locations | A location is created |
profile.updated | Locations | A location is edited |
profile.deleted | Locations | A location is archived |
connection.location_connected | Connected Accounts | A Google or Facebook listing is linked |
connection.location_disconnected | Connected Accounts | A listing is unlinked |
connection.reauth_required | Connected Accounts | Credentials were invalidated |
connection.listing_inaccessible | Connected Accounts | Access to a listing was lost |
connection.google_verification_verified | Connected Accounts | Google verification succeeded |
connection.google_verification_failed | Connected Accounts | Google verification failed |
interaction.review | Reviews | A review arrives or changes |
interaction.response | Reviews | A response is posted or changes |
local_post.created | Posts | A post is created |
local_post.published | Posts | A post goes live on Google |
local_post.rejected | Posts | Google rejected a post |
local_post.deleted | Posts | A post is deleted |
review_analytics.daily_snapshot | Analytics | The daily review roll-up runs |
review_analytics.weekly_snapshot | Analytics | The weekly review roll-up runs |
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:
| Field | Type | Description |
|---|---|---|
event | string | Always listing.submission. |
data | object | See below. |
status | string | success, incomplete, or canceled. |
live_link | string | The live listing URL. Only on success, and only when one is known. |
error_message | string | Why the submission could not complete. Only on incomplete. |
Inside data:
| Field | Type | Description |
|---|---|---|
business_id | integer | The location's numeric id. |
v4_business_id | string | Base64 of Location:<id> — the global ID form. |
location_id | string | The same base64 global ID, not a numeric string. |
site.id | integer | The directory site's id. |
site.name | string | The directory site's name, e.g. Yelp. |
site.url | string | The directory site's home URL. |
{
"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.
data field | Type | Description |
|---|---|---|
source | string | Who created it: user, api, or bulk_edit. |
{
"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, and read the location back if you need current state.
data field | Type | Description |
|---|---|---|
source | string | user, api, or bulk_edit. |
changed_fields | array of string | Location field names that changed, e.g. name, phone, address1. Omitted when empty. |
{
"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.
data field | Type | Description |
|---|---|---|
source | string | user, api, or bulk_edit. |
{
"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.
data field | Type | Description |
|---|---|---|
platform | string | google or facebook. |
connected_account_id | string | The connected account that was linked. |
{
"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.
data field | Type | Description |
|---|---|---|
platform | string | google or facebook. |
connected_account_id | string | The connected account that was unlinked. |
{
"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.
data field | Type | Description |
|---|---|---|
platform | string | google or facebook. |
connected_account_id | string | The connected account needing re-auth. |
reason | string | Human-readable description. Omitted when the source provides none. |
{
"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.
data field | Type | Description |
|---|---|---|
platform | string | google or facebook. |
connected_account_id | string | The connected account that lost access. |
reason | string | Human-readable description. Omitted when the source provides none. |
{
"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.
data field | Type | Description |
|---|---|---|
platform | string | Always google. |
connected_account_id | null | Always null on verification events. |
{
"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. Also observe-only.
Only terminal states emit. In-progress states — under review, pending verification, not yet verified, not connected — produce no event at all, so absence of an event is not a signal.
data field | Type | Description |
|---|---|---|
platform | string | Always google. |
connected_account_id | null | Always null on verification events. |
failure_type | string | rejected for a suspended or duplicate profile; transient when Google could not be read. Retry-worthy only for transient. |
reason | string | Human-readable description. Omitted when the source provides none. |
{
"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.
data.interaction field | Type | Description |
|---|---|---|
id | string | Interaction UUID. Use this to de-duplicate. |
type | string | Review. |
content | string | The review body. May be null. |
rating | number | Star rating. May be null for sources that don't have one. |
title | string | Review title, where the source has one. |
author_name | string | Reviewer's display name. |
author_avatar | string | Reviewer's avatar URL. |
date | string | ISO-8601 date the review was posted at the source. |
source | string | Where it came from, e.g. google.com, facebook.com. |
permalink | string | Link to the review at the source. |
category | string | Interaction category. Social is filtered out before delivery. |
interaction_status | string | Workflow status of the interaction. |
parent_id | string | Always null for a review. |
interaction_request_id | string | The request this interaction belongs to. May be null. |
{
"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.
data.interaction field | Type | Description |
|---|---|---|
type | string | Response. |
parent_id | string | UUID of the review this responds to. |
content | string | The response text. |
rating | number | Always null on a response. |
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.
data field | Type | Description |
|---|---|---|
post_id | integer | The post this item belongs to — the id you get back from the create endpoints. |
post_item_id | integer | The per-location item. A post to 20 locations produces 20 items, and events are per item. |
post_type | string | STANDARD, EVENT, or OFFER. |
post_external_id | string | Google's own resource name for the post. Absent until Google accepts it. |
published_url | string | A browsable URL. Usually absent — Google does not reliably return one; use post_external_id to correlate. |
rejection_reason | string | Only on local_post.rejected. |
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"
}
}
Review analytics
Scheduled review roll-ups, one event per location per period.
Both events share one data shape:
data field | Type | Description |
|---|---|---|
period | string | Period start, YYYY-MM-DD. |
granularity | string | daily or weekly. |
total_reviews | integer | All-time review count for the location. |
new_reviews_in_period | integer | Reviews received during this period. |
average_rating | number | Average rating for this period, to 4 decimal places. 0.0 when there were no reviews. |
previous_average_rating | number | Average rating for the preceding period. 0.0 when there is no preceding data. |
A location with no activity in the period emits nothing, so a missing snapshot means "no reviews in that period", not a delivery failure.
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 posts
and boosts, social connections, AI post ideas, and Google Business Profile
ownership. They have no published REST surface 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.