Предоставление клиента

В этом руководстве показано, как предоставить данные клиенту с помощью API реселлера.

Правильная подготовка клиента включает в себя несколько взаимозависимых шагов, охватывающих несколько API на платформе Google Workspace.

Поток API, используемый для создания клиента Google Workspace.
Рисунок 1. Основные этапы подготовки клиента Google Workspace

На предыдущей диаграмме показано, какие API используются на каждом этапе для предоставления услуг клиенту:

  • Используйте API проверки сайта для размещения токена проверки домена.
  • Используйте API реселлера для создания клиента.
  • Используйте API каталога, чтобы создать первого пользователя и сделать его администратором.
  • Используйте API реселлера для создания подписки.
  • Используйте API проверки сайта для проверки домена.

Предпосылки

  • Экземпляр домена реселлера Google.
  • Полностью оформленное партнерское соглашение Google Workspace.

Настройте свою среду

Чтобы завершить это руководство, настройте свою среду.

Включить API

Перед использованием API Google необходимо включить их в проекте Google Cloud. Вы можете включить один или несколько API в одном проекте Google Cloud.
  • В консоли Google Cloud включите Reseller API, Site Verification API и Admin SDK API.

    Включить APIS

Создать учетную запись службы

Учётная запись службы — это особый тип учётной записи, используемый приложением, а не пользователем. Вы можете использовать учётную запись службы для доступа к данным или выполнения действий с учётной записью робота, а также для доступа к данным от имени пользователей Google Workspace или Cloud Identity. Подробнее см. в разделе «Общие сведения об учётных записях службы» .

Консоль Google Cloud

  1. В консоли Google Cloud перейдите в > IAM и администрирование > Учетные записи служб .

    Перейти к учетным записям служб

  2. Нажмите Создать учетную запись службы .
  3. Заполните данные учетной записи службы, затем нажмите «Создать» и продолжите .
  4. Необязательно: назначьте роли своему сервисному аккаунту, чтобы предоставить доступ к ресурсам вашего проекта Google Cloud. Подробнее см. в разделе Предоставление, изменение и отзыв доступа к ресурсам .
  5. Нажмите «Продолжить» .
  6. Необязательно: введите пользователей или группы, которые смогут управлять этой учётной записью службы и выполнять с ней действия. Подробнее см. в разделе Управление олицетворением учётной записи службы .
  7. Нажмите «Готово» . Запишите адрес электронной почты для учётной записи сервиса.

gcloud CLI

  1. Создайте учетную запись службы:
    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
      --display-name="SERVICE_ACCOUNT_NAME"
  2. Необязательно: назначьте роли своему сервисному аккаунту, чтобы предоставить доступ к ресурсам вашего проекта Google Cloud. Подробнее см. в разделе Предоставление, изменение и отзыв доступа к ресурсам .

Создайте учетные данные для учетной записи службы

Вам необходимо получить учётные данные в виде пары открытого и закрытого ключей. Эти данные используются вашим кодом для авторизации действий сервисной учётной записи в вашем приложении.
  1. В консоли Google Cloud перейдите в > IAM и администрирование > Учетные записи служб .

    Перейти к учетным записям служб

  2. Выберите свою учетную запись службы.
  3. Нажмите Ключи > Добавить ключ > Создать новый ключ .
  4. Выберите JSON , затем нажмите Создать .

    Ваша новая пара открытого и закрытого ключей будет сгенерирована и загружена на ваш компьютер в виде нового файла. Сохраните загруженный JSON-файл как credentials.json в вашем рабочем каталоге. Этот файл — единственная копия данного ключа. Сведения о безопасном хранении ключа см. в разделе Управление ключами учётной записи службы .

  5. Нажмите «Закрыть» .

Настройте делегирование на уровне домена для учетной записи службы

Для вызова API от имени пользователей в организации Google Workspace вашей учетной записи службы необходимо предоставить делегирование полномочий на уровне домена в консоли администратора Google Workspace с помощью учетной записи суперадминистратора. Подробнее см. в статье Делегирование полномочий на уровне домена учетной записи службы .
  1. В консоли Google Cloud перейдите в > IAM и администрирование > Учетные записи служб .

    Перейти к учетным записям служб

  2. Выберите свою учетную запись службы.
  3. Нажмите Показать дополнительные настройки .
  4. В разделе «Делегирование на уровне домена» найдите «Идентификатор клиента» вашей учётной записи службы. Нажмите «Копировать , чтобы скопировать значение идентификатора клиента в буфер обмена.
  5. Если у вас есть права суперадминистратора к соответствующей учетной записи Google Workspace, нажмите «Просмотреть консоль администратора Google Workspace» , затем войдите в систему, используя учетную запись суперадминистратора, и продолжите выполнение следующих шагов.

    Если у вас нет прав суперадминистратора для соответствующей учетной записи Google Workspace, обратитесь к суперадминистратору этой учетной записи и отправьте ему идентификатор клиента вашей учетной записи службы и список областей OAuth, чтобы он мог выполнить следующие шаги в консоли администратора.

    1. В консоли администратора Google перейдите в > Безопасность > Управление доступом и данными > Элементы управления API .

      Перейти к элементам управления API

    2. Нажмите «Управление делегированием на уровне домена» .
    3. Нажмите Добавить новый .
    4. В поле «Идентификатор клиента» вставьте скопированный ранее идентификатор клиента.
    5. В поле «Области действия OAuth» введите список областей действия, требуемых вашим приложением, разделённый запятыми. Это тот же набор областей действия, который вы определили при настройке экрана согласия OAuth.
    6. Нажмите «Авторизовать» .

Создание объектов служб с аутентифицированными учетными данными

Чтобы начать работу с любым API Google, необходимо настроить аутентификацию и учётные данные в вашем приложении. Клиентские библиотеки Google выполняют эту задачу от вашего имени. Все библиотеки имеют шаблоны для создания объекта учётных данных, которому вы можете предоставить доступ ко всем API и передать его в каждый сервис. Приложение, как правило, должно иметь один набор учётных данных и использовать только один облачный проект для всех взаимодействий с API Google.

Используйте файл ключа JSON, который вы сгенерировали при создании учетной записи службы.

Питон
import sys
from apiclient.discovery import build
from apiclient.http import HttpError
from oauth2client.service_account import ServiceAccountCredentials

############## REPLACE WITH YOUR OWN VALUES ####################
JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json'
RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com'
CUSTOMER_DOMAIN = 'example.com'
CUSTOMER_SITE = 'https://www.example.com'
################################################################

# Full List of scopes:
# https://developers.google.com/identity/protocols/googlescopes
OAUTH2_SCOPES = [
    'https://reseller.googleapis.com/auth/apps.order',
    'https://reseller.googleapis.com/auth/siteverification',
    'https://reseller.googleapis.com/auth/admin.directory.user',
]

credentials = ServiceAccountCredentials.from_json_keyfile_name(
    JSON_PRIVATE_KEY_FILE, OAUTH2_SCOPES).create_delegated(RESELLER_ADMIN_USER)

reseller_service = build(
    serviceName='reseller', version='v1', credentials=credentials)

directory_service = build(
    serviceName='admin', version='directory_v1', credentials=credentials)

verification_service = build(
    serviceName='siteVerification', version='v1', credentials=credentials)
Ява
// OAuth2 and HTTP
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.json.jackson2.JacksonFactory;
// Directory API
import com.google.api.services.admin.directory.Directory;
import com.google.api.services.admin.directory.DirectoryScopes;
import com.google.api.services.admin.directory.model.User;
import com.google.api.services.admin.directory.model.UserMakeAdmin;
import com.google.api.services.admin.directory.model.UserName;
// Reseller API
import com.google.api.services.reseller.Reseller;
import com.google.api.services.reseller.ResellerScopes;
import com.google.api.services.reseller.model.Address;
import com.google.api.services.reseller.model.Customer;
import com.google.api.services.reseller.model.RenewalSettings;
import com.google.api.services.reseller.model.Seats;
import com.google.api.services.reseller.model.Subscription;
// Site Verification API
import com.google.api.services.siteVerification.SiteVerification;
import com.google.api.services.siteVerification.SiteVerificationScopes;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceGettokenRequest;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceGettokenResponse;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceResource;
// Java library imports
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;

/**
 * This is a basic example of provisioning a Google Workspace customer.
 */
public class CodelabExample {
  // Full List of scopes:
  // https://developers.google.com/identity/protocols/googlescopes
  private static final List<String> OAUTH2_SCOPES = Arrays.asList(
    ResellerScopes.APPS_ORDER,
    SiteVerificationScopes.SITEVERIFICATION,
    DirectoryScopes.ADMIN_DIRECTORY_USER
  );

  /***************** REPLACE WITH YOUR OWN VALUES ********************************/
  public static final String JSON_PRIVATE_KEY_FILE = "path/to/json_key_file.json";
  public static final String RESELLER_ADMIN_USER = "admin@yourresellerdomain.com";
  public static final String CUSTOMER_DOMAIN = "example.com";
  public static final String CUSTOMER_SITE = "https://www.example.com/";
  /*******************************************************************************/

