Faça atualizações frequentes nos seus produtos

A sub-API Products permite fazer atualizações parciais nos seus produtos atuais. Isso é ideal para dados que mudam com frequência, como preço e disponibilidade, porque evita a necessidade de reenviar todo o produto por uma pequena mudança. No entanto, é recomendável reinserir produtos regularmente para garantir que todos os dados estejam sincronizados.

Este guia mostra como usar o método productinputs.patch para atualizar seus produtos.

Pré-requisitos

Antes de atualizar um produto, você precisa do seguinte:

Atualizar detalhes específicos do produto

Para mudar alguns detalhes de um produto, como preço ou disponibilidade, sem reenviar todas as informações, use o método productInputs.patch.

É possível especificar quais campos você está mudando no parâmetro updateMask. O updateMask é uma lista separada por vírgulas dos campos que você quer atualizar. O método patch se comporta da seguinte maneira:

  • Campos em updateMask e corpo:esses campos são atualizados com os novos valores.
  • Campos em updateMask, mas não no corpo:esses campos são excluídos da entrada de produto.
  • Campos não incluídos em updateMask:esses campos permanecem inalterados.
  • Parâmetro updateMask omitido:todos os campos fornecidos no corpo da solicitação são atualizados. Os campos não fornecidos no corpo da solicitação não são excluídos da entrada de produto.

Confira um exemplo de dados de produtos antes de uma atualização:

{
  "name": "accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345",
  "product": "accounts/{ACCOUNT_ID}/products/en~US~SKU12345",
  "offerId": "SKU12345",
  "contentLanguage": "en",
  "feedLabel": "US",
  "productAttributes": {
    "title": "Classic Cotton T-Shirt",
    "description": "A comfortable, durable, and stylish t-shirt made from 100% cotton.",
    "link": "https://www.example.com/p/SKU12345",
    "availability": "IN_STOCK",
    "price": {
      "amountMicros": "15990000",
      "currencyCode": "USD"
    },
    "condition": "NEW",
    "gtins": [
      "9780007350896"
    ],
    "imageLink": "https://www.example.com/image/SKU12345"
  }
}

Este exemplo atualiza o title e o availability de um produto e exclui o imageLink dele. Os description e price não estão no updateMask e vão permanecer inalterados.

PATCH https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,productAttributes.availability,productAttributes.imageLink&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{
 "productAttributes": {
   "title": "Classic Cotton T-Shirt - New Edition",
   "availability": "OUT_OF_STOCK",
    "description": "A comfortable T-shirt from premium cotton, newer edition.",
    "price": {
      "amountMicros": "9990000",
      "currencyCode": "USD"
    }
 }
}

Uma chamada bem-sucedida retorna o recurso ProductInput atualizado. Os title e availability são atualizados, e o imageLink é removido porque estava no updateMask, mas não no corpo da solicitação. Os description e price permanecem inalterados porque não foram listados em updateMask.

{
  "name": "accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345",
  "product": "accounts/{ACCOUNT_ID}/products/en~US~SKU12345",
  "offerId": "SKU12345",
  "contentLanguage": "en",
  "feedLabel": "US",
  "productAttributes": {
    "title": "Classic Cotton T-Shirt - New Edition",
    "description": "A comfortable, durable, and stylish t-shirt made from 100% cotton.",
    "link": "https://www.example.com/p/SKU12345",
    "availability": "OUT_OF_STOCK",
    "price": {
      "amountMicros": "15990000",
      "currencyCode": "USD"
    },
    "condition": "NEW",
    "gtins": [
      "9780007350896"
    ],
  }
}

As amostras de código a seguir mostram como atualizar um produto.

Java

import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.protobuf.FieldMask;
import com.google.shopping.merchant.datasources.v1.DataSourceName;
import com.google.shopping.merchant.products.v1.Availability;
import com.google.shopping.merchant.products.v1.Condition;
import com.google.shopping.merchant.products.v1.ProductAttributes;
import com.google.shopping.merchant.products.v1.ProductInput;
import com.google.shopping.merchant.products.v1.ProductInputName;
import com.google.shopping.merchant.products.v1.ProductInputsServiceClient;
import com.google.shopping.merchant.products.v1.ProductInputsServiceSettings;
import com.google.shopping.merchant.products.v1.UpdateProductInputRequest;
import com.google.shopping.type.CustomAttribute;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;

