Get push notifications for product status changes

You can subscribe to PRODUCT_STATUS_CHANGE notifications to receive real-time alerts whenever product approval statuses change in your Merchant Center accounts. For example, you can detect when a product becomes disapproved so you can fix potential data quality issues.

Before you begin, ensure that your callback URI is configured according to the requirements described in the Notifications sub-API Overview.

Subscribe to product status changes

To subscribe to product status changes, send a POST request to the notificationsubscriptions resource with registeredEvent set to PRODUCT_STATUS_CHANGE.

Subscribe for a specific target account

The following sample request subscribes to product status changes for a specific merchant account:

POST https://merchantapi.googleapis.com/notifications/v1/accounts/{ACCOUNT_ID}/notificationsubscriptions/
{
  "registeredEvent": "PRODUCT_STATUS_CHANGE",
  "targetAccount": "accounts/{TARGETACCOUNT_ID}",
  "callBackUri": "https://example.com/callback"
}

Replace the following:

  • ACCOUNT_ID: The identifier of the account that owns the subscription and receives notifications.
  • TARGETACCOUNT_ID: The identifier of the account about which you want to receive notifications.

If your Merchant Center account is a standalone account with no linked accounts, use your own account ID for both variables.

Subscribe for all managed accounts

If you manage multiple accounts (such as an advanced account with sub-accounts), you can subscribe to product status changes across all managed accounts by setting allManagedAccounts: true:

POST https://merchantapi.googleapis.com/notifications/v1/accounts/{ACCOUNT_ID}/notificationsubscriptions/
{
  "registeredEvent": "PRODUCT_STATUS_CHANGE",
  "allManagedAccounts": true,
  "callBackUri": "https://example.com/callback"
}

Successful calls return a name identifier for your subscription, including a unique subscription ID:

{
  "name":"accounts/{ACCOUNT_ID}/notificationsubscriptions/{SUBSCRIPTION_ID}",
  "registeredEvent": "PRODUCT_STATUS_CHANGE",
  "allManagedAccounts": true,
  "callBackUri": "https://example.com/callback"
}

Decode product status change payloads

When a product status change occurs, your callback URI receives a base64-encoded message. When decoded, the payload conforms to the ProductStatusChangeMessage format:

{
  "account": "accounts/{TARGETACCOUNT_ID}",
  "managingAccount": "accounts/{ACCOUNT_ID}",
  "resourceType": "PRODUCT",
  "attribute": "STATUS",
  "changes": [{
    "oldValue": "approved",
    "newValue": "disapproved",
    "regionCode": "US",
    "reportingContext": "SHOPPING_ADS"
  }, {
    "oldValue": "approved",
    "newValue": "disapproved",
    "regionCode": "JP",
    "reportingContext": "SHOPPING_ADS"
  },{
    "oldValue": "approved",
    "newValue": "disapproved",
    "regionCode": "GE",
    "reportingContext": "SHOPPING_ADS"
  }],
  "resourceId": "ONLINE~en~US~1234",
  "resource": "accounts/{TARGETACCOUNT_ID}/products/ONLINE~en~US~1234",
  "expirationTime": "2024-10-22T02:43:47.461464Z",
  "eventTime": "2024-03-21T02:43:47.461464Z"
}

Payload fields and rules

  • oldValue and newValue: Represent the previous and updated status. Possible values are approved, pending, disapproved, or an empty string ('').
    • If oldValue is omitted, the product is newly created.
    • If newValue is omitted, the product was deleted.
  • expirationTime: Indicates when the product offer expires. This field is omitted when a product is deleted.
  • reportingContext: The advertising or free listing surface where the status changed. Supported values include SHOPPING_ADS, LOCAL_INVENTORY_ADS, YOUTUBE_SHOPPING, YOUTUBE_CHECKOUT, YOUTUBE_AFFILIATE, and FREE_LISTINGS_UCP_CHECKOUT from the ReportingContextEnum.
  • eventTime: The timestamp when the event was generated. Use this timestamp to ensure proper ordering of events.

Test product status change notifications

Use the following sample request to test whether your callback endpoint receives, acknowledges, and decodes product status change messages correctly:

curl --request POST \
'https://{YOUR_CALLBACK_URI}' \
--header 'Content-Type: application/json' \
--header 'Accept: text/plain' \
--data '{"message":{"data": "ewogICJhY2NvdW50IjogImFjY291bnRzLzEyMzQiLAogICJtYW5hZ2luZ0FjY291bnQiOiAiYWNjb3VudHMvNTY3OCIsCiAgInJlc291cmNlVHlwZSI6ICJQUk9EVUNUIiwKICAiYXR0cmlidXRlIjogIlNUQVRVUyIsCiAgImNoYW5nZXMiOiBbewogICAgIm9sZFZhbHVlIjogImFwcHJvdmVkIiwKICAgICJyZWdpb25Db2RlIjogIlVTIiwKICAgICJyZXBvcnRpbmdDb250ZXh0IjogIlNIT1BQSU5HX0FEUyIKICB9XSwKICAicmVzb3VyY2VJZCI6ICJPTkxJTkV+ZW5+VVN+MDAwMDAwMDAwMDAwIiwKICAicmVzb3VyY2UiOiAiYWNjb3VudHMvMTIzNC9wcm9kdWN0cy9PTkxJTkV+ZW5+VVN+MDAwMDAwMDAwMDAwIiwKICAiZXhwaXJhdGlvblRpbWUiOiAiMjAyNC0xMC0yMlQwMjo0Mzo0Ny40NjE0NjRaIiwKICAiZXZlbnRUaW1lIjogIjIwMjQtMDMtMjFUMDI6NDM6NDcuNDYxNDY0WiIKfQ=="}}'

In response to this call, your callback URI should return an acceptable HTTP status code (such as 200 OK). The decoded message has the following content:

{
  "account": "accounts/1234",
  "managingAccount": "accounts/5678",
  "resourceType": "PRODUCT",
  "attribute": "STATUS",
  "changes": [{
    "oldValue": "approved",
    "regionCode": "US",
    "reportingContext": "SHOPPING_ADS"
  }],
  "resourceId": "ONLINE~en~US~000000000000",
  "resource": "accounts/1234/products/ONLINE~en~US~000000000000",
  "expirationTime": "2024-10-22T02:43:47.461464Z",
  "eventTime": "2024-03-21T02:43:47.461464Z"
}