Merchant API code sample to trigger action for an account issue.

### 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.issueresolution.v1;

    import com.google.api.gax.core.FixedCredentialsProvider;
    import com.google.auth.oauth2.GoogleCredentials;
    import com.google.shopping.merchant.issueresolution.v1.AccountName;
    import com.google.shopping.merchant.issueresolution.v1.Action;
    import com.google.shopping.merchant.issueresolution.v1.ActionFlow;
    import com.google.shopping.merchant.issueresolution.v1.ActionInput;
    import com.google.shopping.merchant.issueresolution.v1.BuiltInUserInputAction;
    import com.google.shopping.merchant.issueresolution.v1.InputField;
    import com.google.shopping.merchant.issueresolution.v1.InputField.ChoiceInput;
    import com.google.shopping.merchant.issueresolution.v1.InputField.ChoiceInput.ChoiceInputOption;
    import com.google.shopping.merchant.issueresolution.v1.InputValue;
    import com.google.shopping.merchant.issueresolution.v1.InputValue.CheckboxInputValue;
    import com.google.shopping.merchant.issueresolution.v1.InputValue.ChoiceInputValue;
    import com.google.shopping.merchant.issueresolution.v1.InputValue.TextInputValue;
    import com.google.shopping.merchant.issueresolution.v1.IssueResolutionServiceClient;
    import com.google.shopping.merchant.issueresolution.v1.IssueResolutionServiceSettings;
    import com.google.shopping.merchant.issueresolution.v1.RenderAccountIssuesRequest;
    import com.google.shopping.merchant.issueresolution.v1.RenderAccountIssuesResponse;
    import com.google.shopping.merchant.issueresolution.v1.RenderIssuesRequestPayload;
    import com.google.shopping.merchant.issueresolution.v1.RenderedIssue;
    import com.google.shopping.merchant.issueresolution.v1.TriggerActionPayload;
    import com.google.shopping.merchant.issueresolution.v1.TriggerActionRequest;
    import com.google.shopping.merchant.issueresolution.v1.TriggerActionResponse;
    import com.google.shopping.merchant.issueresolution.v1.UserInputActionRenderingOption;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    import java.util.stream.Collectors;
    import shopping.merchant.samples.utils.Authenticator;
    import shopping.merchant.samples.utils.Config;

    /**
     * This class demonstrates how to trigger an action on account-level issues for a given Merchant
     * Center account.
     *
     * <p>The example first calls the `renderAccountIssues` to obtain live issues for the account. The
     * user can select the issue, they want to trigger an action for. The program will ask them to
     * provide all required user input, specific for the selected action. Once the input is collected,
     * the program build the request and calls the `triggerAction`
     *
     * <p>NOTE: the access to `triggerAction` is currently limited. To obtain access follow steps in the
     * development guide.
     */
    public class TriggerActionForAccountIssueSample {

      private static void renderAccountIssuesAndTriggerAction(
          Config config,
          String languageCode,
          String timeZone,
          UserInputActionRenderingOption userInputActionOption,
          Scanner scanner)
          throws IOException {

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

        IssueResolutionServiceSettings settings =
            IssueResolutionServiceSettings.newBuilder()
                .setCredentialsProvider(FixedCredentialsProvider.create(credential))
                .build();

        String accountId = config.getAccountId().toString();
        String name = AccountName.newBuilder().setAccount(accountId).build().toString();

        try (IssueResolutionServiceClient client = IssueResolutionServiceClient.create(settings)) {

          // First, we call the `renderAccountIssues` to obtain live issues for the account. The
          // `userInputActionOption` specifies how the complex Built-In actions should be rendered. For
          // this example, the option is set to `REDIRECT_TO_MERCHANT_CENTER`, so the
          // complex actions will be rendered as `BuiltInUserInputAction` that can be started by calling
          // the `triggerAction` method.
          RenderAccountIssuesRequest request =
              RenderAccountIssuesRequest.newBuilder()
                  .setName(name)
                  .setLanguageCode(languageCode)
                  .setTimeZone(timeZone)
                  .setPayload(
                      RenderIssuesRequestPayload.newBuilder()
                          .setUserInputActionOption(userInputActionOption)
                          .build())
                  .build();

          System.out.println("Sending RenderAccountIssues request");

          RenderAccountIssuesResponse response = client.renderAccountIssues(request);

          System.out.println("The full response:");
          System.out.println(response);

          System.out.println("---");
          System.out.println("Summary: ");
          System.out.println(response.getRenderedIssuesCount() + " issues found for the account");

          // Filter all issues that have at least one action that is available and has a built-in user
          // input action.
          List<RenderedIssue> issuesWithTriggerableAction =
              response.getRenderedIssuesList().stream()
                  .filter(
                      issue ->
                          issue.getActionsList().stream()
                              .anyMatch(
                                  action ->
                                      action.getIsAvailable() && action.hasBuiltinUserInputAction()))
                  .collect(Collectors.toList());

          if (issuesWithTriggerableAction.isEmpty()) {
            System.out.println("There is currently no issue that has a triggerable action");
            return; // Early exit as there is no action to be triggered.
          }

          System.out.println(
              issuesWithTriggerableAction.size()
                  + " issues have an action that could be started with the `triggerAction` method:");

          // The user should select the issue for which they will trigger an action
          for (int i = 0; i < issuesWithTriggerableAction.size(); i++) {
            System.out.println("  [" + i + "] " + issuesWithTriggerableAction.get(i).getTitle());
          }
          int selectedIssueId =
              requestUserInputAsNumber(0, issuesWithTriggerableAction.size() - 1, "issue", scanner);
          RenderedIssue issue = issuesWithTriggerableAction.get(selectedIssueId);
          System.out.println("You selected '" + issue.getTitle() + "' issue.");

          List<Action> actions =
              issue.getActionsList().stream()
                  .filter(it -> it.getIsAvailable() && it.hasBuiltinUserInputAction())
                  .collect(Collectors.toList());

          // There could be multiple actions that can be triggered for a given issue. The user should
          // select the action they want to trigger.
          Action action;
          if (actions.size() == 1) {
            action = actions.get(0);
            System.out.println(
                "There is only one action '" + action.getButtonLabel() + "' that can be triggered.");
          } else {
            for (int i = 0; i < actions.size(); i++) {
              System.out.println("  [" + i + "] " + actions.get(i).getButtonLabel());
            }
            int selectedActionId = requestUserInputAsNumber(0, actions.size() - 1, "action", scanner);
            action = actions.get(selectedActionId);
            System.out.println("You selected '" + action.getButtonLabel() + "' action.");
          }

          BuiltInUserInputAction triggerableAction = action.getBuiltinUserInputAction();

          // There could be multiple action flows for a given action. The user should select the
          // specific action flow they want to trigger.
          ActionFlow actionFlow;
          if (triggerableAction.getFlowsList().size() > 1) {
            System.out.println(
                "For the '"
                    + action.getButtonLabel()
                    + "' there are "
                    + triggerableAction.getFlowsCount()
                    + " flows available:");
            for (int i = 0; i < triggerableAction.getFlowsCount(); i++) {
              System.out.println("  [" + i + "] " + triggerableAction.getFlowsList().get(i).getLabel());
            }
            int selectedFlowId =
                requestUserInputAsNumber(0, triggerableAction.getFlowsCount() - 1, "flow", scanner);
            actionFlow = triggerableAction.getFlows(selectedFlowId);
            System.out.println("You selected '" + actionFlow.getLabel() + "' flow");
          } else {
            actionFlow = triggerableAction.getFlowsList().get(0);
          }

          // For each flow, additional content needs to be shown to the user. There should be a dialog
          // with user input form and additional content. The content is defined by the
          // `dialog_title`, `dialog_callout` and `dialog_message` fields.
          System.out.println();
          System.out.println("Additional content to display to the merchant (as a dialog):");
          System.out.println(actionFlow.getDialogTitle());
          if (actionFlow.hasDialogCallout()) {
            System.out.println(actionFlow.getDialogCallout().getFullMessage().getSimpleValue());
          }
          System.out.println(actionFlow.getDialogMessage().getSimpleValue());

          // Collect user input values, that may be required to trigger the action (flow). This would be
          // displayed as a form to the user.
          List<InputValue> inputValues = new ArrayList<>();
          if (actionFlow.getInputsCount() > 0) {
            System.out.println();
            System.out.println("User input form:");

            for (InputField field : actionFlow.getInputsList()) {
              System.out.print("field [" + field.getId() + "]: " + field.getLabel().getSimpleValue());
              if (field.getRequired()) {
                System.out.print(" (required)");
              }
              // checkbox field
              if (field.hasCheckboxInput()) {
                // The user should confirm the checkbox.
                System.out.println(" [checkbox]");
                System.out.print(" Enter 'true' to confirm: ");
                String input = scanner.nextLine();
                if ("true".equals(input.toLowerCase())) {
                  inputValues.add(
                      InputValue.newBuilder()
                          .setInputFieldId(field.getId())
                          .setCheckboxInputValue(CheckboxInputValue.newBuilder().setValue(true).build())
                          .build());
                } else {
                  System.out.println("Wrong value");
                  if (field.getRequired()) {
                    System.out.println("The action can not be triggered without a required value");
                    return;
                  }
                }
                // select field
              } else if (field.hasChoiceInput()) {
                // For the ChoiceInput, there are multiple predefined options. The user should select
                // one of the predefined options.
                System.out.println(" [select]");
                ChoiceInput choiceInput = field.getChoiceInput();
                for (int i = 0; i < choiceInput.getOptionsCount(); i++) {
                  System.out.println(
                      "  ["
                          + i
                          + "] "
                          + choiceInput.getOptions(i).getLabel().getSimpleValue()
                          + " ["
                          + choiceInput.getOptions(i).getId()
                          + "]");
                }
                int selectedOptionId =
                    requestUserInputAsNumber(0, choiceInput.getOptionsCount() - 1, "option", scanner);
                ChoiceInputOption selectedOption = choiceInput.getOptions(selectedOptionId);
                System.out.println("You selected '" + selectedOption.getLabel().getSimpleValue() + "'");

                inputValues.add(
                    InputValue.newBuilder()
                        .setInputFieldId(field.getId())
                        .setChoiceInputValue(
                            ChoiceInputValue.newBuilder()
                                .setChoiceInputOptionId(selectedOption.getId())
                                .build())
                        .build());
                // text input field
              } else if (field.hasTextInput()) {
                // For the TextInput, the user should enter the text.
                System.out.println(" [text]");
                System.out.print(" Enter the text: ");
                String input = scanner.nextLine();

                inputValues.add(
                    InputValue.newBuilder()
                        .setInputFieldId(field.getId())
                        .setTextInputValue(TextInputValue.newBuilder().setValue(input).build())
                        .build());
              }
              System.out.println();
            }
          }

          // Build the request to trigger the action.
          TriggerActionRequest triggerActionRequest =
              TriggerActionRequest.newBuilder()
                  .setLanguageCode(languageCode)
                  .setName(name)
                  .setPayload(
                      TriggerActionPayload.newBuilder()
                          // set the action context for selected action
                          .setActionContext(triggerableAction.getActionContext())
                          // set the action inputs
                          .setActionInput(
                              ActionInput.newBuilder()
                                  // set the FlowId for the selected action flow
                                  .setActionFlowId(actionFlow.getId())
                                  // set user input for all (required) user input fields
                                  .addAllInputValues(inputValues)
                                  .build())
                          .build())
                  .build();

          System.out.println("---");
          System.out.println("Calling `triggerAction` with request: ");
          System.out.println(triggerActionRequest);
          TriggerActionResponse triggerActionResponse = client.triggerAction(triggerActionRequest);

          System.out.println("The full response:");
          System.out.println(triggerActionResponse);

        } catch (Exception e) {
          System.out.println("An error has occured: ");
          System.out.println(e);

          if (e.getMessage()
              .contains(
                  "PERMISSION_DENIED: This API endpoint is not enabled for your cloud project id.")) {
            System.out.println("The access to the `triggerAction` method is currently limited.");
            System.out.println(
                "To get the access, you need to first, submit a request. A link to the form can be"
                    + " found in the development guide");
          }
        }
      }

      private static int requestUserInputAsNumber(int min, int max, String itemName, Scanner scanner) {
        while (true) {
          System.out.print(
              "Enter a number from <" + min + "-" + max + "> to select the " + itemName + ": ");
          try {
            int value = scanner.nextInt();
            if (value >= min && value <= max) {
              scanner.nextLine();
              return value;
            } else {
              System.out.println("Invalid input.");
            }
          } catch (java.util.InputMismatchException e) {
            System.out.println("Invalid input. Please enter a valid number.");
            scanner.nextLine(); // Clear the invalid input from the scanner
          }
        }
      }

      public static void main(String[] args) throws Exception {
        Config config = Config.load();
        String timeZone = "Europe/Zurich";
        String languageCode = "en_GB";
        // To implement complex troubleshooting actions directly in your app,
        // the RenderAccountIssuesRequest must have set the `userInputActionOption` as
        // `BUILT_IN_USER_INPUT_ACTIONS`. Otherwise, these actions would be handled as redirects to
        // the Merchant Center (by default).
        UserInputActionRenderingOption inputActionOption =
            UserInputActionRenderingOption.BUILT_IN_USER_INPUT_ACTIONS;

        try (Scanner scanner = new Scanner(System.in)) {
          renderAccountIssuesAndTriggerAction(
              config, languageCode, timeZone, inputActionOption, scanner);
        }
      }
    }