  public static void main(String[] args)
      throws IOException, GeneralSecurityException, FileNotFoundException {
    // Instantiate services with authenticated credentials
    GoogleCredential jsonCredentials = GoogleCredential
      .fromStream(new FileInputStream(JSON_PRIVATE_KEY_FILE));
    GoogleCredential credentials = new GoogleCredential.Builder()
      .setTransport(GoogleNetHttpTransport.newTrustedTransport())
      .setJsonFactory(JacksonFactory.getDefaultInstance())
      .setServiceAccountScopes(OAUTH2_SCOPES)
      .setServiceAccountUser(RESELLER_ADMIN_USER)
      .setServiceAccountPrivateKey(jsonCredentials.getServiceAccountPrivateKey())
      .setServiceAccountId(jsonCredentials.getServiceAccountId())
      .build();

    Reseller resellerService = new Reseller.Builder(
        credentials.getTransport(),
        credentials.getJsonFactory(),
        credentials).setApplicationName("Google Workspace Creator").build();

    Directory directoryService = new Directory.Builder(
        credentials.getTransport(),
        credentials.getJsonFactory(),
        credentials).setApplicationName("Google Workspace Creator").build();

    SiteVerification verificationService = new SiteVerification.Builder(
        credentials.getTransport(),
        credentials.getJsonFactory(),
        credentials).setApplicationName("Google Workspace Creator").build();
С#
// OAuth2 and HTTP
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
// Reseller API
using Google.Apis.Reseller.v1;
using Google.Apis.Reseller.v1.Data;
// Directory API
using Google.Apis.Admin.Directory.directory_v1;
using User = Google.Apis.Admin.Directory.directory_v1.Data.User;
using UserName = Google.Apis.Admin.Directory.directory_v1.Data.UserName;
using UserMakeAdmin = Google.Apis.Admin.Directory.directory_v1.Data.UserMakeAdmin;
//Site Verification API
using Google.Apis.SiteVerification.v1;
using Google.Apis.SiteVerification.v1.Data;
// System imports
using System;
using System.IO;

class CodelabExample
{
    // Full List of scopes:
    // https://developers.google.com/identity/protocols/googlescopes
    static string[] OAUTH2_SCOPES = {
        ResellerService.Scope.AppsOrder,
        DirectoryService.Scope.AdminDirectoryUser,
        SiteVerificationService.Scope.Siteverification
    };

    /***************** REPLACE WITH YOUR OWN VALUES ********************************/
    public static String JSON_PRIVATE_KEY_FILE = "path/to/json_key_file.json";
    public static String RESELLER_ADMIN_USER = "admin@yourresellerdomain.com";
    public static String CUSTOMER_DOMAIN = "example.com";
    public static String CUSTOMER_SITE = "https://www.example.com/";
    /*******************************************************************************/

    static void Main(string[] args)
    {
        GoogleCredential credential;

        using (var stream = new FileStream(JSON_PRIVATE_KEY_FILE, FileMode.Open, FileAccess.Read))
        {
            credential = GoogleCredential
                .FromStream(stream)
                .CreateScoped(OAUTH2_SCOPES)
                .CreateWithUser(RESELLER_ADMIN_USER);
        }

        var resellerService = new ResellerService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
        });

        var directoryService = new DirectoryService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
        });

        var verificationService = new SiteVerificationService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
        });
PHP
// https://developers.google.com/api-client-library/php/
require_once 'vendor/autoload.php';

// Full List of scopes:
// https://developers.google.com/identity/protocols/googlescopes
$OAUTH2_SCOPES = [
  Google_Service_Reseller::APPS_ORDER,
  Google_Service_SiteVerification::SITEVERIFICATION,
  Google_Service_Directory::ADMIN_DIRECTORY_USER,
];

######### REPLACE WITH YOUR OWN VALUES ###############
$JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json';
$RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com';
$CUSTOMER_DOMAIN = 'example.com';
$CUSTOMER_SITE = 'https://www.example.com/';
######################################################

$client = new Google_Client();
$client->setAuthConfig($JSON_PRIVATE_KEY_FILE);
$client->setSubject($RESELLER_ADMIN_USER);
$client->setScopes($OAUTH2_SCOPES);

$resellerService = new Google_Service_Reseller($client);
$directoryService = new Google_Service_Directory($client);
$verificationService = new Google_Service_SiteVerification($client);
Руби
require 'googleauth'
require 'google/apis/reseller_v1'
require 'google/apis/site_verification_v1'
require 'google/apis/admin_directory_v1'

# Full List of scopes:
# https://developers.google.com/identity/protocols/googlescopes
OAUTH2_SCOPES = [
  'https://reseller.googleapis.com/auth/apps.order',
  'https://reseller.googleapis.com/auth/admin.directory.user',
  'https://reseller.googleapis.com/auth/siteverification',
]

####### REPLACE WITH YOUR OWN VALUES ###############
JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json'
RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com'
CUSTOMER_DOMAIN = 'example.com'
CUSTOMER_SITE = 'https://www.example.com/'
####################################################

credentials = Google::Auth::ServiceAccountCredentials.make_creds(
  json_key_io: File.open(JSON_PRIVATE_KEY_FILE),
  scope: OAUTH2_SCOPES)
credentials.sub = RESELLER_ADMIN_USER

Google::Apis::RequestOptions.default.authorization = credentials

reseller_service = Google::Apis::ResellerV1::ResellerService.new
directory_service = Google::Apis::AdminDirectoryV1::DirectoryService.new
verification_service = Google::Apis::SiteVerificationV1::SiteVerificationService.new
Node.js
// NOTE: This script needs googleapis 28.0.0 or later as it uses promises
const {google} = require('googleapis');

// ############## REPLACE WITH YOUR OWN VALUES ####################
const JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json';
const RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com';
const CUSTOMER_DOMAIN = 'example.com';
const CUSTOMER_SITE = 'https://www.example.com/';
// ################################################################

// Full List of scopes: https://developers.google.com/identity/protocols/googlescopes
const OAUTH2_SCOPES = [
  'https://reseller.googleapis.com/auth/apps.order',
  'https://reseller.googleapis.com/auth/siteverification',
  'https://reseller.googleapis.com/auth/admin.directory.user',
];

const authJWT = new google.auth.JWT({
  keyFile: JSON_PRIVATE_KEY_FILE,
  scopes: OAUTH2_SCOPES,
  subject: RESELLER_ADMIN_USER,
});

const resellerService = google.reseller({version: 'v1', auth: authJWT});
const directoryService = google.admin({version: 'directory_v1', auth: authJWT});
const verificationService = google.siteVerification({version: 'v1', auth: authJWT});

Начать процесс проверки домена

Этот шаг необязателен, но рекомендуется, если у вас есть возможность подтвердить домен клиента. Этот шаг завершается в конце руководства, когда вы подтверждаете домен.

Если вы не подтвердите домен клиента, у него будут следующие ограничения:

