Merchant API code sample to insert merchant reviews asynchronously.

### Java

    // Copyright 2025 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
    //
    //     https://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.

    package shopping.merchant.samples.reviews.v1alpha;

    import com.google.api.core.ApiFuture;
    import com.google.api.core.ApiFutureCallback;
    import com.google.api.core.ApiFutures;
    import com.google.api.gax.core.FixedCredentialsProvider;
    import com.google.auth.oauth2.GoogleCredentials;
    import com.google.common.util.concurrent.MoreExecutors;
    import com.google.protobuf.Timestamp;
    import com.google.shopping.merchant.reviews.v1alpha.InsertMerchantReviewRequest;
    import com.google.shopping.merchant.reviews.v1alpha.MerchantReview;
    import com.google.shopping.merchant.reviews.v1alpha.MerchantReviewAttributes;
    import com.google.shopping.merchant.reviews.v1alpha.MerchantReviewsServiceClient;
    import com.google.shopping.merchant.reviews.v1alpha.MerchantReviewsServiceSettings;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import java.util.stream.Collectors;
    import shopping.merchant.samples.utils.Authenticator;
    import shopping.merchant.samples.utils.Config;

    /** This class demonstrates how to insert multiple merchant reviews asynchronously. */
    public class InsertMerchantReviewsAsyncSample {

      private static String generateRandomString() {
        String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder(8);
        for (int i = 0; i < 8; i++) {
          sb.append(characters.charAt(random.nextInt(characters.length())));
        }
        return sb.toString();
      }

      // Returns a merchant review with a random ID.
      private static MerchantReview createMerchantReview(String accountId) {
        String merchantReviewId = generateRandomString();

        MerchantReviewAttributes attributes =
            MerchantReviewAttributes.newBuilder()
                .setTitle("Great Merchant!")
                .setContent("Would buy there again.")
                .setMinRating(1)
                .setMaxRating(5)
                .setRating(4)
                .setReviewTime(Timestamp.newBuilder().setSeconds(1731165684).build())
                .setReviewLanguage("en-US")
                .build();

        return MerchantReview.newBuilder()
            .setMerchantReviewId(merchantReviewId)
            .setMerchantReviewAttributes(attributes)
            .build();
      }

      public static void asyncInsertMerchantReviews(String accountId, String dataSourceId)
          throws Exception {
        GoogleCredentials credential = new Authenticator().authenticate();

        MerchantReviewsServiceSettings merchantReviewsServiceSettings =
            MerchantReviewsServiceSettings.newBuilder()
                .setCredentialsProvider(FixedCredentialsProvider.create(credential))
                .build();

        try (MerchantReviewsServiceClient merchantReviewsServiceClient =
            MerchantReviewsServiceClient.create(merchantReviewsServiceSettings)) {

          // Arbitrarily creates five merchant reviews with random IDs.
          List<InsertMerchantReviewRequest> requests = new ArrayList<>();
          for (int i = 0; i < 5; i++) {
            InsertMerchantReviewRequest request =
                InsertMerchantReviewRequest.newBuilder()
                    .setParent(String.format("accounts/%s", accountId))
                    .setMerchantReview(createMerchantReview(accountId))
                    // Must be a merchant reviews data source. In other words, a data source whose
                    // "type"
                    // is MerchantReviewDataSource.
                    .setDataSource(String.format("accounts/%s/dataSources/%s", accountId, dataSourceId))
                    .build();
            requests.add(request);
          }

          // Inserts the merchant reviews.
          List<ApiFuture<MerchantReview>> futures =
              requests.stream()
                  .map(
                      request ->
                          merchantReviewsServiceClient
                              .insertMerchantReviewCallable()
                              .futureCall(request))
                  .collect(Collectors.toList());

          // Creates callback to handle the responses when all are ready.
          ApiFuture<List<MerchantReview>> responses = ApiFutures.allAsList(futures);
          ApiFutures.addCallback(
              responses,
              new ApiFutureCallback<List<MerchantReview>>() {
                @Override
                public void onSuccess(List<MerchantReview> results) {
                  System.out.println("Inserted merchant reviews below:");
                  System.out.println(results);
                }

                @Override
                public void onFailure(Throwable throwable) {
                  System.out.println(throwable);
                }
              },
              MoreExecutors.directExecutor());
        } catch (Exception e) {
          System.out.println(e);
        }
      }

      public static void main(String[] args) throws Exception {
        Config config = Config.load();
        asyncInsertMerchantReviews(config.getAccountId().toString(), "YOUR_DATA_SOURCE_ID");
      }
    }

