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 theContent-Type
header andapplication/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 about product status changes for a specific merchant account.
POST https://merchantapi.googleapis.com/notifications/v1beta/accounts/MERCHANT_ID/notificationsubscriptions/
{
"registeredEvent": "PRODUCT_STATUS_CHANGE",
"targetAccount": "accounts/TARGETMERCHANT_ID",
"callBackUri": "https://example.com"
}
Replace the following:
- MERCHANT_ID: The unique identifier of the account that should receive the notifications.
- TARGETMERCHANT_ID: The unique identifier of the account about which you want to receive notifications.
If your Merchant Center account is a standalone account with no linked accounts, and you want to receive notifications for your own account, replace both these variables with your account ID.
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": true
instead 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 https://merchantapi.googleapis.com/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": "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/TARGETMERCHANT_ID/products/ONLINE~en~US~1234",
"expirationTime": "2024-10-22T02:43:47.461464Z",
"eventTime": "2024-03-21T02: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 expirationTime
field won't exist in case the product was deleted.
The reportingContext
field supports only (SHOPPING_ADS
, LOCAL_INVENTORY_ADS
, YOUTUBE_SHOPPING
, YOUTUBE_CHECKOUT
, YOUTUBE_AFFILIATE
) from the enum value ReportingContextEnum.
For product status change event, oldValue
and newValue
fields will have one
of these values : (approved
, pending
, disapproved
, ``).
The eventTime
field holds the creation time of the event itself, if you want
to do message ordering you should rely on the value in that field and don't rely
on the order of receiving the messages.
Follow the ProductStatusChangeMessage format for more details.
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":
"ewogICJhY2NvdW50IjogImFjY291bnRzLzEyMzQiLAogICJtYW5hZ2luZ0FjY291bnQiOiAiYWNjb3VudHMvNTY3OCIsCiAgInJlc291cmNlVHlwZSI6ICJQUk9EVUNUIiwKICAiYXR0cmlidXRlIjogIlNUQVRVUyIsCiAgImNoYW5nZXMiOiBbewogICAgIm9sZFZhbHVlIjogImFwcHJvdmVkIiwKICAgICJyZWdpb25Db2RlIjogIlVTIiwKICAgICJyZXBvcnRpbmdDb250ZXh0IjogIlNIT1BQSU5HX0FEUyIKICB9XSwKICAicmVzb3VyY2VJZCI6ICJPTkxJTkV+ZW5+VVN+MDAwMDAwMDAwMDAwIiwKICAicmVzb3VyY2UiOiAiYWNjb3VudHMvMTIzNC9wcm9kdWN0cy9PTkxJTkV+ZW5+VVN+MDAwMDAwMDAwMDAwIiwKICAiZXhwaXJhdGlvblRpbWUiOiAiMjAyNC0xMC0yMlQwMjo0Mzo0Ny40NjE0NjRaIiwKICAiZXZlbnRUaW1lIjogIjIwMjQtMDMtMjFUMDI6NDM6NDcuNDYxNDY0WiIKfQ=="}}' 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": "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"
}