/** This class demonstrates how to update a product input */
public class UpdateProductInputSample {

  public static void updateProductInput(Config config, String productId, String dataSourceId)
      throws Exception {

    // Obtains OAuth token based on the user's configuration.
    GoogleCredentials credential = new Authenticator().authenticate();

    // Creates service settings using the credentials retrieved above.
    ProductInputsServiceSettings productInputsServiceSettings =
        ProductInputsServiceSettings.newBuilder()
            .setCredentialsProvider(FixedCredentialsProvider.create(credential))
            .build();

    // Creates product name to identify product.
    String name =
        ProductInputName.newBuilder()
            .setAccount(config.getAccountId().toString())
            .setProductinput(productId)
            .build()
            .toString();

    // Just productAttributes and customAttributes can be updated
    FieldMask fieldMask =
        FieldMask.newBuilder()
            .addPaths("product_attributes.title")
            .addPaths("product_attributes.description")
            .addPaths("product_attributes.link")
            .addPaths("product_attributes.image_link")
            .addPaths("product_attributes.availability")
            .addPaths("product_attributes.condition")
            .addPaths("product_attributes.gtins")
            .addPaths("custom_attributes.mycustomattribute")
            .build();

    // Calls the API and catches and prints any network failures/errors.
    try (ProductInputsServiceClient productInputsServiceClient =
        ProductInputsServiceClient.create(productInputsServiceSettings)) {

      ProductAttributes attributes =
          ProductAttributes.newBuilder()
              .setTitle("A Tale of Two Cities")
              .setDescription("A classic novel about the French Revolution")
              .setLink("https://exampleWebsite.com/tale-of-two-cities.html")
              .setImageLink("https://exampleWebsite.com/tale-of-two-cities.jpg")
              .setAvailability(Availability.IN_STOCK)
              .setCondition(Condition.NEW)
              .addGtins("9780007350896")
              .build();

      // The datasource can be either a primary or supplemental datasource.
      String dataSource =
          DataSourceName.newBuilder()
              .setAccount(config.getAccountId().toString())
              .setDatasource(dataSourceId)
              .build()
              .toString();

      UpdateProductInputRequest request =
          UpdateProductInputRequest.newBuilder()
              .setUpdateMask(fieldMask)
              // You can only update product attributes and custom_attributes
              .setDataSource(dataSource)
              .setProductInput(
                  ProductInput.newBuilder()
                      .setName(name)
                      .setProductAttributes(attributes)
                      .addCustomAttributes(
                          CustomAttribute.newBuilder()
                              .setName("mycustomattribute")
                              .setValue("Example value")
                              .build())
                      .build())
              .build();

      System.out.println("Sending update ProductInput request");
      ProductInput response = productInputsServiceClient.updateProductInput(request);
      System.out.println("Updated ProductInput Name below");
      // The last part of the product name will be the product ID assigned to a product by Google.
      // Product ID has the format `contentLanguage~feedLabel~offerId`
      System.out.println(response.getName());
      System.out.println("Updated Product below");
      System.out.println(response);
    } catch (Exception e) {
      System.out.println(e);
    }
  }

  public static void main(String[] args) throws Exception {
    Config config = Config.load();
    // An ID assigned to a product by Google. In the format
    // contentLanguage~feedLabel~offerId
    String productId = "en~label~sku123"; // Replace with your product ID.

    // Identifies the data source that will own the product input.
    String dataSourceId = "{INSERT_DATASOURCE_ID}"; // Replace with your datasource ID.

    updateProductInput(config, productId, dataSourceId);
  }
}

PHP