### PHP

    <?php
    /**
     * Copyright 2025 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
     *
     *     https://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.
     */

    require_once __DIR__ . '/../../../vendor/autoload.php';
    require_once __DIR__ . '/../../Authentication/Authentication.php';
    require_once __DIR__ . '/../../Authentication/Config.php';
    use GuzzleHttp\Promise\Utils;
    use Google\Protobuf\Timestamp;
    use Google\Shopping\Merchant\Reviews\V1alpha\Client\MerchantReviewsServiceClient;
    use Google\Shopping\Merchant\Reviews\V1alpha\InsertMerchantReviewRequest;
    use Google\Shopping\Merchant\Reviews\V1alpha\MerchantReview;
    use Google\Shopping\Merchant\Reviews\V1alpha\MerchantReviewAttributes;

    /**
     * This class demonstrates how to insert multiple merchant reviews asynchronously.
     */
    class InsertMerchantReviewsAsyncSample
    {
        private const DATA_SOURCE_ID = '<DATA_SOURCE_ID>';

        /**
         * Generates a random string of 8 alphanumeric characters.
         * @return string A random string.
         */
        private static function generateRandomString(): string
        {
            $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            $randomString = '';
            $length = 8;
            for ($i = 0; $i < $length; $i++) {
                $randomString .= $characters[random_int(0, strlen($characters) - 1)];
            }
            return $randomString;
        }

        /**
         * Creates a sample MerchantReview object with a random ID.
         * @return MerchantReview A sample MerchantReview object.
         */
        private static function createMerchantReview(): MerchantReview
        {
            $merchantReviewId = self::generateRandomString();

            $attributes = (new MerchantReviewAttributes())
                ->setTitle('Great Merchant!')
                ->setContent('Would buy there again.')
                ->setMinRating(1)
                ->setMaxRating(5)
                ->setRating(4)
                ->setReviewTime(new Timestamp(['seconds' => 1731165684]))
                ->setReviewLanguage('en-US');

            return (new MerchantReview())
                ->setMerchantReviewId($merchantReviewId)
                ->setAttributes($attributes);
        }

        /**
         * Inserts multiple merchant reviews into your Merchant Center account asynchronously.
         *
         * @param array $config The configuration data for authentication and account ID.
         * @param string $dataSourceId The ID of the data source for the reviews.
         */
        public static function asyncInsertMerchantReviewsSample(array $config, 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 client.
            $merchantReviewsServiceClient = new MerchantReviewsServiceClient($options);

            $parent = sprintf('accounts/%s', $config['accountId']);
            $dataSource = sprintf('accounts/%s/dataSources/%s', $config['accountId'], $dataSourceId);

            $insertedReviews = [];
            $errors = [];
            $promises = [];
            // Inserts 5 merchant reviews
            for ($i = 0; $i < 5; $i++) {
                try {
                    $merchantReview = self::createMerchantReview();
                    $merchantReviewId = $merchantReview->getMerchantReviewId();
                    $request = (new InsertMerchantReviewRequest())
                        ->setParent($parent)
                        ->setMerchantReview($merchantReview)
                        ->setDataSource($dataSource);

                    printf("Dispatching insert request for Merchant Review ID: %s%s", $merchantReviewId, PHP_EOL);

                    // Store the promise, keyed by a unique identifier for this review
                    // This helps match responses/errors back to the original request.
                    $promises[$merchantReviewId] = $merchantReviewsServiceClient->insertMerchantReviewAsync($request);

                } catch (Exception $e) {
                    printf(
                        "Error preparing/dispatching merchant reviews %s",
                        $e->getMessage(),
                        PHP_EOL
                    );
                }
            }

            if (empty($promises)) {
                echo "No review insert requests were dispatched." . PHP_EOL;
            } else {
                echo "All review insert requests dispatched. Waiting for responses..." . PHP_EOL;

                // Wait for all the promises to settle (either fulfilled or rejected)
                // Utils::settle() returns an array of results, each with 'state' and 'value' or 'reason'
                $results = Utils::settle($promises)->wait();

                $insertedReviewsResponses = [];
                $errors = [];

                foreach ($results as $merchantReviewId => $result) {

                    if ($result['state'] === 'fulfilled') {
                        $response = $result['value']; // This is the actual response object from the API
                        printf("Successfully inserted merchant review ID: %s%s", $merchantReviewId, PHP_EOL);
                        $insertedReviewsResponses[] = $response;
                    } elseif ($result['state'] === 'rejected') {
                        $reason = $result['reason']; // This is the exception object
                        printf(
                            "Error inserting merchant review Id: %s. %s",
                            $merchantReviewId,
                            $reason->getMessage(),
                            PHP_EOL
                        );
                        $errors[] = ['reviewId' => $merchantReviewId, 'reason' => $reason];
                    }
                }

                // Now $insertedReviewsResponses contains actual successful response objects
                // And $errors contains details about the failed requests.
                printf("Processing complete. Successful inserts: %d, Errors: %d%s", count($insertedReviewsResponses), count($errors), PHP_EOL);
            }
        }

        /**
         * Helper to execute the sample.
         */
        public function callSample(): void
        {
            $config = Config::generateConfig();
            self::asyncInsertMerchantReviewsSample($config, self::DATA_SOURCE_ID);
        }
    }

    $sample = new InsertMerchantReviewsAsyncSample();
    $sample->callSample();