Get and classify accounts under MCC

Retrieves customers under a mcc manager and splits them according to their account_type.

Python

#!/usr/bin/env python
# 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.
"""Retrieves customers under a mcc manager and splits them according to their account_type."""

import argparse
import traceback
from typing import Any
from google.ads.searchads360.v0.enums.types.account_level import AccountLevelTypeEnum
from google.ads.searchads360.v0.services.types.search_ads360_service import SearchSearchAds360StreamRequest
from google.api_core import exceptions
from util_searchads360 import SearchAds360Client


def _map_data(data, data_dictionary) -> None:
  """Inserts customer data into its corresponding dictionary using id as the key."""
  if data:
    data_dictionary[data['id']] = data


def _prepare_sub_manager_data(customer) -> dict[str, Any]:
  """Using the customer object, prepares sub-manager info."""
  sub_manager_id = customer.sub_manager_id

  sub_managers_info = {
      'id': sub_manager_id,
      'name': customer.sub_manager_descriptive_name,
      'type': AccountLevelTypeEnum.AccountLevelType.SUB_MANAGER.name,
      'parent_id': customer.manager_id,
  }
  return sub_managers_info


def _prepare_associate_manager_data(customer) -> dict[str, Any] | None:
  """Using the customer object, prepares associate-manager info."""
  associate_manager_id = customer.associate_manager_id
  associate_manager_id_descriptive_name = str(
      customer.associate_manager_descriptive_name
  )
  if not associate_manager_id_descriptive_name or associate_manager_id == 0:
    return None

  associate_manager_info = {
      'id': associate_manager_id,
      'name': associate_manager_id_descriptive_name,
      'type': AccountLevelTypeEnum.AccountLevelType.ASSOCIATE_MANAGER.name,
      'parent_id': customer.sub_manager_id,
  }
  return associate_manager_info


def _prepare_client_customer_data(customer) -> dict[str, Any]:
  """Using the customer object, prepares client-customer info."""
  client_customer_id = customer.id

  # Determine parent ID for the client account
  parent_id = (
      customer.associate_manager_id
      or customer.sub_manager_id
      or customer.manager_id
  )

  client_customer_info = {
      'id': client_customer_id,
      'name': customer.descriptive_name,
      'type': customer.account_type.name,
      'parent_id': parent_id,
  }
  return client_customer_info


def _get_all_accounts_details(
    search_ads_360_service,
    client_customer_id,
    sub_managers_data,
    associate_managers_data,
    client_accounts_data,
) -> None:
  """Fetches details for a client customer and updates hierarchy maps."""
  query = """
      SELECT
        customer.id,
        customer.descriptive_name,
        customer.account_type,
        customer.manager_id,
        customer.manager_descriptive_name,
        customer.sub_manager_id,
        customer.sub_manager_descriptive_name,
        customer.associate_manager_id,
        customer.associate_manager_descriptive_name,
        customer.account_level
      FROM customer"""
  request = SearchSearchAds360StreamRequest()
  request.customer_id = client_customer_id
  request.query = query
  try:
    results_stream = search_ads_360_service.search_stream(request=request)
    for response in results_stream:
      for row in response.results:
        customer = row.customer
        _map_data(_prepare_sub_manager_data(customer), sub_managers_data)
        _map_data(
            _prepare_associate_manager_data(customer), associate_managers_data
        )
        _map_data(_prepare_client_customer_data(customer), client_accounts_data)

  except exceptions.GoogleAPICallError as e:
    print(
        'ERROR: An unexpected error occurred while fetching customer'
        f' information for {client_customer_id}.\nDetails: {e}\n'
    )


def _get_client_customer_ids(search_ads_360_service, customer_id) -> list[str]:
  """Retrieves a list of client customer IDs (if the customer is a manager).

  Args:
    search_ads_360_service: The Search Ads 360 service client.
    customer_id: The customer ID of the mcc manager customer.

  Returns:
    A list of client customer IDs.
  """
  request = SearchSearchAds360StreamRequest()
  query = """
    SELECT
      customer_client.id,
      customer_client.manager
    FROM customer_client
    WHERE customer_client.manager = False
  """
  customer_client_ids = []
  request.customer_id = customer_id
  request.query = query
  try:
    # Issues a search stream request.
    results_stream = search_ads_360_service.search_stream(request=request)
    for response in results_stream:
      for row in response.results:
        customer_client_ids.append(str(row.customer_client.id))

  except exceptions.GoogleAPICallError as e:
    print(
        'ERROR: An unexpected error occurred while fetching client customer IDs'
        f' for {customer_id}.\nDetails: {e}\n'
    )
  return customer_client_ids