use Google\ApiCore\ApiException;
use Google\Protobuf\FieldMask;
use Google\Shopping\Merchant\Products\V1\Availability;
use Google\Shopping\Merchant\Products\V1\Condition;
use Google\Shopping\Merchant\Products\V1\ProductAttributes;
use Google\Shopping\Merchant\Products\V1\Client\ProductInputsServiceClient;
use Google\Shopping\Merchant\Products\V1\ProductInput;
use Google\Shopping\Merchant\Products\V1\UpdateProductInputRequest;
use Google\Shopping\Type\CustomAttribute;

/**
 * This class demonstrates how to update a product input.
 */
class UpdateProductInputSample
{
    // An ID assigned to a product by Google. In the format
    // contentLanguage~feedLabel~offerId
    // Please ensure this product ID exists for the update to succeed.
    private const PRODUCT_ID = "online~en~label~sku123";

    // Identifies the data source that will own the product input.
    // Please ensure this data source ID exists.
    private const DATASOURCE_ID = "<INSERT_DATASOURCE_ID>";

    /**
     * Helper function to construct the full product input resource name.
     *
     * @param string $accountId The merchant account ID.
     * @param string $productInputId The product input ID (e.g., "online~en~label~sku123").
     * @return string The full product input resource name.
     */
    private static function getProductInputName(string $accountId, string $productInputId): string
    {
        return sprintf("accounts/%s/productInputs/%s", $accountId, $productInputId);
    }

    /**
     * Helper function to construct the full data source resource name.
     *
     * @param string $accountId The merchant account ID.
     * @param string $dataSourceId The data source ID.
     * @return string The full data source resource name.
     */
    private static function getDataSourceName(string $accountId, string $dataSourceId): string
    {
        return sprintf("accounts/%s/dataSources/%s", $accountId, $dataSourceId);
    }

    /**
     * Updates an existing product input in your Merchant Center account.
     *
     * @param array $config The configuration array containing the account ID.
     * @param string $productId The ID of the product input to update.
     * @param string $dataSourceId The ID of the data source.
     */
    public static function updateProductInput(
        array $config,
        string $productId,
        string $dataSourceId
    ): void {
        // Gets the OAuth credentials to make the request.
        $credentials = Authentication::useServiceAccountOrTokenFile();

        // Creates options config containing credentials for the client to use.
        $options = ['credentials' => $credentials];

        // Creates a ProductInputsServiceClient.
        $productInputsServiceClient = new ProductInputsServiceClient($options);

        // Construct the full resource name of the product input to be updated.
        $name = self::getProductInputName($config['accountId'], $productId);

        // Define the FieldMask to specify which fields to update.
        // Only 'attributes' and 'custom_attributes' can be specified in the
        // FieldMask for product input updates.
        $fieldMask = new FieldMask([
            'paths' => [
                "product_attributes.title",
                "product_attributes.description",
                "product_attributes.link",
                "product_attributes.image_link",
                "product_attributes.availability",
                "product_attributes.condition",
                "product_attributes.gtin",
                "custom_attributes.mycustomattribute" // Path for a specific custom attribute
            ]
        ]);

        // Calls the API and handles any network failures or errors.
        try {
            // Define the new attributes for the product.
            $attributes = new ProductAttributes([
                'title' => 'A Tale of Two Cities 3',
                'description' => 'A classic novel about the French Revolution',
                'link' => 'https://exampleWebsite.com/tale-of-two-cities.html',
                'image_link' => 'https://exampleWebsite.com/tale-of-two-cities.jpg',
                'availability' => Availability::IN_STOCK,
                'condition' => Condition::PBNEW,
                'gtins' => ['9780007350896'] // GTIN is a repeated field.
            ]);

            // Construct the full data source name.
            // This specifies the data source context for the update.
            $dataSource = self::getDataSourceName($config['accountId'], $dataSourceId);

            // Create the ProductInput object with the desired updates.
            // The 'name' field must match the product input being updated.
            $productInput = new ProductInput([
                'name' => $name,
                'product_attributes' => $attributes,
                'custom_attributes' => [ // Provide the list of custom attributes.
                    new CustomAttribute([
                        'name' => 'mycustomattribute',
                        'value' => 'Example value'
                    ])
                ]
            ]);

            // Create the UpdateProductInputRequest.
            $request = new UpdateProductInputRequest([
                'update_mask' => $fieldMask,
                'data_source' => $dataSource,
                'product_input' => $productInput
            ]);

            print "Sending update ProductInput request\n";
            // Make the API call to update the product input.
            $response = $productInputsServiceClient->updateProductInput($request);

            print "Updated ProductInput Name below\n";
            // The name of the updated product input.
            // The last part of the product name is the product ID (e.g., contentLanguage~feedLabel~offerId).
            print $response->getName() . "\n";
            print "Updated Product below\n";
            // Print the full updated product input object.
            print_r($response);

        } catch (ApiException $e) {
            printf("ApiException caught: %s\n", $e->getMessage());
        }
    }