Чтобы получить токен проверки сайта, выполните следующие действия:

  1. Чтобы получить токен проверки сайта, используйте API проверки сайта . Вы не можете проверить, был ли домен ранее проверен, но можете проверять сайты несколько раз без каких-либо проблем. Параметры verificationMethod различаются в зависимости от типа проверки: INET_DOMAIN или SITE . Выберите один из следующих вариантов:

    • Для типа INET_DOMAIN используйте один из следующих параметров verificationMethod :

      • DNS_TXT
      • DNS_CNAME

      В следующем примере извлечения токена используется тип INET_DOMAIN :

      Питон
      # Retrieve the site verification token and place it according to:
      # https://developers.google.com/site-verification/v1/getting_started#tokens
      response = verification_service.webResource().getToken(
          body={
              'site': {
                  'type': 'INET_DOMAIN',
                  'identifier': CUSTOMER_DOMAIN
              },
              'verificationMethod': 'DNS_TXT'
          }).execute()
      print(response)
      Ява
      // Retrieve the site verification token and place it according to:
      // https://developers.google.com/site-verification/v1/getting_started#tokens
      SiteVerificationWebResourceGettokenRequest.Site getTokenSite =
          new SiteVerificationWebResourceGettokenRequest.Site()
              .setType("INET_DOMAIN")
              .setIdentifier(CUSTOMER_DOMAIN);
      
      SiteVerificationWebResourceGettokenRequest request =
          new SiteVerificationWebResourceGettokenRequest()
              .setVerificationMethod("DNS_TXT")
              .setSite(getTokenSite);
      
      SiteVerificationWebResourceGettokenResponse getTokenResponse =
          verificationService.webResource().getToken(request).execute();
      System.out.println("Site Verification Token: " + getTokenResponse.getToken());
      С#
      // Retrieve the site verification token and place it according to:
      // https://developers.google.com/site-verification/v1/getting_started#tokens
      SiteVerificationWebResourceGettokenRequest.SiteData getTokenSite =
          new SiteVerificationWebResourceGettokenRequest.SiteData()
          {
              Type = "INET_DOMAIN",
              Identifier = CUSTOMER_DOMAIN
          };
      
      SiteVerificationWebResourceGettokenRequest request =
          new SiteVerificationWebResourceGettokenRequest()
          {
              VerificationMethod = "DNS_TXT",
              Site = getTokenSite
          };
      
      SiteVerificationWebResourceGettokenResponse getTokenResponse =
          verificationService.WebResource.GetToken(request).Execute();
      Console.WriteLine("Site Verification Token: {0}", getTokenResponse.Token);
      PHP
      // Retrieve the site verification token and place it according to:
      // https://developers.google.com/site-verification/v1/getting_started#tokens
      $body =
      new Google_Service_SiteVerification_SiteVerificationWebResourceGettokenRequest([
        'verificationMethod' => 'DNS_TXT',
        'site' => [
          'type' => 'INET_DOMAIN',
          'identifier' => $CUSTOMER_DOMAIN
        ]
      ]);
      $response = $verificationService->webResource->getToken($body);
      print_r ($response);
      Руби
      # Retrieve the site verification token and place it according to:
      # https://developers.google.com/site-verification/v1/getting_started#tokens
      request = Google::Apis::SiteVerificationV1::GetWebResourceTokenRequest.new(
        site: {
          type: 'INET_DOMAIN',
          identifier: CUSTOMER_DOMAIN
        },
        verification_method: 'DNS_TXT'
      )
      
      response = verification_service.get_web_resource_token(request)
      puts response.inspect
      Node.js
      /**
       * Retrieve the site verification token and place it according to:
       * https://developers.google.com/site-verification/v1/getting_started#tokens
       */
      const getTokenPromise = verificationService.webResource.getToken({
        requestBody: {
          site: {
            type: 'INET_DOMAIN',
            identifier: CUSTOMER_DOMAIN,
          },
          verificationMethod: 'DNS_TXT',
        }
      }).then(({data}) => {
        console.log(data);
        return data;
      });
    • Для типа SITE используйте один из следующих параметров verificationMethod :

      • FILE
      • META

      В следующем примере извлечения токена используется тип SITE с методом проверки FILE . При использовании типа проверки SITE необходимо добавить к идентификатору префикс http:// или https:// .

      Питон
      # Retrieve the site verification token and place it according to:
      # https://developers.google.com/site-verification/v1/getting_started#tokens
      response = verification_service.webResource().getToken(
          body={
              'site': {
                  'type': 'SITE',
                  'identifier': CUSTOMER_SITE
              },
              'verificationMethod': 'FILE'
          }).execute()
      print(response)
      Ява
      // Retrieve the site verification token and place it according to:
      // https://developers.google.com/site-verification/v1/getting_started#tokens
      SiteVerificationWebResourceGettokenRequest.Site getTokenSite =
          new SiteVerificationWebResourceGettokenRequest.Site()
              .setType("SITE")
              .setIdentifier(CUSTOMER_SITE);
      
      SiteVerificationWebResourceGettokenRequest request =
          new SiteVerificationWebResourceGettokenRequest()
              .setVerificationMethod("FILE")
              .setSite(getTokenSite);
      
      SiteVerificationWebResourceGettokenResponse getTokenResponse =
          verificationService.webResource().getToken(request).execute();
      System.out.println("Site Verification Token: " + getTokenResponse.getToken());
      С#
      // Retrieve the site verification token and place it according to:
      // https://developers.google.com/site-verification/v1/getting_started#tokens
      SiteVerificationWebResourceGettokenRequest.SiteData getTokenSite =
          new SiteVerificationWebResourceGettokenRequest.SiteData()
          {
              Type = "SITE",
              Identifier = CUSTOMER_SITE
          };
      
      SiteVerificationWebResourceGettokenRequest request =
          new SiteVerificationWebResourceGettokenRequest()
          {
              VerificationMethod = "FILE",
              Site = getTokenSite
          };
      
      SiteVerificationWebResourceGettokenResponse getTokenResponse =
          verificationService.WebResource.GetToken(request).Execute();
      Console.WriteLine("Site Verification Token: {0}", getTokenResponse.Token);
      PHP
      // Retrieve the site verification token and place it according to:
      // https://developers.google.com/site-verification/v1/getting_started#tokens
      $body =
      new Google_Service_SiteVerification_SiteVerificationWebResourceGettokenRequest([
        'verificationMethod' => 'FILE',
        'site' => [
          'type' => 'SITE',
          'identifier' => $CUSTOMER_DOMAIN
        ]
      ]);
      $response = $verificationService->webResource->getToken($body);
      print_r($response);
      Руби
      # Retrieve the site verification token and place it according to:
      # https://developers.google.com/site-verification/v1/getting_started#tokens
      request = Google::Apis::SiteVerificationV1::GetWebResourceTokenRequest.new(
        site: {
          type: 'SITE',
          identifier: CUSTOMER_SITE
        },
        verification_method: 'FILE'
      )
      
      response = verification_service.get_web_resource_token(request)
      puts response.inspect
      Node.js
      /**
       * Retrieve the site verification token and place it according to:
       * https://developers.google.com/site-verification/v1/getting_started#tokens
       */
      const getTokenPromise = verificationService.webResource.getToken({
        requestBody: {
          site: {
            type: 'SITE',
            identifier: CUSTOMER_SITE,
          },
          verificationMethod: 'FILE',
        }
      }).then(({data}) => {
        console.log(data);
        return data;
      });
  2. Поместите токен проверки сайта в запись DNS или на сайт .

Создайте клиента с помощью API реселлера

  1. Используйте метод Customers.Get , чтобы определить, существует ли клиент уже в Google Workspace:

    Питон
    # Determine if customer domain already has Google Workspace
    try:
      response = reseller_service.customers().get(
          customerId=CUSTOMER_DOMAIN).execute()
      print('Customer already exists if call succeeds')
      sys.exit()
    except HttpError as error:
      if int(error.resp['status']) == 404:
        print('Domain available for Google Workspace creation')
      else:
        raise
    Ява
    // Determine if customer domain already has Google Workspace
    try {
      resellerService.customers().get(CUSTOMER_DOMAIN).execute();
      System.out.println("Customer already exists if call succeeds");
      System.exit(0);
    } catch (HttpResponseException e) {
        if (e.getStatusCode() == 404) {
          System.out.println("Domain available for Google Workspace creation");
        } else { 
          throw e; 
        }
    }
    С#
    // Determine if customer domain already has Google Workspace
    try
    {
        resellerService.Customers.Get(CUSTOMER_DOMAIN).Execute();
        Console.WriteLine("Customer already exists if call succeeds");
        Environment.Exit(0);
    }
    catch (Google.GoogleApiException e) {
        if (e.Error.Code == 404)
        {
            Console.WriteLine("Domain available for Google Workspace creation");
        } else throw e;
    }
    PHP
    // Determine if customer domain already has Google Workspace
    try {
      $response = $resellerService->customers->get($CUSTOMER_DOMAIN);
      exit('Customer already exists if call succeeds');
    } catch(Google_Service_Exception $e) {
      if ($e->getErrors()[0]['reason'] == 'notFound'){
        print ("Domain available for Google Workspace creation\n");
      } else {
        throw $e;
      }
    }
    Руби
    # Determine if customer domain already has Google Workspace
    begin
      reseller_service.get_customer(CUSTOMER_DOMAIN)
      abort('Customer already exists if call succeeds')
    rescue Google::Apis::ClientError => ex
      if ex.status_code == 404
        puts 'Domain available for Google Workspace creation'
      else
        raise ex
      end
    end
    Node.js
    // Determine if customer domain already has Google Workspace
    const getCustomerPromise = resellerService.customers.get({
      customerId: CUSTOMER_DOMAIN
    }).then(() => {
      throw new Error('Customer already exists');
    }, resErr => {
      if (resErr.code === 404) {
        console.log('Domain available for Google Workspace creation');
      } else {
        throw resErr;
      }
    });
  2. В зависимости от ответа выполните следующие действия:

    • Если клиент не существует, метод customers.get возвращает код ошибки HTTP 404 Перейдите к следующему шагу — созданию записи клиента в Google Workspace.

    • Если метод customers.get возвращает результат без ошибок, проверьте, является ли клиент вашим, проверив свойство alternateEmail в теле ответа. Если свойство alternateEmail отсутствует, необходимо перенести клиента и его подписки .

  3. Создайте запись клиента в Google Workspace. Чтобы создавать подписки для этого клиента, необходимо создать запись клиента, следуя следующим рекомендациям:

    • alternateEmail не может находиться в том же домене, что и customerDomain .
    • Поле postalAddress.countryCode должно быть двухбуквенным кодом страны ISO.

    В следующем примере показано создание записи клиента:

    Питон
    # Create customer resource
    response = reseller_service.customers().insert(
        body={
            'customerDomain': CUSTOMER_DOMAIN,
            'alternateEmail': 'marty.mcfly@gmail.com',
            'postalAddress': {
                'contactName': 'Marty McFly',
                'organizationName': 'Acme Corp',
                'postalCode': '10009',
                'countryCode': 'US',
            }
        }).execute()
    print(response)
    Ява
    // Create customer resource
    Address address = new Address()
      .setContactName("Marty McFly")
      .setOrganizationName("Acme Corp")
      .setCountryCode("US")
      .setPostalCode("10009");
    
    Customer customer = new Customer()
      .setCustomerDomain(CUSTOMER_DOMAIN)
      .setAlternateEmail("marty.mcfly@gmail.com")
      .setPostalAddress(address);
    
    Customer customerResponse = resellerService.customers()
      .insert(customer).execute();
    System.out.println("Created Customer:\n" + customerResponse);
    С#
    // Create customer resource
    Address address = new Address()
    {
        ContactName = "Marty McFly",
        OrganizationName = "Acme Corp",
        CountryCode = "US",
        PostalCode = "10009"
    };
    
    Customer customer = new Customer()
    {
        CustomerDomain = CUSTOMER_DOMAIN,
        AlternateEmail = "marty.mcfly@gmail.com",
        PostalAddress = address
    };
    
    Customer customerResponse = resellerService.Customers.Insert(customer).Execute();
    Console.WriteLine("Created Customer:\n{0}", customerResponse);
    PHP
    // Create customer resource
    $customer = new Google_Service_Reseller_Customer([
      'customerDomain' => $CUSTOMER_DOMAIN,
      'alternateEmail' => 'marty.mcfly@gmail.com',
      'postalAddress' => [
        'contactName' => 'Marty McFly',
        'organizationName' => 'Acme Corp',
        'countryCode' => 'US',
        'postalCode' => '10009'
      ]
    ]);
    $response = $resellerService->customers->insert($customer);
    print_r ($response);
    Руби
    # Create customer resource
    customer = Google::Apis::ResellerV1::Customer.new(
      customer_domain: CUSTOMER_DOMAIN,
      alternate_email: 'marty.mcfly@gmail.com',
      postal_address: {
        contact_name: 'Marty McFly',
        organization_name: 'Acme Corp',
        country_code: 'US',
        postal_code: '10009'})
    
    response = reseller_service.insert_customer(customer)
    puts response.inspect
    Node.js
    // Create customer resource
    const insertCustomerPromise = resellerService.customers.insert({
      requestBody: {
        customerDomain: CUSTOMER_DOMAIN,
        alternateEmail: 'marty.mcfly@gmail.com',
        postalAddress: {
          contactName: 'Marty McFly',
          organizationName: 'Acme Corp',
          postalCode: '10009',
          countryCode: 'US',
        }
      }
    }).then(({data}) => {
      console.log(data);
      return data;
    });