def main(service_client, login_customer_id) -> None:
  search_ads_360_service = service_client.get_service()

  sub_managers_data = {}
  associate_managers_data = {}
  client_accounts_data = {}

  # Get all client customer IDs under the login_customer_id (MCC manager)
  customer_client_ids = _get_client_customer_ids(
      search_ads_360_service, login_customer_id
  )

  for customer_client_id in customer_client_ids:
    _get_all_accounts_details(
        search_ads_360_service,
        customer_client_id,
        sub_managers_data,
        associate_managers_data,
        client_accounts_data,
    )


if __name__ == '__main__':
  # SearchAds360Client will read the search-ads-360.yaml configuration file in
  # the home directory if none is specified.
  search_ads_360_client = SearchAds360Client.load_from_file()

  parser = argparse.ArgumentParser(
      description=(
          'Retrieves all customer_client for a mcc manager customer and runs a'
          ' query on each customer_client.'
      )
  )

  # Arguments to provide to run the example.
  parser.add_argument(
      '-l',
      '--login_customer_id',
      type=str,
      required=True,
      help=(
          'The Search Ads 360 MCC manager login customer ID (10 digits, no'
          ' dashes). This can be obtained from the UI or from calling'
          ' ListAccessibleCustomers - '
          'https://developers.google.com/search-ads/reporting/concepts/login-customer-id.'
      ),
  )

  args = parser.parse_args()

  search_ads_360_client.set_ids(args.login_customer_id, args.login_customer_id)

  try:
    main(search_ads_360_client, args.login_customer_id)
  except Exception:  # pylint: disable=broad-except
    traceback.print_exc()

Download run_mcc_query.py

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 sample;

import com.beust.jcommander.Parameter;
import com.google.ads.searchads360.v0.enums.AccountLevelTypeEnum.AccountLevelType;
import com.google.ads.searchads360.v0.lib.SearchAds360Client;
import com.google.ads.searchads360.v0.resources.Customer;
import com.google.ads.searchads360.v0.services.SearchAds360Row;
import com.google.ads.searchads360.v0.services.SearchAds360ServiceClient;
import com.google.ads.searchads360.v0.services.SearchSearchAds360StreamRequest;
import com.google.ads.searchads360.v0.services.SearchSearchAds360StreamResponse;
import com.google.api.gax.rpc.ServerStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** Retrieves customers under a mcc manager and splits them according to their account_type. */
public class RunMccQuery {

  private static record AccountDetails(long id, String name, String type, long parentId) {}

  private static class RunMccQueryParams extends CodeSampleParams {

    @Parameter(
        names = "--loginCustomerId",
        required = true,
        description =
            "The Search Ads 360 MCC manager login customer ID (10 digits, no dashes). This can be"
                + " obtained from the UI or from calling ListAccessibleCustomers -"
                + " https://developers.google.com/search-ads/reporting/concepts/login-customer-id.")
    private String loginCustomerId;
  }

  public static void main(String[] args) {
    RunMccQueryParams params = new RunMccQueryParams();
    params.parseArguments(args);
    final String loginCustomerId = params.loginCustomerId;

    try {
      // Creates a SearchAds360Client with the specified loginCustomerId.
      final SearchAds360Client searchAds360Client =
          SearchAds360Client.newBuilder()
              .setLoginCustomerId(loginCustomerId)
              .fromPropertiesFile()
              .build();
      // Creates the Search Ads 360 Service client.
      SearchAds360ServiceClient client = searchAds360Client.create();
      new RunMccQuery().runExample(client, loginCustomerId);
    } catch (Exception exception) {
      System.err.printf("Failed with exception: %s%n", exception);
      exception.printStackTrace();
      System.exit(1);
    }
  }

  private void runExample(
      SearchAds360ServiceClient searchAds360ServiceClient, String loginCustomerId) {
    Map<Long, AccountDetails> subManagersData = new HashMap<>();
    Map<Long, AccountDetails> associateManagersData = new HashMap<>();
    Map<Long, AccountDetails> clientAccountsData = new HashMap<>();

    List<String> customerClientIds =
        getClientCustomerIds(searchAds360ServiceClient, loginCustomerId);

    for (String customerClientId : customerClientIds) {
      getAllAccountsDetails(
          searchAds360ServiceClient,
          customerClientId,
          subManagersData,
          associateManagersData,
          clientAccountsData);
    }
  }