    /**
     * Executes the UpdateProductInput sample.
     */
    public function callSample(): void
    {
        $config = Config::generateConfig();
        $productId = self::PRODUCT_ID;
        $dataSourceId = self::DATASOURCE_ID;

        self::updateProductInput($config, $productId, $dataSourceId);
    }
}

// Run the script.
$sample = new UpdateProductInputSample();
$sample->callSample();

Python

"""A module to update a product input."""

from examples.authentication import configuration
from examples.authentication import generate_user_credentials
from google.protobuf import field_mask_pb2
from google.shopping.merchant_products_v1 import Availability
from google.shopping.merchant_products_v1 import Condition
from google.shopping.merchant_products_v1 import ProductAttributes
from google.shopping.merchant_products_v1 import ProductInput
from google.shopping.merchant_products_v1 import ProductInputsServiceClient
from google.shopping.merchant_products_v1 import UpdateProductInputRequest
from google.shopping.type import CustomAttribute


# Fetches the Merchant Center account ID from the authentication examples.
# This ID is needed to construct resource names for the API.
_ACCOUNT_ID = configuration.Configuration().read_merchant_info()


def update_product_input(account_id: str, product_id: str, data_source_id: str):
  """Updates an existing product input for a specific account.

  Args:
    account_id: The Merchant Center account ID.
    product_id: The ID of the product input to update. This ID is assigned by
      Google and has the format `contentLanguage~feedLabel~offerId`.
    data_source_id: The ID of the data source that owns the product input.
  """

  # Obtains OAuth credentials for authentication.
  credentials = generate_user_credentials.main()

  # Creates a ProductInputsServiceClient instance.
  client = ProductInputsServiceClient(credentials=credentials)

  # Constructs the full resource name for the product input.
  # Format: accounts/{account}/productInputs/{productinput}
  name = f"accounts/{account_id}/productInputs/{product_id}"

  # Defines the FieldMask to specify which fields of the product input
  # are being updated. Only 'attributes' and 'custom_attributes' can be updated.
  field_mask = field_mask_pb2.FieldMask(
      paths=[
          "product_attributes.title",
          "product_attributes.description",
          "product_attributes.link",
          "product_attributes.image_link",
          "product_attributes.availability",
          "product_attributes.condition",
          "product_attributes.gtins",
          "custom_attributes.mycustomattribute",
      ]
  )

  # Prepares the new attribute values for the product.
  attributes = ProductAttributes(
      title="A Tale of Two Cities updated",
      description="A classic novel about the French Revolution",
      link="https://exampleWebsite.com/tale-of-two-cities.html",
      image_link="https://exampleWebsite.com/tale-of-two-cities.jpg",
      availability=Availability.IN_STOCK,
      condition=Condition.NEW,
      gtins=["9780007350896"],  # GTIN is a repeated field.
  )

  # Constructs the full resource name for the data source.
  # The data source can be primary or supplemental.
  # Format: accounts/{account}/dataSources/{datasource}
  data_source = f"accounts/{account_id}/dataSources/{data_source_id}"

  # Prepares the ProductInput object with the updated information.
  product_input_data = ProductInput(
      name=name,
      product_attributes=attributes,
      custom_attributes=[
          CustomAttribute(
              name="mycustomattribute", value="Example value"
          )
      ],
  )

  # Creates the UpdateProductInputRequest.
  request = UpdateProductInputRequest(
      update_mask=field_mask,
      data_source=data_source,
      product_input=product_input_data,
  )

  # Sends the update request to the API.
  try:
    print("Sending update ProductInput request")
    response = client.update_product_input(request=request)
    print("Updated ProductInput Name below")
    # The response includes the name of the updated product input.
    # The last part of the product name is the product ID assigned by Google.
    print(response.name)
    print("Updated Product below")
    print(response)
  except RuntimeError as e:
    # Catches and prints any errors that occur during the API call.
    print(e)