Создайте первого пользователя-администратора с помощью API Admin SDK

После регистрации клиента необходимо создать первого пользователя и немедленно повысить его до уровня суперадминистратора домена, чтобы клиент мог получить доступ к новым услугам и принять все применимые Условия обслуживания.

  1. Создайте первого пользователя и задайте ему пароль. Пароли должны быть достаточно сложными и содержать не менее восьми символов. Подробнее см. в разделе « user .

    Питон
    # Create first admin user
    response = directory_service.users().insert(
        body={
            'primaryEmail': 'marty.mcfly@' + CUSTOMER_DOMAIN,
            'name': {
                'givenName': 'Marty',
                'familyName': 'McFly',
            },
            'password': 'Timecircuit88'
        }).execute()
    print(response)
    Ява
    // Create first admin user
    String userEmail = "marty.mcfly@" + CUSTOMER_DOMAIN;
    
    UserName name = new UserName();
    name.setGivenName("Marty");
    name.setFamilyName("McFly");
    
    User user = new User();
    user.setPrimaryEmail(userEmail);
    user.setPassword("TimeCircuit88");
    user.setName(name);
    
    User userResponse = directoryService.users().insert(user).execute();
    System.out.println("Created User:\n" + userResponse);
    С#
    // Create first admin user
    String userEmail = "marty.mcfly@" + CUSTOMER_DOMAIN;
    
    UserName name = new UserName()
    {
        GivenName = "Marty",
        FamilyName = "McFly"
    };
    
    User user = new User()
    {
        PrimaryEmail = userEmail,
        Password = "TimeCircuit88",
        Name = name
    };
    
    User userResponse = directoryService.Users.Insert(user).Execute();
    Console.WriteLine("Created User:\n{0}", userResponse);
    PHP
    // Create first admin user
    $user = new Google_Service_Directory_User([
      'primaryEmail' => 'marty.mcfly@' . $CUSTOMER_DOMAIN,
      'password' => 'Timecircuit88',
      'name' => [
        'givenName' => 'Marty',
        'familyName' => 'McFly',
        'fullName' => 'Marty McFly'
      ]
    ]);
    $response = $directoryService->users->insert($user);
    print_r ($response);
    Руби
    # Create first admin user
    user = Google::Apis::AdminDirectoryV1::User.new(
      name: {
        given_name: 'Marty',
        family_name: 'McFly',
        full_name: 'Marty McFly'
      },
      password: 'Timecircuit88',
      primary_email: 'marty.mcfly@' + CUSTOMER_DOMAIN,
    )
    
    response = directory_service.insert_user(user)
    puts response.inspect
    Node.js
    // Create first admin user
    const insertUserPromise = directoryService.users.insert({
      requestBody: {
        primaryEmail: `marty.mcfly@${CUSTOMER_DOMAIN}`,
        name: {
          givenName: 'Marty',
          familyName: 'McFly',
        },
        password: 'Timecircuit88',
      }
    }).then(({data}) => {
      console.log(data);
      return data;
    });

    Если вызов для создания пользователя возвращает HTTP 409 , возможно, имя пользователя уже существует в качестве учетной записи Google потребителя.

  2. Повысьте уровень пользователя до роли суперадминистратора:

    Питон
    # Promote user to admin status
    response = directory_service.users().makeAdmin(
        userKey='marty.mcfly@' + CUSTOMER_DOMAIN, body={
            'status': True
        }).execute()
    Ява
    // Promote user to admin status
    UserMakeAdmin admin = new UserMakeAdmin();
    admin.setStatus(true);
    
    directoryService.users().makeAdmin(userEmail, admin).execute();
    System.out.println("User promoted to Admin");
    С#
    // Promote user to admin status
    UserMakeAdmin admin = new UserMakeAdmin()
    {
        Status = true
    };
    directoryService.Users.MakeAdmin(admin, userEmail).Execute();
    Console.WriteLine("User promoted to Admin");
    PHP
    // Promote user to admin status
    $makeAdmin = new Google_Service_Directory_UserMakeAdmin([
      'status' => true
    ]);
    $directoryService->users->makeAdmin(
      'marty.mcfly@' . $CUSTOMER_DOMAIN,
      $makeAdmin
    );
    Руби
    # Promote user to admin status
    admin_status = Google::Apis::AdminDirectoryV1::UserMakeAdmin.new(
      status: true
    )
    
    response = directory_service.make_user_admin('marty.mcfly@' + CUSTOMER_DOMAIN, admin_status)
    Node.js
    // Promote user to admin status
    const makeAdminPromise = directoryService.users.makeAdmin({
      userKey: `marty.mcfly@${CUSTOMER_DOMAIN}`,
      requestBody: {
        status: true
      }
    });

Создайте подписку Google Workspace для клиента

