Get push notifications for changes to your account data

You can use the Merchant Notifications API to get push notifications for changes to account data. For example, if you subscribe to product status change notifications, you can be notified in real time when a product is disapproved. You can subscribe to notifications for any of your sub-accounts or other linked accounts.

This guide provides examples of how to manage notifications for product status changes. You can use these examples to manage notifications for other events by changing the value of the registeredEvent field in your requests. For a full list of the event types, see the Merchant Notifications API reference.

Subscribe

To receive notifications, you need a callBackUri. Your callback URI must meet the following requirements:

  • Must be a publicly accessible HTTPS address with a valid SSL certificate, signed by a certificate authority.
  • Must accept HTTP POST requests with the Content-Typeheader and application/json value.
  • Must return one of the following response codes to acknowledge that the notification was received.
    • 102
    • 200
    • 201
    • 202
    • 204

You can use the same callback URI for multiple subscriptions. We recommend using a unique callback URI per advanced account, per event type to minimize the load of push requests to a single URI.

Here's a sample request to subscribe to notifications for product status changes for a specific merchant account. Use the merchant ID of the account that should receive the notifications as the merchantId in the request URL, and the merchant ID of the account to receive notifications for as the targetMerchantId in the request body. If your account is a standalone account with no linked accounts, and you want to receive notifications for your own account, use your own merchant ID in both places.

POST https://merchantapi.googleapis.com/notifications/v1beta/accounts/MERCHANT_ID/notificationsubscriptions/
{
  "registeredEvent": "PRODUCT_STATUS_CHANGE",
  "targetAccount": "accounts/TARGETMERCHANT_ID",
  "callBackUri": "https://example.com"
}

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

{
  "name":"accounts/MERCHANT_ID/notificationsubscriptions/subscriptionId",
  "registeredEvent": "PRODUCT_STATUS_CHANGE",
  "targetAccount": "accounts/TARGETMERCHANT_ID",
  "callBackUri": "https://example.com"
}

You can use this name to GET and DELETE individual subscriptions.

You can subscribe to notifications for product status changes for all of your linked accounts by including "allManagedAccounts": trueinstead of a targetAccount in your request:

POST https://merchantapi.googleapis.com/notifications/v1beta/accounts/MERCHANT_ID/notificationsubscriptions/

{
  "registeredEvent": "PRODUCT_STATUS_CHANGE",
  "allManagedAccounts": true,
  "callBackUri": "https://example.com"
}

To update an existing subscription, use PATCH with an update_mask to specify the fields you want to update, and the new values in the JSON body:

PATCH /notifications/v1beta/accounts/MERCHANT_ID/notificationsubscriptions/SUBSCRIPTION_ID?update_mask=callBackUri

{
  "​callBackUri": "https://my-own-personal-domain.com"
}

Decode notifications

After you create a subscription, you receive notifications to the specified callBackUri in the following format:

{"message":{"data":"{base64_encoded_string}"}}

The notification data is encoded. You can decode the data to a readable text format to use in your implementation. Here's a sample spring boot controller you might use to process the encoded data:

@RestController
public class ExampleController {
@RequestMapping(value = "/push",
  method = RequestMethod.POST,
  consumes = {"application/json"},
  produces = {"text/plain"})
  @ResponseStatus(HttpStatus.OK)
  public void doStuff(@RequestBody String message) {
        //wrapped message
        JSONObject jsonObject = new JSONObject(message);
        JSONObject jsonMessage = jsonObject.getJSONObject("message");
        message = jsonMessage.getString("data");
        byte[] decodedBytes = Base64.getDecoder().decode(message);
        String decodedMessage = new String(decodedBytes);
        // Implement your business logic here
  }
}

Here's an example of a base64_encoded_string that has been decoded:

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

If there's no oldValue field in the notification, a new product was added to your account. If there's no newValue field, the product was deleted from your account.

The reportingContext field supports only (SHOPPING_ADS, LOCAL_INVENTORY_ADS, YOUTUBE_SHOPPING, YOUTUBE_CHECKOUT) from the enum value ReportingContextEnum.

Test your implementation

Here's a sample notification you can use to test your callback URI and decoding:

curl --header "Content-Type: application/json" --header "Accept: text/plain" --request POST --data '{"message":{"data":
"ewogICJhY2NvdW50IjogImFjY291bnRzLzEyMzQiLAogICJtYW5hZ2luZ0FjY291bnQiOiAiYWNjb3VudHMvNTY3OCIsCiAgInJlc291cmNlVHlwZSI6ICJQUk9EVUNUIiwKICAiYXR0cmlidXRlIjogIlNUQVRVUyIsCiAgImNoYW5nZXMiOiBbewogICAgIm9sZFZhbHVlIjogImVsaWdpYmxlIiwKICAgICJyZWdpb25Db2RlIjogIlVTIiwKICAgICJyZXBvcnRpbmdDb250ZXh0IjogIlNIT1BQSU5HX0FEUyIKICB9XSwKICAicmVzb3VyY2VJZCI6ICJPTkxJTkV+ZW5+VVN+MDAwMDAwMDAwMDAwIiwKICAicmVzb3VyY2UiOiAiYWNjb3VudHMvMTIzNC9wcm9kdWN0cy9PTkxJTkV+ZW5+VVN+MDAwMDAwMDAwMDAwIiwKICAiZXhwaXJhdGlvblRpbWUiOiAiMjAyNC0xMC0yMlQwMjo0Mzo0Ny40NjE0NjRaIgp9"}}' https://{callBackUri}

In response to this call, your callback URI should return a successful response code. The decoded message should have the following value:

{
  "account": "accounts/1234",
  "managingAccount": "accounts/5678",
  "resourceType": "PRODUCT",
  "attribute": "STATUS",
  "changes": [{
    "oldValue": "eligible",
    "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"
}