if __name__ == "__main__":
  # The ID of the product to be updated.
  # This ID is assigned by Google and typically follows the format:
  # contentLanguage~feedLabel~offerId
  # Replace with an actual product ID from your Merchant Center account.
  product_id_to_update = "online~en~label~sku123"

  # The ID of the data source that will own the updated product input.
  # Replace with an actual data source ID from your Merchant Center account.
  data_source_id_for_update = "<INSERT_DATA_SOURCE_ID>"

  update_product_input(
      _ACCOUNT_ID, product_id_to_update, data_source_id_for_update
  )

cURL

curl --location --request PATCH 'https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,productAttributes.description&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}' \
--header 'Authorization: Bearer <API_TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
   "productAttributes": {
       "title": "A Tale of Two Cities",
       "description": "A classic novel about the French Revolution"
   }
}'

Atualizar usando atributos personalizados

É possível atualizar atributos padrão e personalizados em uma única chamada. Para atualizar um atributo personalizado, adicione o prefixo customAttributes ao nome dele em updateMask.

Este exemplo executa várias ações em uma única solicitação:

  • Atualiza diretamente o atributo padrão title.
  • Atualiza um atributo personalizado (myCustomAttrToBeUpdated).
  • Insere um novo atributo personalizado (myCustomAttrToBeInserted).
  • Exclui um atributo personalizado (myCustomAttrToBeDeleted).
PATCH https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,customAttributes.myCustomAttrToBeInserted,customAttributes.myCustomAttrToBeUpdated,customAttributes.myCustomAttrToBeDeleted&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{
  "productAttributes": {
    "title": "ProductTitle Updated"
  },
  "customAttributes": [
    {
      "name": "description",
      "value": "A newly updated description."
    },
    {
      "name": "myCustomAttrToBeUpdated",
      "value": "myCustomAttrToBeUpdated updated value"
    },
    {
      "name": "myCustomAttrToBeInserted",
      "value": "new from update"
    }
  ]
}

Uma solicitação bem-sucedida retorna o ProductInput atualizado, refletindo todas as mudanças especificadas.

Entender as atualizações de atributos personalizados

Use o campo customAttributes para atualizar atributos que você definiu. Eles não são mapeados para a especificação padrão e serão armazenados como atributos personalizados no produto final.

Como as atualizações de produtos são processadas

Quando você envia uma solicitação patch, a atualização é aplicada aos dados ProductInput específicos antes de qualquer regra ser aplicada. Isso resulta em comportamento consistente entre a inserção e a atualização de produtos.

Veja como sua atualização é processada:

  1. Atualizar entrada:sua solicitação patch modifica o ProductInput específico associado à fonte de dados fornecida.

  2. Processamento e fusão:depois que a entrada é atualizada, o processamento começa:

    • Regras de feed e fontes de dados complementares:as regras configuradas na fonte principal do produto combinam o ProductInput das fontes principal e complementar. Essas regras podem mudar atributos ou derivar novos. Para saber mais sobre como configurar as regras, consulte o artigo https://support.google.com/merchants/answer/14994083.
    • Outras fontes de dados:dados de outras fontes (por exemplo, melhorias automáticas) também são mesclados com a entrada da fonte de dados principal.
    • Validação:os dados combinados são validados de acordo com a especificação de dados de produtos e as políticas de compras do Google.
  3. Produto final:o resultado desse pipeline é o recurso Product final e processado que pode ser retornado usando products.get ou products.list. Essa também é a versão do produto que aparece no Merchant Center e está qualificada para aparecer em diferentes destinos.

Devido a esse processo de várias etapas, há um atraso, geralmente de alguns minutos, entre o envio de uma solicitação de atualização e a inclusão das mudanças no recurso Product final, que pode ser recuperado com products.get.