При создании подписки для клиента необходимо указать внутренний идентификатор транзакции или идентификатор этого клиента в поле purchaseOrderId . Подробнее о конкретных аргументах и ​​значениях см. в разделе Управление подписками .

  1. Чтобы создать подписку, используйте вызов Subscriptions.Insert . В следующем примере используется подписка ANNUAL_YEARLY_PAY :

    Питон
    # Create subscription resource
    response = reseller_service.subscriptions().insert(
        customerId=CUSTOMER_DOMAIN,
        body={
            'customerId': CUSTOMER_DOMAIN,
            'skuId': '1010020027',
            'plan': {
                'planName': 'ANNUAL_MONTHLY_PAY',
            },
            'seats': {
                'numberOfSeats': 5,
            },
            'renewalSettings': {  # only relevant for annual plans
                'renewalType': 'RENEW_CURRENT_USERS_MONTHLY_PAY'
            }
        }).execute()
    print(response)
    Ява
    // Create subscription resource
    Seats seats = new Seats()
      .setNumberOfSeats(5);
    
    Subscription.Plan plan = new Subscription.Plan()
      .setPlanName("ANNUAL_YEARLY_PAY");
    
    RenewalSettings renewalSettings = new RenewalSettings()
      .setRenewalType("RENEW_CURRENT_USERS_MONTHLY_PAY");
    
    Subscription subscription = new Subscription()
      .setCustomerId(CUSTOMER_DOMAIN)
      .setSeats(seats)
      .setPlan(plan)
      .setSkuId("1010020027")
      .setRenewalSettings(renewalSettings);
    
    Subscription subscriptionResponse = resellerService.subscriptions()
      .insert(CUSTOMER_DOMAIN, subscription).execute();
    System.out.println("Created Subscription:\n" + subscriptionResponse);
    С#
    // Create subscription resource
    Seats seats = new Seats()
    {
        NumberOfSeats = 5
    };
    
    Subscription.PlanData plan = new Subscription.PlanData()
    {
        PlanName = "ANNUAL_YEARLY_PAY"
    };
    
    RenewalSettings renewalSettings = new RenewalSettings()
    {
        RenewalType = "RENEW_CURRENT_USERS_MONTHLY_PAY"
    };
    
    Subscription subscription = new Subscription()
    {
        CustomerId = CUSTOMER_DOMAIN,
        Seats = seats,
        Plan = plan,
        SkuId = "1010020027",
        RenewalSettings = renewalSettings
    };
    
    Subscription subscriptionResponse = resellerService.Subscriptions
        .Insert(subscription, CUSTOMER_DOMAIN).Execute();
    Console.WriteLine("Created Subscription:\n" + subscriptionResponse);
    PHP
    // Create subscription resource
    $subscription = new Google_Service_Reseller_Subscription([
      'customerId' => $CUSTOMER_DOMAIN,
      'skuId' => '1010020027',
      'plan' => [
        'planName' => 'ANNUAL_MONTHLY_PAY'
      ],
      'seats' => [
        'numberOfSeats' => '5'
      ],
      'renewalSettings' => [
        'renewalType' => 'RENEW_CURRENT_USERS_MONTHLY_PAY'
      ]
    ]);
    $response = $resellerService->subscriptions->insert(
      $CUSTOMER_DOMAIN,
      $subscription
    );
    print_r ($response);
    Руби
    # Create subscription resource
    subscription = Google::Apis::ResellerV1::Subscription.new(
      customer_id: CUSTOMER_DOMAIN,
      sku_id: '1010020027',
      plan: {
        plan_name: 'ANNUAL_MONTHLY_PAY'
      },
      seats: {
        number_of_seats: 5,
      },
      renewal_settings: {
        renewal_type: 'RENEW_CURRENT_USERS_MONTHLY_PAY'
      }
    )
    
    response = reseller_service.insert_subscription(CUSTOMER_DOMAIN, subscription)
    puts response.inspect
    Node.js
    // Create subscription resource
    const insertSubscriptionPromise = resellerService.subscriptions.insert({
      customerId: CUSTOMER_DOMAIN,
      requestBody: {
        customerId: CUSTOMER_DOMAIN,
        skuId: '1010020027',
        plan: {
          planName: 'ANNUAL_MONTHLY_PAY',
        },
        seats: {
          numberOfSeats: 5,
        },
        renewalSettings: { // only relevant for annual plans
          renewalType: 'RENEW_CURRENT_USERS_MONTHLY_PAY',
        }
      }
    }).then(({data}) => {
      console.log(data);
      return data;
    });
  2. Подписки находятся в состоянии SUSPENDED до тех пор, пока администратор клиента не войдет в систему и не примет Условия обслуживания. Администраторы клиентов перенаправляются на страницу Условий обслуживания при первом входе в систему при доступе к любому сервису Google (например, Gmail или Google Диску).

Подтвердите домен и назначьте владельцев домена

Этот шаг необязателен, но рекомендуется, если у вас есть возможность проверить домен клиента. Вызов API проверки сайта webResource.insert() проверяет домен и назначает ему владельцев, указанных в параметре owners[] тела запроса.

В следующем примере показано, как проверить INET_DOMAIN :

Питон
# Verify domain and designate domain owners
response = verification_service.webResource().insert(
    verificationMethod='DNS_TXT',
    body={
        'site': {
            'type': 'INET_DOMAIN',
            'identifier': CUSTOMER_DOMAIN
        },
        'owners': ['marty.mcfly@' + CUSTOMER_DOMAIN]
    }).execute()
print(response)
Ява
// Verify domain and designate domain owners
SiteVerificationWebResourceResource.Site verifySite =
      new SiteVerificationWebResourceResource.Site()
            .setIdentifier(CUSTOMER_DOMAIN)
            .setType("INET_DOMAIN");

List<String> owners = Arrays.asList(userEmail);

SiteVerificationWebResourceResource resource =
  new SiteVerificationWebResourceResource()
        .setSite(verifySite)
        .setOwners(owners);

SiteVerificationWebResourceResource verifyResponse = 
  verificationService.webResource().insert("DNS_TXT", resource).execute();
System.out.println("Site Verification Web Resource:\n" + verifyResponse);
С#
// Verify domain and designate domain owners
SiteVerificationWebResourceResource.SiteData verifySite =
      new SiteVerificationWebResourceResource.SiteData()
      {
          Identifier = CUSTOMER_DOMAIN,
          Type = "INET_DOMAIN"
      };

string[] owners = { userEmail };

SiteVerificationWebResourceResource resource =
  new SiteVerificationWebResourceResource()
  {
      Site = verifySite,
      Owners = owners
  };

SiteVerificationWebResourceResource verifyResponse =
    verificationService.WebResource.Insert(resource, "DNS_TXT").Execute();
Console.WriteLine("Site Verification Web Resource:\n" + verifyResponse);
PHP
// Verify domain and designate domain owners
$body =
new Google_Service_SiteVerification_SiteVerificationWebResourceResource([
  'site' => [
    'type' => 'INET_DOMAIN',
    'identifier' => $CUSTOMER_DOMAIN,
  ],
  'owners' => ['marty.mcfly@' . $CUSTOMER_DOMAIN]
]);

$response = $verificationService->webResource->insert('DNS_TXT', $body);
print_r ($response);
Руби
# Verify domain and designate domain owners
webResource = Google::Apis::SiteVerificationV1::SiteVerificationWebResourceResource.new(
  site: {
    type: 'INET_DOMAIN',
    identifier: CUSTOMER_DOMAIN
  },
  owners: ['marty.mcfly@' + CUSTOMER_DOMAIN]
)

response = verification_service.insert_web_resource('DNS_TXT', webResource)
puts response.inspect
Node.js
// Verify domain and designate domain owners
const verifyDomainPromise = verificationService.webResource.insert({
  verificationMethod: 'DNS_TXT',
  requestBody: {
    site: {
      type: 'INET_DOMAIN',
      identifier: CUSTOMER_DOMAIN,
    },
    owners: [`marty.mcfly@${CUSTOMER_DOMAIN}`],
  }
}).then(({data}) => {
  console.log(data);
  return data;
});

В случае успеха этот вызов возвращает код HTTP 200 Если webResource.insert() не может проверить домен, он возвращает код ошибки уровня HTTP 400 Повторите вызов webResource.insert() с задержкой, пока домен не будет успешно проверен.

Соедини все это вместе

В следующем примере показан полный код для подготовки клиента Google Workspace:

Питон
"""This is a basic example of provisioning a Google Workspace customer.
"""
import sys
from apiclient.discovery import build
from apiclient.http import HttpError
from oauth2client.service_account import ServiceAccountCredentials

############## REPLACE WITH YOUR OWN VALUES ####################
JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json'
RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com'
CUSTOMER_DOMAIN = 'example.com'
CUSTOMER_SITE = 'https://www.example.com'
################################################################

# Full List of scopes:
# https://developers.google.com/identity/protocols/googlescopes
OAUTH2_SCOPES = [
    'https://reseller.googleapis.com/auth/apps.order',
    'https://reseller.googleapis.com/auth/siteverification',
    'https://reseller.googleapis.com/auth/admin.directory.user',
]

credentials = ServiceAccountCredentials.from_json_keyfile_name(
    JSON_PRIVATE_KEY_FILE, OAUTH2_SCOPES).create_delegated(RESELLER_ADMIN_USER)

reseller_service = build(
    serviceName='reseller', version='v1', credentials=credentials)

directory_service = build(
    serviceName='admin', version='directory_v1', credentials=credentials)

verification_service = build(
    serviceName='siteVerification', version='v1', credentials=credentials)

# Retrieve the site verification token and place it according to:
# https://developers.google.com/site-verification/v1/getting_started#tokens
response = verification_service.webResource().getToken(
    body={
        'site': {
            'type': 'INET_DOMAIN',
            'identifier': CUSTOMER_DOMAIN
        },
        'verificationMethod': 'DNS_TXT'
    }).execute()
print(response)

# Determine if customer domain already has Google Workspace
try:
  response = reseller_service.customers().get(
      customerId=CUSTOMER_DOMAIN).execute()
  print('Customer already exists if call succeeds')
  sys.exit()
except HttpError as error:
  if int(error.resp['status']) == 404:
    print('Domain available for Google Workspace creation')
  else:
    raise

# Create customer resource
response = reseller_service.customers().insert(
    body={
        'customerDomain': CUSTOMER_DOMAIN,
        'alternateEmail': 'marty.mcfly@gmail.com',
        'postalAddress': {
            'contactName': 'Marty McFly',
            'organizationName': 'Acme Corp',
            'postalCode': '10009',
            'countryCode': 'US',
        }
    }).execute()
print(response)

