// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.shopping.merchant.products.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/shopping/merchant/products/v1/products_common.proto";
import "google/shopping/type/types.proto";

option csharp_namespace = "Google.Shopping.Merchant.Products.V1";
option go_package = "cloud.google.com/go/shopping/merchant/products/apiv1/productspb;productspb";
option java_multiple_files = true;
option java_outer_classname = "ProductInputsProto";
option java_package = "com.google.shopping.merchant.products.v1";
option php_namespace = "Google\\Shopping\\Merchant\\Products\\V1";
option ruby_package = "Google::Shopping::Merchant::Products::V1";

// Service to use ProductInput resource.
service ProductInputsService {
  option (google.api.default_host) = "merchantapi.googleapis.com";
  option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/content";

  // [Uploads a product input to your Merchant Center
  // account](/merchant/api/guides/products/add-manage#add_a_product). You
  // must have a products [data
  // source](/merchant/api/guides/data-sources/api-sources#create-primary-data-source)
  // to be able to insert a product. The unique identifier of the data source is
  // passed as a query parameter in the request URL.
  //
  // If a product input with the same contentLanguage, offerId, and dataSource
  // already exists, then the product input inserted by this method replaces
  // that entry.
  //
  // After inserting, updating, or deleting a product input, it may take several
  // minutes before the processed product can be retrieved.
  rpc InsertProductInput(InsertProductInputRequest) returns (ProductInput) {
    option (google.api.http) = {
      post: "/products/v1/{parent=accounts/*}/productInputs:insert"
      body: "product_input"
    };
  }

  // Updates the existing product input in your Merchant Center account.
  // The name of the product input to update is taken from the `name` field
  // within the `ProductInput` resource.
  //
  // After inserting, updating, or deleting a product input, it may take several
  // minutes before the processed product can be retrieved.
  rpc UpdateProductInput(UpdateProductInputRequest) returns (ProductInput) {
    option (google.api.http) = {
      patch: "/products/v1/{product_input.name=accounts/*/productInputs/*}"
      body: "product_input"
    };
    option (google.api.method_signature) = "product_input,update_mask";
  }

  // Deletes a product input from your Merchant Center account.
  //
  // After inserting, updating, or deleting a product input, it may take several
  // minutes before the processed product can be retrieved.
  rpc DeleteProductInput(DeleteProductInputRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/products/v1/{name=accounts/*/productInputs/*}"
    };
    option (google.api.method_signature) = "name";
  }
}

// This resource represents input data you submit for a product, not the
//  processed product that you see in Merchant Center, in Shopping ads, or
//  across Google surfaces. Product inputs, rules and supplemental data source
//  data are combined to create the processed
//  [Product][google.shopping.merchant.products.v1.Product]. For more
//  information, see [Manage products](/merchant/api/guides/products/overview).
//
//  Required product input attributes to pass data validation checks are
//  primarily defined in the [Products Data
//  Specification](https://support.google.com/merchants/answer/188494).
//
//  The following attributes are required:
//  [feedLabel][google.shopping.merchant.products.v1.Product.feed_label],
//  [contentLanguage][google.shopping.merchant.products.v1.Product.content_language]
//  and [offerId][google.shopping.merchant.products.v1.Product.offer_id].
//
//  After inserting, updating, or deleting a product input, it may take several
//  minutes before the processed product can be retrieved.
//
//  All fields in the product input and its sub-messages match the English name
//  of their corresponding attribute in the [Products Data
//  Specification](https://support.google.com/merchants/answer/188494) with
//  [some exceptions](https://support.google.com/merchants/answer/7052112).
//  The following reference documentation lists the field names in the
//  **camelCase** casing style while the Products Data Specification lists the
//  names in the **snake_case** casing style.
message ProductInput {
  option (google.api.resource) = {
    type: "merchantapi.googleapis.com/ProductInput"
    pattern: "accounts/{account}/productInputs/{productinput}"
    plural: "productInputs"
    singular: "productInput"
  };

  // Identifier. The name of the product.
  // Format: `accounts/{account}/productInputs/{productinput}`
  //
  // The {productinput} segment is a unique identifier for the product.
  // This identifier must be unique within a merchant account and generally
  // follows the structure: `content_language~feed_label~offer_id`. Example:
  // `en~US~sku123` For legacy local products, the structure is:
  // `local~content_language~feed_label~offer_id`. Example: `local~en~US~sku123`
  //
  // The format of the {productinput} segment in the URL is automatically
  // detected by the server, supporting two options:
  //
  // 1.  **Encoded Format**: The `{productinput}` segment is an unpadded
  // base64url
  //     encoded string (RFC 4648 Section 5). The decoded string must result
  //     in the `content_language~feed_label~offer_id` structure. This encoding
  //     MUST be used if any part of the product identifier (like `offer_id`)
  //     contains characters such as `/`, `%`, or `~`.
  //     *   Example: To represent the product ID `en~US~sku/123`, the
  //         `{productinput}` segment must be the unpadded base64url encoding of
  //         this string, which is `ZW5-VVN-c2t1LzEyMw`. The full resource name
  //         for the product would be
  //         `accounts/123/productInputs/ZW5-VVN-c2t1LzEyMw`.
  //
  // 2.  **Plain Format**: The `{productinput}` segment is the tilde-separated
  // string
  //     `content_language~feed_label~offer_id`. This format is suitable only
  //     when `content_language`, `feed_label`, and `offer_id` do not contain
  //     URL-problematic characters like `/`, `%`, or `~`.
  //
  // We recommend using the **Encoded Format** for all product IDs to ensure
  // correct parsing, especially those containing special characters. The
  // presence of tilde (`~`) characters in the `{productinput}` segment is used
  // to differentiate between the two formats.
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. The **unpadded base64url encoded name** of the product input.
  // Format:
  // `accounts/{account}/productInputs/{productinput}` where the last
  // section `productinput` is the unpadded base64url encoding of the
  // `content_language~feed_label~offer_id` name.
  // Example: `accounts/123/productInputs/ZW5-VVN-c2t1LzEyMw` for the decoded
  // product input name `accounts/123/productInputs/en~US~sku/123`. This field
  // can be used directly as input to the API methods that require the product
  // input name to be encoded if it contains special characters, for example
  // [`GetProductInput`](https://developers.google.com/merchant/api/reference/rest/products_v1/accounts.productInputs/get).
  string base64_encoded_name = 12 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The name of the processed product.
  // Format: `accounts/{account}/products/{product}`
  string product = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The **unpadded base64url encoded name** of the processed
  // product. Format: `accounts/{account}/products/{product}` where the last
  // section `product` is the unpadded base64url encoding of the
  // `content_language~feed_label~offer_id` name.
  // Example: `accounts/123/products/ZW5-VVN-c2t1LzEyMw` for the decoded
  // product name `accounts/123/products/en~US~sku/123`. This field can be used
  // directly as input to the API methods that require the product name to be
  // encoded if it contains special characters, for example
  // [`GetProduct`](https://developers.google.com/merchant/api/reference/rest/products_v1/accounts.products/get).
  string base64_encoded_product = 13
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Immutable. Determines whether the product is **only** targeting
  // local destinations and whether the product name should be distinguished
  // with a `local~` prefix. For example,
  // `accounts/123/productInputs/local~en~US~sku123`. If a product that is not
  // `legacy_local` is already targeting local destinations,
  // creating a `legacy_local` product with an otherwise matching name will
  // fail.
  bool legacy_local = 10 [(google.api.field_behavior) = IMMUTABLE];

  // Required. Immutable. Your unique identifier for the product. This is the
  // same for the product input and processed product. Leading and trailing
  // whitespaces are stripped and multiple whitespaces are replaced by a single
  // whitespace upon submission. See the [products data
  // specification](https://support.google.com/merchants/answer/188494#id) for
  // details.
  string offer_id = 4 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.field_behavior) = IMMUTABLE
  ];

  // Required. Immutable. The two-letter [ISO
  // 639-1](http://en.wikipedia.org/wiki/ISO_639-1) language code for the
  // product.
  string content_language = 5 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.field_behavior) = IMMUTABLE
  ];

  // Required. Immutable. The feed label that lets you categorize and identify
  // your products. The maximum allowed characters are 20, and the supported
  // characters are `A-Z`, `0-9`, hyphen, and underscore. The feed label must
  // not include any spaces. For more information, see [Using feed
  // labels](//support.google.com/merchants/answer/14994087).
  string feed_label = 6 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.field_behavior) = IMMUTABLE
  ];

  // Optional. Immutable. Represents the existing version (freshness) of the
  // product, which can be used to preserve the right order when multiple
  // updates are done at the same time.
  //
  // If set, the insertion is prevented when version number is lower than
  // the current version number of the existing product. Re-insertion (for
  // example, product refresh after 30 days) can be performed with the current
  // `version_number`.
  //
  // Only supported for insertions into primary data sources.
  // Do not set this field for updates.
  // Do not set this field for insertions into supplemental data sources.
  //
  // If the operation is prevented, the aborted exception will be
  // thrown.
  optional int64 version_number = 7 [
    (google.api.field_behavior) = OPTIONAL,
    (google.api.field_behavior) = IMMUTABLE
  ];

  // Optional. A list of strongly-typed product attributes.
  ProductAttributes product_attributes = 11
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. A list of custom (merchant-provided) attributes. It can also be
  // used for submitting any attribute of the data specification in its generic
  // form (for example,
  // `{ "name": "size type", "value": "regular" }`).
  // This is useful for submitting attributes not explicitly exposed by the
  // API.
  // Maximum allowed number of characters for each
  // custom attribute is 10240 (represents sum of characters for name and
  // value). Maximum 2500 custom attributes can be set per product, with total
  // size of 102.4kB. Underscores in custom attribute names are replaced by
  // spaces upon insertion.
  repeated google.shopping.type.CustomAttribute custom_attributes = 9
      [(google.api.field_behavior) = OPTIONAL];
}

// Request message for the InsertProductInput method.
message InsertProductInputRequest {
  // Required. The account where this product will be inserted.
  // Format: `accounts/{account}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "merchantapi.googleapis.com/Product"
    }
  ];

  // Required. The product input to insert.
  ProductInput product_input = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The primary or supplemental product data source name. If the
  // product already exists and data source provided is different, then the
  // product will be moved to a new data source. For more information, see
  // [Create a primary data
  // source](/merchant/api/guides/data-sources/api-sources#create-primary-data-source).
  //
  // Only API data sources are supported.
  //
  // Format: `accounts/{account}/dataSources/{datasource}`. For example,
  // `accounts/123456/dataSources/104628`.
  string data_source = 3 [(google.api.field_behavior) = REQUIRED];
}

// Request message for the UpdateProductInput method.
// The product (primary input) must exist for the update to succeed.
// If the update is for a primary product input, the existing primary product
// input must be from the same data source.
message UpdateProductInputRequest {
  // Required. The product input resource to update. Information you submit will
  // be applied to the processed product as well. The `name` field within this
  // resource identifies the product input to be updated.
  ProductInput product_input = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The list of product attributes to be updated.
  //
  // If the update mask is omitted, then it is treated as implied field mask
  // equivalent to all fields that are populated (have a non-empty value).
  //
  // Attributes specified in the update mask without a value specified in the
  // body will be deleted from the product.
  //
  // Update mask can only be specified for top level fields in
  // attributes and custom attributes.
  //
  // To specify the update mask for custom attributes you need to add the
  // `custom_attribute.` prefix.
  //
  // Providing special "*" value for full product replacement is not supported.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = OPTIONAL];

  // Required. The primary or supplemental product data source where
  // `data_source` name identifies the product input to be updated.
  //
  // Only API data sources are supported.
  //
  // Format: `accounts/{account}/dataSources/{datasource}`. For example,
  // `accounts/123456/dataSources/104628`.
  string data_source = 3 [(google.api.field_behavior) = REQUIRED];
}

// Request message for the DeleteProductInput method.
message DeleteProductInputRequest {
  // Required. The name of the product input to delete.
  // Format: `accounts/{account}/productInputs/{productInput}`
  //
  // The {productInput} segment is a unique identifier for the product.
  // This identifier must be unique within a merchant account and generally
  // follows the structure: `content_language~feed_label~offer_id`. Example:
  // `en~US~sku123` For legacy local products, the structure is:
  // `local~content_language~feed_label~offer_id`. Example: `local~en~US~sku123`
  //
  // The format of the {productInput} segment in the URL is automatically
  // detected by the server, supporting two options:
  //
  // 1.  **Encoded Format**: The `{productInput}` segment is an unpadded
  // base64url
  //     encoded string (RFC 4648 Section 5). The decoded string must result
  //     in the `content_language~feed_label~offer_id` structure. This encoding
  //     MUST be used if any part of the product identifier (like `offer_id`)
  //     contains characters such as `/`, `%`, or `~`.
  //     *   Example: To represent the product ID `en~US~sku/123`, the
  //         `{productInput}` segment must be the unpadded base64url encoding of
  //         this string, which is `ZW5-VVN-c2t1LzEyMw`. The full resource name
  //         for the product would be
  //         `accounts/123/productInputs/ZW5-VVN-c2t1LzEyMw`.
  //
  // 2.  **Plain Format**: The `{productInput}` segment is the tilde-separated
  // string
  //     `content_language~feed_label~offer_id`. This format is suitable only
  //     when `content_language`, `feed_label`, and `offer_id` do not contain
  //     URL-problematic characters like `/`, `%`, or `~`.
  //
  // We recommend using the **Encoded Format** for all product IDs to ensure
  // correct parsing, especially those containing special characters. The
  // presence of tilde (`~`) characters in the `{productInput}` segment is used
  // to differentiate between the two formats.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "merchantapi.googleapis.com/ProductInput"
    }
  ];

  // Required. The primary or supplemental data source from which the product
  // input should be deleted. Format:
  // `accounts/{account}/dataSources/{datasource}`. For example,
  // `accounts/123456/dataSources/104628`.
  string data_source = 2 [(google.api.field_behavior) = REQUIRED];
}