Exemplo: atualizar um produto com uma única entrada principal

Esse é o caso de uso mais comum. Um produto existe em uma única fonte de dados principal, e você quer atualizar alguns dos atributos dele.

  1. Estado inicial:um produto en~US~SKU12345 existe na sua fonte de dados principal com title: "Classic T-Shirt" e price: 15.99 USD.
  2. Solicitação de atualização:você envia uma solicitação patch para atualizar price para 14.99 USD e define availability como out of stock.
  3. Processamento:
    • O ProductInput de SKU12345 foi atualizado.
  4. Produto final:o Product final agora tem title: "Classic T-Shirt", price: 14.99 USD e availability: "out of stock".

Exemplo: atualizar um produto com dados e regras complementares

Este exemplo mostra como as regras de feed podem afetar uma atualização, fazendo com que algumas mudanças sejam aplicadas enquanto outras são substituídas.

  1. Estado inicial:
    • Entrada principal:en~US~SKU12345 tem title: "Great T-Shirt" e description: "A great short-sleeve t-shirt.".
    • Entrada complementar:o mesmo produto tem uma entrada em uma fonte de dados complementar com title: "Awesome T-Shirt" e description: "An awesome short-sleeve t-shirt.".
    • Regra de feed:uma regra é definida para usar o title da fonte de dados complementar. Não há uma regra para description.
    • Resultado:o Product final processado tem title: "Awesome T-Shirt" e description: "A great short-sleeve t-shirt.".
  2. Solicitação de atualização:você envia uma solicitação patch para atualizar a fonte de dados principal, definindo title como "Fantastic T-Shirt" e description como "A fantastic short-sleeve t-shirt.".
  3. Processamento:
    • O ProductInput na fonte de dados principal é atualizado para ter title: "Fantastic T-Shirt" e description: "A fantastic short-sleeve t-shirt.".
    • O pipeline de processamento é executado.
    • Para o title, a regra do feed determina que o valor da fonte de dados complementar (Awesome T-Shirt) tem precedência, substituindo sua atualização.
    • Para o description, como não há uma regra de substituição, o valor atualizado da entrada principal (A fantastic short-sleeve t-shirt.) é usado.
  4. Produto final:o título final do Product continua Awesome T-Shirt (sua atualização foi substituída), mas a descrição agora é A fantastic short-sleeve t-shirt. (sua atualização foi aplicada).

Escolher entre atualizações e fontes de dados complementares

É possível modificar os dados de produtos usando productinputs.patch ou inserindo dados em fontes complementares. A melhor opção depende da sua estratégia de gerenciamento de dados.

Para evitar resultados imprevisíveis, recomendamos que você não use productinputs.patch e fontes de dados complementares para gerenciar os mesmos dados de produtos para o mesmo item.

Confira uma comparação detalhada:

Recurso productinputs.patch (atualizações) Fontes de dados complementares
Ideal para Mudanças rápidas, frequentes e parciais nos dados atuais (por exemplo, preço, disponibilidade). Camadas de dados logicamente separados, gerenciamento de diferentes atributos por sistemas diferentes ou substituições complexas baseadas em regras.
Mecanismo Modifica um ProductInput existente no local. Cria um novo ProductInput separado em uma fonte de dados complementar.
Granularidade dos dados Opera em campos específicos de um único ProductInput. Opera em todo o ProductInput na fonte complementar.
Persistência As mudanças persistem até que o mesmo ProductInput seja substituído por um insert completo ou outro patch. A persistência é controlada pelas regras de feed. Pode substituir os dados principais por tempo indeterminado se as regras priorizarem isso.
Interação de regras Pode ser usado sem as regras do feed, já que atualiza uma fonte de dados e um ProductInput. É necessário configurar explicitamente uma regra na fonte principal para vincular a fonte complementar.
Configuração da fonte de dados Opera em uma fonte de dados atual. Não é necessário adicionar novas fontes. É necessário criar e gerenciar fontes de dados complementares separadas e vinculá-las usando regras de feed.