# Create first admin user
response = directory_service.users().insert(
    body={
        'primaryEmail': 'marty.mcfly@' + CUSTOMER_DOMAIN,
        'name': {
            'givenName': 'Marty',
            'familyName': 'McFly',
        },
        'password': 'Timecircuit88'
    }).execute()
print(response)

# Promote user to admin status
response = directory_service.users().makeAdmin(
    userKey='marty.mcfly@' + CUSTOMER_DOMAIN, body={
        'status': True
    }).execute()

# Create subscription resource
response = reseller_service.subscriptions().insert(
    customerId=CUSTOMER_DOMAIN,
    body={
        'customerId': CUSTOMER_DOMAIN,
        'skuId': '1010020027',
        'plan': {
            'planName': 'ANNUAL_MONTHLY_PAY',
        },
        'seats': {
            'numberOfSeats': 5,
        },
        'renewalSettings': {  # only relevant for annual plans
            'renewalType': 'RENEW_CURRENT_USERS_MONTHLY_PAY'
        }
    }).execute()
print(response)

# Verify domain and designate domain owners
response = verification_service.webResource().insert(
    verificationMethod='DNS_TXT',
    body={
        'site': {
            'type': 'INET_DOMAIN',
            'identifier': CUSTOMER_DOMAIN
        },
        'owners': ['marty.mcfly@' + CUSTOMER_DOMAIN]
    }).execute()
print(response)
Ява
// OAuth2 and HTTP
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.json.jackson2.JacksonFactory;
// Directory API
import com.google.api.services.admin.directory.Directory;
import com.google.api.services.admin.directory.DirectoryScopes;
import com.google.api.services.admin.directory.model.User;
import com.google.api.services.admin.directory.model.UserMakeAdmin;
import com.google.api.services.admin.directory.model.UserName;
// Reseller API
import com.google.api.services.reseller.Reseller;
import com.google.api.services.reseller.ResellerScopes;
import com.google.api.services.reseller.model.Address;
import com.google.api.services.reseller.model.Customer;
import com.google.api.services.reseller.model.RenewalSettings;
import com.google.api.services.reseller.model.Seats;
import com.google.api.services.reseller.model.Subscription;
// Site Verification API
import com.google.api.services.siteVerification.SiteVerification;
import com.google.api.services.siteVerification.SiteVerificationScopes;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceGettokenRequest;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceGettokenResponse;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceResource;
// Java library imports
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;

/**
 * This is a basic example of provisioning a Google Workspace customer.
 */
public class CodelabExample {
  // Full List of scopes:
  // https://developers.google.com/identity/protocols/googlescopes
  private static final List<String> OAUTH2_SCOPES = Arrays.asList(
    ResellerScopes.APPS_ORDER,
    SiteVerificationScopes.SITEVERIFICATION,
    DirectoryScopes.ADMIN_DIRECTORY_USER
  );

  /***************** REPLACE WITH YOUR OWN VALUES ********************************/
  public static final String JSON_PRIVATE_KEY_FILE = "path/to/json_key_file.json";
  public static final String RESELLER_ADMIN_USER = "admin@yourresellerdomain.com";
  public static final String CUSTOMER_DOMAIN = "example.com";
  public static final String CUSTOMER_SITE = "https://www.example.com/";
  /*******************************************************************************/

  public static void main(String[] args)
      throws IOException, GeneralSecurityException, FileNotFoundException {
    // Instantiate services with authenticated credentials
    GoogleCredential jsonCredentials = GoogleCredential
      .fromStream(new FileInputStream(JSON_PRIVATE_KEY_FILE));
    GoogleCredential credentials = new GoogleCredential.Builder()
      .setTransport(GoogleNetHttpTransport.newTrustedTransport())
      .setJsonFactory(JacksonFactory.getDefaultInstance())
      .setServiceAccountScopes(OAUTH2_SCOPES)
      .setServiceAccountUser(RESELLER_ADMIN_USER)
      .setServiceAccountPrivateKey(jsonCredentials.getServiceAccountPrivateKey())
      .setServiceAccountId(jsonCredentials.getServiceAccountId())
      .build();

    Reseller resellerService = new Reseller.Builder(
        credentials.getTransport(),
        credentials.getJsonFactory(),
        credentials).setApplicationName("Google Workspace Creator").build();

    Directory directoryService = new Directory.Builder(
        credentials.getTransport(),
        credentials.getJsonFactory(),
        credentials).setApplicationName("Google Workspace Creator").build();

    SiteVerification verificationService = new SiteVerification.Builder(
        credentials.getTransport(),
        credentials.getJsonFactory(),
        credentials).setApplicationName("Google Workspace Creator").build();

    // Retrieve the site verification token and place it according to:
    // https://developers.google.com/site-verification/v1/getting_started#tokens
    SiteVerificationWebResourceGettokenRequest.Site getTokenSite =
        new SiteVerificationWebResourceGettokenRequest.Site()
            .setType("INET_DOMAIN")
            .setIdentifier(CUSTOMER_DOMAIN);

    SiteVerificationWebResourceGettokenRequest request =
        new SiteVerificationWebResourceGettokenRequest()
            .setVerificationMethod("DNS_TXT")
            .setSite(getTokenSite);

    SiteVerificationWebResourceGettokenResponse getTokenResponse =
        verificationService.webResource().getToken(request).execute();
    System.out.println("Site Verification Token: " + getTokenResponse.getToken());

    // Determine if customer domain already has Google Workspace
    try {
      resellerService.customers().get(CUSTOMER_DOMAIN).execute();
      System.out.println("Customer already exists if call succeeds");
      System.exit(0);
    } catch (HttpResponseException e) {
        if (e.getStatusCode() == 404) {
          System.out.println("Domain available for Google Workspace creation");
        } else { 
          throw e; 
        }
    }

    // Create customer resource
    Address address = new Address()
      .setContactName("Marty McFly")
      .setOrganizationName("Acme Corp")
      .setCountryCode("US")
      .setPostalCode("10009");

    Customer customer = new Customer()
      .setCustomerDomain(CUSTOMER_DOMAIN)
      .setAlternateEmail("marty.mcfly@gmail.com")
      .setPostalAddress(address);

    Customer customerResponse = resellerService.customers()
      .insert(customer).execute();
    System.out.println("Created Customer:\n" + customerResponse);

    // Create first admin user
    String userEmail = "marty.mcfly@" + CUSTOMER_DOMAIN;

    UserName name = new UserName();
    name.setGivenName("Marty");
    name.setFamilyName("McFly");

    User user = new User();
    user.setPrimaryEmail(userEmail);
    user.setPassword("TimeCircuit88");
    user.setName(name);

    User userResponse = directoryService.users().insert(user).execute();
    System.out.println("Created User:\n" + userResponse);

    // Promote user to admin status
    UserMakeAdmin admin = new UserMakeAdmin();
    admin.setStatus(true);

    directoryService.users().makeAdmin(userEmail, admin).execute();
    System.out.println("User promoted to Admin");

    // Create subscription resource
    Seats seats = new Seats()
      .setNumberOfSeats(5);

    Subscription.Plan plan = new Subscription.Plan()
      .setPlanName("ANNUAL_YEARLY_PAY");

    RenewalSettings renewalSettings = new RenewalSettings()
      .setRenewalType("RENEW_CURRENT_USERS_MONTHLY_PAY");

    Subscription subscription = new Subscription()
      .setCustomerId(CUSTOMER_DOMAIN)
      .setSeats(seats)
      .setPlan(plan)
      .setSkuId("1010020027")
      .setRenewalSettings(renewalSettings);

    Subscription subscriptionResponse = resellerService.subscriptions()
      .insert(CUSTOMER_DOMAIN, subscription).execute();
    System.out.println("Created Subscription:\n" + subscriptionResponse);

    // Verify domain and designate domain owners
    SiteVerificationWebResourceResource.Site verifySite =
          new SiteVerificationWebResourceResource.Site()
                .setIdentifier(CUSTOMER_DOMAIN)
                .setType("INET_DOMAIN");

    List<String> owners = Arrays.asList(userEmail);

    SiteVerificationWebResourceResource resource =
      new SiteVerificationWebResourceResource()
            .setSite(verifySite)
            .setOwners(owners);

    SiteVerificationWebResourceResource verifyResponse = 
      verificationService.webResource().insert("DNS_TXT", resource).execute();
    System.out.println("Site Verification Web Resource:\n" + verifyResponse);
  }
}
С#
// OAuth2 and HTTP
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
// Reseller API
using Google.Apis.Reseller.v1;
using Google.Apis.Reseller.v1.Data;
// Directory API
using Google.Apis.Admin.Directory.directory_v1;
using User = Google.Apis.Admin.Directory.directory_v1.Data.User;
using UserName = Google.Apis.Admin.Directory.directory_v1.Data.UserName;
using UserMakeAdmin = Google.Apis.Admin.Directory.directory_v1.Data.UserMakeAdmin;
//Site Verification API
using Google.Apis.SiteVerification.v1;
using Google.Apis.SiteVerification.v1.Data;
// System imports
using System;
using System.IO;