  /** Retrieves a list of client customer IDs (if the customer is a manager). */
  private List<String> getClientCustomerIds(
      SearchAds360ServiceClient searchAds360ServiceClient, String managerCustomerId) {
    List<String> customerClientIds = new ArrayList<>();
    String query =
        """
        SELECT customer_client.id, customer_client.manager
        FROM customer_client
        WHERE customer_client.manager = FALSE
        """;

    SearchSearchAds360StreamRequest request =
        SearchSearchAds360StreamRequest.newBuilder()
            .setCustomerId(managerCustomerId)
            .setQuery(query)
            .build();

    try {
      ServerStream<SearchSearchAds360StreamResponse> stream =
          searchAds360ServiceClient.searchStreamCallable().call(request);
      for (SearchSearchAds360StreamResponse response : stream) {
        for (SearchAds360Row row : response.getResultsList()) {
          customerClientIds.add(String.valueOf(row.getCustomerClient().getId()));
        }
      }
    } catch (Exception e) {
      System.err.printf(
          "ERROR: An unexpected error occurred while fetching client customer IDs for %s.%nDetails:"
              + " %s%n",
          managerCustomerId, e);
    }
    return customerClientIds;
  }

  /** Fetches details for a client customer and updates hierarchy maps. */
  private void getAllAccountsDetails(
      SearchAds360ServiceClient searchAds360ServiceClient,
      String clientCustomerId,
      Map<Long, AccountDetails> subManagersData,
      Map<Long, AccountDetails> associateManagersData,
      Map<Long, AccountDetails> clientAccountsData) {
    String query =
        """
        SELECT
          customer.id, customer.descriptive_name, customer.account_type,
          customer.manager_id, customer.manager_descriptive_name, customer.sub_manager_id,
          customer.sub_manager_descriptive_name, customer.associate_manager_id,
          customer.associate_manager_descriptive_name, customer.account_level
        FROM customer
        """;

    SearchSearchAds360StreamRequest request =
        SearchSearchAds360StreamRequest.newBuilder()
            .setCustomerId(clientCustomerId)
            .setQuery(query)
            .build();

    try {
      ServerStream<SearchSearchAds360StreamResponse> stream =
          searchAds360ServiceClient.searchStreamCallable().call(request);
      for (SearchSearchAds360StreamResponse response : stream) {
        for (SearchAds360Row row : response.getResultsList()) {
          Customer customer = row.getCustomer();
          mapData(prepareSubManagerData(customer), subManagersData);
          mapData(prepareAssociateManagerData(customer), associateManagersData);
          mapData(prepareClientCustomerData(customer), clientAccountsData);
        }
      }
    } catch (Exception e) {
      System.err.printf(
          "ERROR: An unexpected error occurred while fetching customer information for"
              + " %s.%nDetails: %s%n",
          clientCustomerId, e);
    }
  }

  /** Inserts customer data into its corresponding dictionary using id as the key. */
  private void mapData(AccountDetails accountDetails, Map<Long, AccountDetails> dataCollectionMap) {
    if (accountDetails.id() != 0) {
      dataCollectionMap.put(accountDetails.id(), accountDetails);
    }
  }

  /** Using the customer object, prepares sub-manager info. */
  private AccountDetails prepareSubManagerData(Customer customer) {
    return new AccountDetails(
        customer.getSubManagerId(),
        customer.getSubManagerDescriptiveName(),
        AccountLevelType.SUB_MANAGER.name(),
        customer.getManagerId());
  }

  /** Using the customer object, prepares associate-manager info. */
  private AccountDetails prepareAssociateManagerData(Customer customer) {
    return new AccountDetails(
        customer.getAssociateManagerId(),
        customer.getAssociateManagerDescriptiveName(),
        AccountLevelType.ASSOCIATE_MANAGER.name(),
        customer.getSubManagerId());
  }

  /** Using the customer object, prepares client-customer info. */
  private AccountDetails prepareClientCustomerData(Customer customer) {
    long parentId = customer.getManagerId();
    if (customer.getAssociateManagerId() != 0) {
      parentId = customer.getAssociateManagerId();
    } else if (customer.getSubManagerId() != 0) {
      parentId = customer.getSubManagerId();
    }
    return new AccountDetails(
        customer.getId(),
        customer.getDescriptiveName(),
        customer.getAccountType().name(),
        parentId);
  }
}

Download RunMccQuery.java