class CodelabExample
{
    // Full List of scopes:
    // https://developers.google.com/identity/protocols/googlescopes
    static string[] OAUTH2_SCOPES = {
        ResellerService.Scope.AppsOrder,
        DirectoryService.Scope.AdminDirectoryUser,
        SiteVerificationService.Scope.Siteverification
    };

    /***************** REPLACE WITH YOUR OWN VALUES ********************************/
    public static String JSON_PRIVATE_KEY_FILE = "path/to/json_key_file.json";
    public static String RESELLER_ADMIN_USER = "admin@yourresellerdomain.com";
    public static String CUSTOMER_DOMAIN = "example.com";
    public static String CUSTOMER_SITE = "https://www.example.com/";
    /*******************************************************************************/

    static void Main(string[] args)
    {
        GoogleCredential credential;

        using (var stream = new FileStream(JSON_PRIVATE_KEY_FILE, FileMode.Open, FileAccess.Read))
        {
            credential = GoogleCredential
                .FromStream(stream)
                .CreateScoped(OAUTH2_SCOPES)
                .CreateWithUser(RESELLER_ADMIN_USER);
        }

        var resellerService = new ResellerService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
        });

        var directoryService = new DirectoryService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
        });

        var verificationService = new SiteVerificationService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
        });

        // Retrieve the site verification token and place it according to:
        // https://developers.google.com/site-verification/v1/getting_started#tokens
        SiteVerificationWebResourceGettokenRequest.SiteData getTokenSite =
            new SiteVerificationWebResourceGettokenRequest.SiteData()
            {
                Type = "INET_DOMAIN",
                Identifier = CUSTOMER_DOMAIN
            };

        SiteVerificationWebResourceGettokenRequest request =
            new SiteVerificationWebResourceGettokenRequest()
            {
                VerificationMethod = "DNS_TXT",
                Site = getTokenSite
            };

        SiteVerificationWebResourceGettokenResponse getTokenResponse =
            verificationService.WebResource.GetToken(request).Execute();
        Console.WriteLine("Site Verification Token: {0}", getTokenResponse.Token);

        // Determine if customer domain already has Google Workspace
        try
        {
            resellerService.Customers.Get(CUSTOMER_DOMAIN).Execute();
            Console.WriteLine("Customer already exists if call succeeds");
            Environment.Exit(0);
        }
        catch (Google.GoogleApiException e) {
            if (e.Error.Code == 404)
            {
                Console.WriteLine("Domain available for Google Workspace creation");
            } else throw e;
        }

        // Create customer resource
        Address address = new Address()
        {
            ContactName = "Marty McFly",
            OrganizationName = "Acme Corp",
            CountryCode = "US",
            PostalCode = "10009"
        };

        Customer customer = new Customer()
        {
            CustomerDomain = CUSTOMER_DOMAIN,
            AlternateEmail = "marty.mcfly@gmail.com",
            PostalAddress = address
        };

        Customer customerResponse = resellerService.Customers.Insert(customer).Execute();
        Console.WriteLine("Created Customer:\n{0}", customerResponse);

        // Create first admin user
        String userEmail = "marty.mcfly@" + CUSTOMER_DOMAIN;

        UserName name = new UserName()
        {
            GivenName = "Marty",
            FamilyName = "McFly"
        };

        User user = new User()
        {
            PrimaryEmail = userEmail,
            Password = "TimeCircuit88",
            Name = name
        };

        User userResponse = directoryService.Users.Insert(user).Execute();
        Console.WriteLine("Created User:\n{0}", userResponse);

        // Promote user to admin status
        UserMakeAdmin admin = new UserMakeAdmin()
        {
            Status = true
        };
        directoryService.Users.MakeAdmin(admin, userEmail).Execute();
        Console.WriteLine("User promoted to Admin");

        // Create subscription resource
        Seats seats = new Seats()
        {
            NumberOfSeats = 5
        };

        Subscription.PlanData plan = new Subscription.PlanData()
        {
            PlanName = "ANNUAL_YEARLY_PAY"
        };

        RenewalSettings renewalSettings = new RenewalSettings()
        {
            RenewalType = "RENEW_CURRENT_USERS_MONTHLY_PAY"
        };

        Subscription subscription = new Subscription()
        {
            CustomerId = CUSTOMER_DOMAIN,
            Seats = seats,
            Plan = plan,
            SkuId = "1010020027",
            RenewalSettings = renewalSettings
        };

        Subscription subscriptionResponse = resellerService.Subscriptions
            .Insert(subscription, CUSTOMER_DOMAIN).Execute();
        Console.WriteLine("Created Subscription:\n" + subscriptionResponse);

        // Verify domain and designate domain owners
        SiteVerificationWebResourceResource.SiteData verifySite =
              new SiteVerificationWebResourceResource.SiteData()
              {
                  Identifier = CUSTOMER_DOMAIN,
                  Type = "INET_DOMAIN"
              };

        string[] owners = { userEmail };

        SiteVerificationWebResourceResource resource =
          new SiteVerificationWebResourceResource()
          {
              Site = verifySite,
              Owners = owners
          };

        SiteVerificationWebResourceResource verifyResponse =
            verificationService.WebResource.Insert(resource, "DNS_TXT").Execute();
        Console.WriteLine("Site Verification Web Resource:\n" + verifyResponse);
    }
}
PHP
// https://developers.google.com/api-client-library/php/
require_once 'vendor/autoload.php';

// Full List of scopes:
// https://developers.google.com/identity/protocols/googlescopes
$OAUTH2_SCOPES = [
  Google_Service_Reseller::APPS_ORDER,
  Google_Service_SiteVerification::SITEVERIFICATION,
  Google_Service_Directory::ADMIN_DIRECTORY_USER,
];

######### REPLACE WITH YOUR OWN VALUES ###############
$JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json';
$RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com';
$CUSTOMER_DOMAIN = 'example.com';
$CUSTOMER_SITE = 'https://www.example.com/';
######################################################

$client = new Google_Client();
$client->setAuthConfig($JSON_PRIVATE_KEY_FILE);
$client->setSubject($RESELLER_ADMIN_USER);
$client->setScopes($OAUTH2_SCOPES);

$resellerService = new Google_Service_Reseller($client);
$directoryService = new Google_Service_Directory($client);
$verificationService = new Google_Service_SiteVerification($client);

// Retrieve the site verification token and place it according to:
// https://developers.google.com/site-verification/v1/getting_started#tokens
$body =
new Google_Service_SiteVerification_SiteVerificationWebResourceGettokenRequest([
  'verificationMethod' => 'DNS_TXT',
  'site' => [
    'type' => 'INET_DOMAIN',
    'identifier' => $CUSTOMER_DOMAIN
  ]
]);
$response = $verificationService->webResource->getToken($body);
print_r ($response);

// Determine if customer domain already has Google Workspace
try {
  $response = $resellerService->customers->get($CUSTOMER_DOMAIN);
  exit('Customer already exists if call succeeds');
} catch(Google_Service_Exception $e) {
  if ($e->getErrors()[0]['reason'] == 'notFound'){
    print ("Domain available for Google Workspace creation\n");
  } else {
    throw $e;
  }
}

// Create customer resource
$customer = new Google_Service_Reseller_Customer([
  'customerDomain' => $CUSTOMER_DOMAIN,
  'alternateEmail' => 'marty.mcfly@gmail.com',
  'postalAddress' => [
    'contactName' => 'Marty McFly',
    'organizationName' => 'Acme Corp',
    'countryCode' => 'US',
    'postalCode' => '10009'
  ]
]);
$response = $resellerService->customers->insert($customer);
print_r ($response);

// Create first admin user
$user = new Google_Service_Directory_User([
  'primaryEmail' => 'marty.mcfly@' . $CUSTOMER_DOMAIN,
  'password' => 'Timecircuit88',
  'name' => [
    'givenName' => 'Marty',
    'familyName' => 'McFly',
    'fullName' => 'Marty McFly'
  ]
]);
$response = $directoryService->users->insert($user);
print_r ($response);

// Promote user to admin status
$makeAdmin = new Google_Service_Directory_UserMakeAdmin([
  'status' => true
]);
$directoryService->users->makeAdmin(
  'marty.mcfly@' . $CUSTOMER_DOMAIN,
  $makeAdmin
);

// Create subscription resource
$subscription = new Google_Service_Reseller_Subscription([
  'customerId' => $CUSTOMER_DOMAIN,
  'skuId' => '1010020027',
  'plan' => [
    'planName' => 'ANNUAL_MONTHLY_PAY'
  ],
  'seats' => [
    'numberOfSeats' => '5'
  ],
  'renewalSettings' => [
    'renewalType' => 'RENEW_CURRENT_USERS_MONTHLY_PAY'
  ]
]);
$response = $resellerService->subscriptions->insert(
  $CUSTOMER_DOMAIN,
  $subscription
);
print_r ($response);

// Verify domain and designate domain owners
$body =
new Google_Service_SiteVerification_SiteVerificationWebResourceResource([
  'site' => [
    'type' => 'INET_DOMAIN',
    'identifier' => $CUSTOMER_DOMAIN,
  ],
  'owners' => ['marty.mcfly@' . $CUSTOMER_DOMAIN]
]);

$response = $verificationService->webResource->insert('DNS_TXT', $body);
print_r ($response);
Руби
require 'googleauth'
require 'google/apis/reseller_v1'
require 'google/apis/site_verification_v1'
require 'google/apis/admin_directory_v1'

# Full List of scopes:
# https://developers.google.com/identity/protocols/googlescopes
OAUTH2_SCOPES = [
  'https://reseller.googleapis.com/auth/apps.order',
  'https://reseller.googleapis.com/auth/admin.directory.user',
  'https://reseller.googleapis.com/auth/siteverification',
]

####### REPLACE WITH YOUR OWN VALUES ###############
JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json'
RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com'
CUSTOMER_DOMAIN = 'example.com'
CUSTOMER_SITE = 'https://www.example.com/'
####################################################

credentials = Google::Auth::ServiceAccountCredentials.make_creds(
  json_key_io: File.open(JSON_PRIVATE_KEY_FILE),
  scope: OAUTH2_SCOPES)
credentials.sub = RESELLER_ADMIN_USER

Google::Apis::RequestOptions.default.authorization = credentials

reseller_service = Google::Apis::ResellerV1::ResellerService.new
directory_service = Google::Apis::AdminDirectoryV1::DirectoryService.new
verification_service = Google::Apis::SiteVerificationV1::SiteVerificationService.new

# Retrieve the site verification token and place it according to:
# https://developers.google.com/site-verification/v1/getting_started#tokens
request = Google::Apis::SiteVerificationV1::GetWebResourceTokenRequest.new(
  site: {
    type: 'INET_DOMAIN',
    identifier: CUSTOMER_DOMAIN
  },
  verification_method: 'DNS_TXT'
)

response = verification_service.get_web_resource_token(request)
puts response.inspect

# Determine if customer domain already has Google Workspace
begin
  reseller_service.get_customer(CUSTOMER_DOMAIN)
  abort('Customer already exists if call succeeds')
rescue Google::Apis::ClientError => ex
  if ex.status_code == 404
    puts 'Domain available for Google Workspace creation'
  else
    raise ex
  end
end

# Create customer resource
customer = Google::Apis::ResellerV1::Customer.new(
  customer_domain: CUSTOMER_DOMAIN,
  alternate_email: 'marty.mcfly@gmail.com',
  postal_address: {
    contact_name: 'Marty McFly',
    organization_name: 'Acme Corp',
    country_code: 'US',
    postal_code: '10009'})

response = reseller_service.insert_customer(customer)
puts response.inspect

# Create first admin user
user = Google::Apis::AdminDirectoryV1::User.new(
  name: {
    given_name: 'Marty',
    family_name: 'McFly',
    full_name: 'Marty McFly'
  },
  password: 'Timecircuit88',
  primary_email: 'marty.mcfly@' + CUSTOMER_DOMAIN,
)

response = directory_service.insert_user(user)
puts response.inspect

# Promote user to admin status
admin_status = Google::Apis::AdminDirectoryV1::UserMakeAdmin.new(
  status: true
)

response = directory_service.make_user_admin('marty.mcfly@' + CUSTOMER_DOMAIN, admin_status)

# Create subscription resource
subscription = Google::Apis::ResellerV1::Subscription.new(
  customer_id: CUSTOMER_DOMAIN,
  sku_id: '1010020027',
  plan: {
    plan_name: 'ANNUAL_MONTHLY_PAY'
  },
  seats: {
    number_of_seats: 5,
  },
  renewal_settings: {
    renewal_type: 'RENEW_CURRENT_USERS_MONTHLY_PAY'
  }
)

response = reseller_service.insert_subscription(CUSTOMER_DOMAIN, subscription)
puts response.inspect

# Verify domain and designate domain owners
webResource = Google::Apis::SiteVerificationV1::SiteVerificationWebResourceResource.new(
  site: {
    type: 'INET_DOMAIN',
    identifier: CUSTOMER_DOMAIN
  },
  owners: ['marty.mcfly@' + CUSTOMER_DOMAIN]
)

response = verification_service.insert_web_resource('DNS_TXT', webResource)
puts response.inspect
Node.js
// NOTE: This script needs googleapis 28.0.0 or later as it uses promises
const {google} = require('googleapis');

// ############## REPLACE WITH YOUR OWN VALUES ####################
const JSON_PRIVATE_KEY_FILE = 'path/to/json_key_file.json';
const RESELLER_ADMIN_USER = 'admin@yourresellerdomain.com';
const CUSTOMER_DOMAIN = 'example.com';
const CUSTOMER_SITE = 'https://www.example.com/';
// ################################################################

// Full List of scopes: https://developers.google.com/identity/protocols/googlescopes
const OAUTH2_SCOPES = [
  'https://reseller.googleapis.com/auth/apps.order',
  'https://reseller.googleapis.com/auth/siteverification',
  'https://reseller.googleapis.com/auth/admin.directory.user',
];

const authJWT = new google.auth.JWT({
  keyFile: JSON_PRIVATE_KEY_FILE,
  scopes: OAUTH2_SCOPES,
  subject: RESELLER_ADMIN_USER,
});

const resellerService = google.reseller({version: 'v1', auth: authJWT});
const directoryService = google.admin({version: 'directory_v1', auth: authJWT});
const verificationService = google.siteVerification({version: 'v1', auth: authJWT});

// Run all the steps one after each other, and exit as soon as one of them fail
Promise.resolve()
  .then(() => {
    /**
     * Retrieve the site verification token and place it according to:
     * https://developers.google.com/site-verification/v1/getting_started#tokens
     */
    const getTokenPromise = verificationService.webResource.getToken({
      requestBody: {
        site: {
          type: 'INET_DOMAIN',
          identifier: CUSTOMER_DOMAIN,
        },
        verificationMethod: 'DNS_TXT',
      }
    }).then(({data}) => {
      console.log(data);
      return data;
    });


    return getTokenPromise;
  })
  .then(() => {
    // Determine if customer domain already has Google Workspace
    const getCustomerPromise = resellerService.customers.get({
      customerId: CUSTOMER_DOMAIN
    }).then(() => {
      throw new Error('Customer already exists');
    }, resErr => {
      if (resErr.code === 404) {
        console.log('Domain available for Google Workspace creation');
      } else {
        throw resErr;
      }
    });

    return getCustomerPromise;
  })
  .then(() => {
    // Create customer resource
    const insertCustomerPromise = resellerService.customers.insert({
      requestBody: {
        customerDomain: CUSTOMER_DOMAIN,
        alternateEmail: 'marty.mcfly@gmail.com',
        postalAddress: {
          contactName: 'Marty McFly',
          organizationName: 'Acme Corp',
          postalCode: '10009',
          countryCode: 'US',
        }
      }
    }).then(({data}) => {
      console.log(data);
      return data;
    });

    return insertCustomerPromise;
  })
  .then(() => {
    // Create first admin user
    const insertUserPromise = directoryService.users.insert({
      requestBody: {
        primaryEmail: `marty.mcfly@${CUSTOMER_DOMAIN}`,
        name: {
          givenName: 'Marty',
          familyName: 'McFly',
        },
        password: 'Timecircuit88',
      }
    }).then(({data}) => {
      console.log(data);
      return data;
    });

    return insertUserPromise;
  }).then(() => {
    // Promote user to admin status
    const makeAdminPromise = directoryService.users.makeAdmin({
      userKey: `marty.mcfly@${CUSTOMER_DOMAIN}`,
      requestBody: {
        status: true
      }
    });

    return makeAdminPromise;
  })
  .then(() => {
    // Create subscription resource
    const insertSubscriptionPromise = resellerService.subscriptions.insert({
      customerId: CUSTOMER_DOMAIN,
      requestBody: {
        customerId: CUSTOMER_DOMAIN,
        skuId: '1010020027',
        plan: {
          planName: 'ANNUAL_MONTHLY_PAY',
        },
        seats: {
          numberOfSeats: 5,
        },
        renewalSettings: { // only relevant for annual plans
          renewalType: 'RENEW_CURRENT_USERS_MONTHLY_PAY',
        }
      }
    }).then(({data}) => {
      console.log(data);
      return data;
    });

    return insertSubscriptionPromise;
  })
  .then(() => {
    // Verify domain and designate domain owners
    const verifyDomainPromise = verificationService.webResource.insert({
      verificationMethod: 'DNS_TXT',
      requestBody: {
        site: {
          type: 'INET_DOMAIN',
          identifier: CUSTOMER_DOMAIN,
        },
        owners: [`marty.mcfly@${CUSTOMER_DOMAIN}`],
      }
    }).then(({data}) => {
      console.log(data);
      return data;
    });

    return verifyDomainPromise;
  })
  .catch(err => {
    console.error('Error:', err.message);
    if (err.code) {
      console.log('Error code:', err.code);
    }
    if (err.errors) {
      console.log('Details:', err.errors);
    }
  });