Принцип работы

Введение

API автоматической настройки помогает реселлерам устройств автоматизировать интеграцию. Вы можете встроить автоматическую настройку в инструменты продаж вашей организации, чтобы повысить эффективность работы пользователей и клиентов. Используйте API, чтобы помочь пользователям:

  • Назначать приобретенные устройства аккаунту клиента для автоматической настройки.
  • Создайте аккаунт автоматической настройки для клиента.
  • Прикрепите к устройствам метаданные о телефонах и заказах вашей организации.
  • Создавайте отчеты об устройствах, назначенных вашим клиентам.

В этом документе описывается API и объясняются шаблоны. Если вы хотите изучить API самостоятельно, ознакомьтесь с кратким руководством по Java, .NET или Python.

Основные понятия API

Клиенты и устройства – это основные ресурсы, которые вы используете в API. Чтобы создать клиентов, вызовите create. Вы можете создавать устройства, используя методы API для декларирования (см. ниже). Ваша организация также может создавать клиентов и устройства с помощью портала автоматической настройки.

Связь между устройством и ресурсом клиента

Клиент
Компании, которым ваша организация продает устройства. У клиентов есть name и ID. Используйте идентификатор клиента, чтобы заявить права на его устройства или найти их. Подробнее Customer…
Устройство
Устройство Android или устройство с ChromeOS с поддержкой автоматической настройки, которое ваша организация продает клиенту. Устройства имеют идентификаторы оборудования, метаданные и претензии клиентов. Устройства – это центральный элемент API, поэтому они используются почти во всех методах. Подробнее Device…
DeviceIdentifier
Инкапсулирует идентификаторы оборудования, такие как IMEI или MEID, для идентификации изготовленного устройства. Используйте DeviceIdentifier, чтобы найти, обновить или заявить права на устройство. Подробнее об идентификаторах…
DeviceMetadata
Хранит пары "ключ-значение" метаданных для устройства. Используйте DeviceMetadata для хранения метаданных организации. Подробнее о метаданных устройств…

Список всех методов и ресурсов API, которые может использовать ваше приложение, приведен в документации по API.

Создание клиентов

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

Чтобы создать аккаунты клиентов для автоматической настройки, вызовите метод API create. Поскольку клиенты видят название компании на портале автоматической настройки, пользователь вашего приложения должен подтвердить, что оно указано правильно. После создания клиента его имя изменить нельзя.

Вам нужно указать хотя бы один корпоративный адрес электронной почты, связанный с аккаунтом Google, чтобы назначить его владельцем. Личные аккаунты Gmail не поддерживаются. Если клиенту нужна помощь с привязкой аккаунта, отправьте ему инструкции из статьи Как связать аккаунт Google с аккаунтом в стороннем сервисе.

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

Java

// Provide the customer data as a Company type.
// The API requires a name and owners.
Company customer = new Company();
customer.setCompanyName("XYZ Corp");
customer.setOwnerEmails(Arrays.asList("liz@example.com", "darcy@example.com"));
customer.setAdminEmails(Collections.singletonList("jane@example.com"));

// Use our reseller ID for the parent resource name.
String parentResource = String.format("partners/%d", PARTNER_ID);

// Call the API to create the customer using the values in the company object.
CreateCustomerRequest body = new CreateCustomerRequest();
body.setCustomer(customer);
Company response = service.partners().customers().create(parentResource, body).execute();

.NET

// Provide the customer data as a Company type.
// The API requires a name and owners.
var customer = new Company
{
    CompanyName = "XYZ Corp",
    OwnerEmails = new String[] { "liz@example.com", "darcy@example.com" },
    AdminEmails = new String[] { "jane@example.com" }
};

// Use our reseller ID for the parent resource name.
var parentResource = String.Format("partners/{0}", PartnerId);

// Call the API to create the customer using the values in the company object.
var body = new CreateCustomerRequest
{
    Customer = customer
};
var request = service.Partners.Customers.Create(body, parentResource);
var response = request.Execute();

Python

# Provide the customer data as a Company type. The API requires
# a name and at least one owner.
company = {'companyName':'XYZ Corp', \
  'ownerEmails':['liz@example.com', 'darcy@example.com'], \
  'adminEmails':['jane@example.com']}

# Use our reseller ID for the parent resource name.
parent_resource = 'partners/{0}'.format(PARTNER_ID)

# Call the API to create the customer using the values in the company object.
response = service.partners().customers().create(parent=parent_resource,
    body={'customer':company}).execute()

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

Регистрация устройств для клиентов

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

В записи о подготовке устройства есть раздел, посвященный автоматической настройке. Вы назначаете устройство, заявляя права на раздел автоматической настройки в записи клиента. Вызовите метод partners.devices.claim или partners.devices.claimAsync, указав клиента в качестве аргумента. Всегда указывайте SECTION_TYPE_ZERO_TOUCH в качестве значения для sectionType.

Чтобы зарегистрировать устройство для другого клиента, сначала нужно отменить регистрацию (см. ниже). Методы claim проверяют поля DeviceIdentifier, включая IMEI, MEID или серийный номер, название производителя и модель, а также подтвержденный идентификатор устройства для устройств с ChromeOS при создании нового устройства.

Ниже показано, как заявить права на устройство.

Java

// Identify the device to claim.
DeviceIdentifier identifier = new DeviceIdentifier();
// The manufacturer value is optional but recommended for cellular devices
identifier.setManufacturer("Google");
identifier.setImei("098765432109875");

// Create the body to connect the customer with the device.
ClaimDeviceRequest body = new ClaimDeviceRequest();
body.setDeviceIdentifier(identifier);
body.setCustomerId(customerId);
body.setSectionType("SECTION_TYPE_ZERO_TOUCH");

// Claim the device.
ClaimDeviceResponse response = service.partners().devices().claim(PARTNER_ID, body).execute();

.NET

// Identify the device to claim.
var deviceIdentifier = new DeviceIdentifier
{
    // The manufacturer value is optional but recommended for cellular devices
    Manufacturer = "Google",
    Imei = "098765432109875"
};

// Create the body to connect the customer with the device.
ClaimDeviceRequest body = new ClaimDeviceRequest
{
    DeviceIdentifier = deviceIdentifier,
    CustomerId = CustomerId,
    SectionType = "SECTION_TYPE_ZERO_TOUCH"
};

// Claim the device.
var response = service.Partners.Devices.Claim(body, PartnerId).Execute();

Python

# Identify the device to claim.
# The manufacturer value is optional but recommended for cellular devices
device_identifier = {'manufacturer':'Google', 'imei':'098765432109875'}

# Create the body to connect the customer with the device.
request_body = {'deviceIdentifier':device_identifier, \
    'customerId':customer_id, \
    'sectionType':'SECTION_TYPE_ZERO_TOUCH'}

# Claim the device.
response = service.partners().devices().claim(partnerId=PARTNER_ID,
    body=request_body).execute()

Как отменить регистрацию устройств

Ваша организация может отменить регистрацию устройства клиента. Если вы откажетесь от прав на устройство, оно будет удалено из списка для автоматической настройки. Реселлер может отменить регистрацию устройства, если его нужно перенести в другой аккаунт, вернуть или если оно было зарегистрировано по ошибке. Чтобы отменить связь устройства с клиентом, вызовите метод partners.devices.unclaim или partners.devices.unclaimAsync.

Поставщики

Поставщиками могут быть партнеры-реселлеры в вашей дилерской сети, местные операторы в глобальной сети реселлеров или любая организация, которая продает устройства от вашего имени. Поставщики помогают разделить пользователей, клиентов и устройства.

  • Созданные вами поставщики не могут видеть ваш аккаунт автоматической настройки или аккаунты друг друга.
  • Вы можете просматривать клиентов и устройства поставщиков, а также отменять регистрацию устройств поставщиков. Однако вы не можете назначать устройства клиентам поставщиков.

Используйте портал, чтобы создавать поставщиков для своей организации. С помощью API это сделать нельзя. Чтобы создать нового поставщика, у вас должна быть роль Владелец. Если у вашей организации есть поставщики, вы можете вызвать partners.vendors.list, чтобы получить список поставщиков, и partners.vendors.customers.list, чтобы получить список клиентов поставщика. В примере ниже используются оба метода, чтобы напечатать отчет со статусом Условий использования для клиентов поставщиков.

Java

// First, get the organization's vendors.
String parentResource = String.format("partners/%d", PARTNER_ID);
ListVendorsResponse results = service.partners().vendors().list(parentResource).execute();
if (results.getVendors() == null) {
  return;
}

// For each vendor, report the company name and a maximum 5 customers.
for (Company vendor: results.getVendors()) {
  System.out.format("\n%s customers\n", vendor.getCompanyName());
  System.out.println("---");
  // Use the vendor's API resource name as the parent resource.
  AndroidProvisioningPartner.Partners.Vendors.Customers.List customerRequest =
      service.partners().vendors().customers().list(vendor.getName());
  customerRequest.setPageSize(5);
  ListVendorCustomersResponse customerResponse = customerRequest.execute();

  List<Company> customers = customerResponse.getCustomers();
  if (customers == null) {
    System.out.println("No customers");
    break;
  } else {
    for (Company customer: customers) {
      System.out.format("%s: %s\n",
          customer.getCompanyName(),
          customer.getTermsStatus());
    }
  }
}

.NET

// First, get the organization's vendors.
var parentResource = String.Format("partners/{0}", PartnerId);
var results = service.Partners.Vendors.List(parentResource).Execute();
if (results.Vendors == null)
{
    return;
}

// For each vendor, report the company name and a maximum 5 customers.
foreach (Company vendor in results.Vendors)
{
    Console.WriteLine("\n{0} customers", vendor);
    Console.WriteLine("---");
    // Use the vendor's API resource name as the parent resource.
    PartnersResource.VendorsResource.CustomersResource.ListRequest customerRequest =
        service.Partners.Vendors.Customers.List(vendor.Name);
    customerRequest.PageSize = 5;
    var customerResponse = customerRequest.Execute();

    IList<Company> customers = customerResponse.Customers;
    if (customers == null)
    {
        Console.WriteLine("No customers");
        break;
    }
    else
    {
        foreach (Company customer in customers)
        {
            Console.WriteLine("{0}: {1}", customer.Name, customer.TermsStatus);
        }
    }
}

Python

# First, get the organization's vendors.
parent_resource = 'partners/{0}'.format(PARTNER_ID)
vendor_response = service.partners().vendors().list(
    parent=parent_resource).execute()
if 'vendors' not in vendor_response:
  return

# For each vendor, report the company name and a maximum 5 customers.
for vendor in vendor_response['vendors']:
  print '\n{0} customers'.format(vendor['companyName'])
  print '---'
  # Use the vendor's API resource name as the parent resource.
  customer_response = service.partners().vendors().customers().list(
      parent=vendor['name'], pageSize=5).execute()
  if 'customers' not in customer_response:
    print 'No customers'
    break
  for customer in customer_response['customers']:
    print '  {0}: {1}'.format(customer['name'], customer['termsStatus'])

Если у вас много устройств, вам может потребоваться узнать, какой реселлер или поставщик заявил права на устройство. Чтобы получить числовой идентификатор реселлера, проверьте значение поля resellerId в записи о регистрации устройства.

Ваша организация может отменить регистрацию устройства, выполненную поставщиком. Для других вызовов API, которые изменяют устройства, перед вызовом метода API необходимо убедиться, что ваша организация заявила права на устройство. Ниже приведен пример.

Java

// Get the devices claimed for two customers: one of our organization's
// customers and one of our vendor's customers.
FindDevicesByOwnerRequest body = new FindDevicesByOwnerRequest();
body.setSectionType("SECTION_TYPE_ZERO_TOUCH");
body.setCustomerId(Arrays.asList(resellerCustomerId, vendorCustomerId));
body.setLimit(MAX_PAGE_SIZE);
FindDevicesByOwnerResponse response =
    service.partners().devices().findByOwner(PARTNER_ID, body).execute();
if (response.getDevices() == null) {
  return;
}

for (Device device: response.getDevices()) {
  // Confirm the device was claimed by our reseller and not a vendor before
  // updating metadata in another method.
  for (DeviceClaim claim: device.getClaims()) {
    if (claim.getResellerId() == PARTNER_ID) {
      updateDeviceMetadata(device.getDeviceId());
      break;
    }
  }
}

.NET

// Get the devices claimed for two customers: one of our organization's
// customers and one of our vendor's customers.
FindDevicesByOwnerRequest body = new FindDevicesByOwnerRequest
{
    Limit = MaxPageSize,
    SectionType = "SECTION_TYPE_ZERO_TOUCH",
    CustomerId = new List<long?>
    {
        resellerCustomerId,
        vendorCustomerId
    }
};
var response = service.Partners.Devices.FindByOwner(body, PartnerId).Execute();
if (response.Devices == null)
{
    return;
}

foreach (Device device in response.Devices)
{
    // Confirm the device was claimed by our reseller and not a vendor before
    // updating metadata in another method.
    foreach (DeviceClaim claim in device.Claims)
    {
        if (claim.ResellerId == PartnerId)
        {
            UpdateDeviceMetadata(device.DeviceId);
            break;
        }
    }
}

Python

# Get the devices claimed for two customers: one of our organization's
# customers and one of our vendor's customers.
request_body = {'limit':MAX_PAGE_SIZE, \
  'pageToken':None, \
  'customerId':[reseller_customer_id, vendor_customer_id], \
  'sectionType':'SECTION_TYPE_ZERO_TOUCH'}
response = service.partners().devices().findByOwner(partnerId=PARTNER_ID,
    body=request_body).execute()

for device in response['devices']:
  # Confirm the device was claimed by our reseller and not a vendor before
  # updating metadata in another method.
  for claim in device['claims']:
    if claim['resellerId'] == PARTNER_ID:
      update_device_metadata(device['deviceId'])
      break

Длительные пакетные операции

API включает асинхронные версии методов устройства. Эти методы позволяют выполнять пакетную обработку многих устройств, а синхронные методы обрабатывают одно устройство на каждый запрос к API. Названия асинхронных методов имеют суффикс Async, например claimAsync.

Асинхронные методы API возвращают результат до завершения обработки. Асинхронные методы также помогают вашему приложению (или инструменту) оставаться отзывчивым для пользователей, пока они ждут завершения продолжительной операции. Приложение должно периодически проверять статус операции.

Операции

Для отслеживания длительной пакетной операции используется Operation. При успешном вызове асинхронного метода в ответе возвращается ссылка на операцию. Ниже приведен фрагмент кода JSON, который показывает типичный ответ после вызова updateMetadataAsync.

{
  "name": "operations/apibatchoperation/1234567890123476789"
}

Каждая операция содержит список отдельных задач. Вызовите operations.get, чтобы узнать статус и результаты задач, содержащихся в операции. Ниже показано, как это сделать. В своем приложении вам нужно будет обрабатывать все ошибки.

Java

// Build out the request body to apply the same order number to a customer's
// purchase of 2 devices.
UpdateMetadataArguments firstUpdate = new UpdateMetadataArguments();
firstUpdate.setDeviceMetadata(metadata);
firstUpdate.setDeviceId(firstTargetDeviceId);

UpdateMetadataArguments secondUpdate = new UpdateMetadataArguments();
secondUpdate.setDeviceMetadata(metadata);
secondUpdate.setDeviceId(firstTargetDeviceId);

// Start the device metadata update.
UpdateDeviceMetadataInBatchRequest body = new UpdateDeviceMetadataInBatchRequest();
body.setUpdates(Arrays.asList(firstUpdate, secondUpdate));
Operation response = service
    .partners()
    .devices()
    .updateMetadataAsync(PARTNER_ID, body)
    .execute();

// Assume the metadata update started, so get the Operation for the update.
Operation operation = service.operations().get(response.getName()).execute();

.NET

// Build out the request body to apply the same order number to a customer's
// purchase of 2 devices.
var updates = new List<UpdateMetadataArguments>
{
    new UpdateMetadataArguments
    {
        DeviceMetadata = metadata,
        DeviceId = firstTargetDeviceId
    },
    new UpdateMetadataArguments
    {
        DeviceMetadata = metadata,
        DeviceId = secondTargetDeviceId
    }
};

// Start the device metadata update.
UpdateDeviceMetadataInBatchRequest body = new UpdateDeviceMetadataInBatchRequest
{
    Updates = updates
};
var response = service.Partners.Devices.UpdateMetadataAsync(body, PartnerId).Execute();

// Assume the metadata update started, so get the Operation for the update.
Operation operation = service.Operations.Get(response.Name).Execute();

Python

# Build out the request body to apply the same order number to a customer's
# purchase of 2 devices.
updates = [{'deviceMetadata':metadata,'deviceId':first_target_device_id},
    {'deviceMetadata':metadata,'deviceId':second_target_device_id}]

# Start the device metadata update.
response = service.partners().devices().updateMetadataAsync(
    partnerId=PARTNER_ID, body={'updates':updates}).execute()

# Assume the metadata update started, so get the Operation for the update.
operation = service.operations().get(name=response['name']).execute()

Чтобы узнать, завершена ли операция, проверьте, есть ли в ней поле done со значением true. Если done отсутствует или имеет значение false, операция все ещё выполняется.

Ответы

После завершения операции API обновляет ее, добавляя результат, даже если все или ни одна из отдельных задач не были выполнены успешно. Поле response – это объект DevicesLongRunningOperationResponse, содержащий подробные сведения об обработке каждого устройства в ходе операции.

Проверьте поле successCount, чтобы узнать, не произошел ли сбой в каких-либо задачах, и избежать итерации по большим спискам результатов. Поле perDeviceStatus объекта DevicesLongRunningOperationResponse – это список экземпляров OperationPerDevice с подробными сведениями о каждом устройстве, задействованном в операции. Порядок задач в списке соответствует порядку в исходном запросе.

Каждая задача OperationPerDevice содержит поле result и краткое напоминание о запросе, полученном сервером. Проверьте, выполнена ли задача, с помощью поля result.

Фрагмент кода JSON ниже показывает часть типичного ответа на операцию после вызова updateMetadataAsync:

"response": {
  "perDeviceStatus": [
    {
      "result": {
        "deviceId": "12345678901234567",
        "status": "SINGLE_DEVICE_STATUS_SUCCESS"
      },
      "updateMetadata": {
        "deviceId": "12345678901234567",
        "deviceMetadata": {
          "entries": {
            "phonenumber": "+1 (800) 555-0100"
          }
        }
      }
    }
  ],
  "successCount": 1
}

Следить за выполнением

Если вашему приложению нужно отслеживать ход выполнения, периодически запрашивайте операцию. Поле metadata содержит экземпляр DevicesLongRunningOperationMetadata, который позволяет приложению проверять ход выполнения операции. Чтобы отслеживать ход выполнения операции, используйте поля DevicesLongRunningOperationMetadata, перечисленные в таблице ниже.

Поле Обычное использование
processingStatus По мере выполнения операции значение меняется с BATCH_PROCESS_PENDING на BATCH_PROCESS_IN_PROGRESS, а затем на BATCH_PROCESS_PROCESSED.
progress Процент обработанных обновлений. Приложение может использовать эти данные, чтобы рассчитать время окончания. Поскольку значение progress может быть равно 100, пока операция завершается, проверьте поле done, чтобы узнать, завершена ли операция и есть ли результат.
devicesCount Показывает количество обновлений в операции. Это число может отличаться от количества обновлений в запросе, если API не может обработать некоторые из них.

В упрощенном примере ниже показано, как приложение может использовать метаданные о ходе выполнения для установки интервалов опроса. В вашем приложении может потребоваться более сложный исполнитель задач для опроса. Вам также потребуется добавить обработку ошибок.

Java

// Milliseconds between polling the API.
private static long MIN_INTERVAL = 2000;
private static long MAX_INTERVAL = 10000;

// ...
// Start the device metadata update.
Operation response = service
    .partners()
    .devices()
    .updateMetadataAsync(PARTNER_ID, body)
    .execute();
String operationName = response.getName();

// Start polling for completion.
long startTime = new Date().getTime();
while (true) {

  // Get the latest update on the operation's progress using the API.
  Operation operation = service.operations().get(operationName).execute();

  if (operation.get("done") != null && operation.getDone()) {
    // The operation is finished. Print the status.
    System.out.format("Operation complete: %s of %s successful device updates\n",
        operation.getResponse().get("successCount"),
        operation.getMetadata().get("devicesCount"));
    break;

  } else {
    // Estimate how long the operation *should* take - within min and max value.
    BigDecimal opProgress = (BigDecimal) operation.getMetadata().get("progress");
    double progress = opProgress.longValue();
    long interval = MAX_INTERVAL;
    if (progress > 0) {
      interval = (long) ((new Date().getTime() - startTime) *
          ((100.0 - progress) / progress));
    }
    interval = Math.max(MIN_INTERVAL, Math.min(interval, MAX_INTERVAL));

    // Sleep until the operation should be complete.
    Thread.sleep(interval);
  }
}

.NET

// Milliseconds between polling the API.
private static double MinInterval = 2000;
private static double MaxInterval = 10000;

// ...
// Start the device metadata update.
var response = service.Partners.Devices.UpdateMetadataAsync(body, PartnerId).Execute();
var operationName = response.Name;

// Start polling for completion.
var startTime = DateTime.Now;
while (true)
{

    // Get the latest update on the operation's progress using the API.
    Operation operation = service.Operations.Get(operationName).Execute();

    if (operation.Done == true)
    {
        // The operation is finished. Print the status.
        Console.WriteLine("Operation complete: {0} of {1} successful device updates",
                          operation.Response["successCount"],
                          operation.Metadata["devicesCount"]);
        break;
    }
    else
    {
        // Estimate how long the operation *should* take - within min and max value.
        double progress = (double)(long)operation.Metadata["progress"];
        double interval = MaxInterval;
        if (progress > 0)
        {
            interval = DateTime.Now.Subtract(startTime).TotalMilliseconds *
                                     ((100.0 - progress) / progress);
        }
        interval = Math.Max(MinInterval, Math.Min(interval, MaxInterval));

        // Sleep until the operation should be complete.
        System.Threading.Thread.Sleep((int)interval);
    }
}

Python

# Seconds between polling the API.
MIN_INTERVAL = 2;
MAX_INTERVAL = 10;

# ...
# Start the device metadata update
response = service.partners().devices().updateMetadataAsync(
  partnerId=PARTNER_ID, body={'updates':updates}).execute()

op_name = response['name']
start_time = time.time()

# Start polling for completion
while True:
  # Get the latest update on the operation's progress using the API
  op = service.operations().get(name=op_name).execute()

  if 'done' in op and op['done']:
    # The operation is finished. Print the status.
    print('Operation complete: {0} of {1} successful device updates'.format(
      op['response']['successCount'], op['metadata']['devicesCount']
    ))
    break
  else:
    # Estimate how long the operation *should* take - within min and max.
    progress = op['metadata']['progress']
    interval = MIN_INTERVAL
    if progress > 0:
      interval = (time.time() - start_time) * ((100.0 - progress) / progress)
    interval = max(MIN_INTERVAL, min(interval, MAX_INTERVAL))

    # Sleep until the operation should be complete.
    time.sleep(interval)

Выберите подход к опросу, который подходит для пользователей вашего приложения. Некоторым пользователям приложения может быть полезно регулярно получать информацию о ходе выполнения процесса, если они ждут его завершения.

Результаты с разбивкой по страницам

Метод API partners.devices.findByOwner может возвращать очень большие списки устройств. Чтобы уменьшить размер ответа, этот и другие методы API (например, partners.devices.findByIdentifier) поддерживают постраничные результаты. При постраничном выводе результатов приложение может запрашивать и обрабатывать большие списки по одной странице за раз.

После вызова метода API проверьте, содержит ли ответ значение для nextPageToken. Если значение nextPageToken не равно null, приложение может использовать его, чтобы получить ещё одну страницу устройств, повторно вызвав метод. Вам нужно задать верхний предел для количества устройств в параметре limit. Если nextPageToken – это null, ваше приложение запросило последнюю страницу.

В примере ниже показано, как приложение может выводить список устройств по одной странице за раз.

Java

private static long MAX_PAGE_SIZE = 10;

// ...
/**
 * Demonstrates how to loop through paginated lists of devices.
 * @param pageToken       The token specifying which result page to return.
 * @throws IOException    If the zero-touch API call fails.
 */
private void printDevices(String pageToken) throws IOException {

  // Create the request body to find the customer's devices.
  FindDevicesByOwnerRequest body = new FindDevicesByOwnerRequest();
  body.setLimit(MAX_PAGE_SIZE);
  body.setSectionType("SECTION_TYPE_ZERO_TOUCH");
  body.setCustomerId(Collections.singletonList(targetCustomerId));

  // Call the API to get a page of Devices. Send a page token from the method
  // argument (might be None). If the page token is None, the API returns the first page.
  FindDevicesByOwnerResponse response =
      service.partners().devices().findByOwner(PARTNER_ID, body).execute();
  if (response.getDevices() == null) {
    return;
  }

  // Print the devices included in this page of results.
  for (Device device: response.getDevices()) {
    System.out.format("Device %s\n", device.getName());
  }
  System.out.println("---");

  // Check to see if another page of devices is available. If yes,
  // fetch and print the devices.
  if (response.getNextPageToken() != null) {
    this.printDevices(response.getNextPageToken());
  }
}

// ...
// Pass null to start printing the first page of devices.
printDevices(null);

.NET

private static int MaxPageSize = 10;

// ...
/// <summary>Demonstrates how to loop through paginated lists of devices.</summary>
/// <param name="pageToken">The token specifying which result page to return.</param>
private void PrintDevices(string pageToken)
{
    // Create the request body to find the customer's devices.
    FindDevicesByOwnerRequest body = new FindDevicesByOwnerRequest
    {
        PageToken = pageToken,
        Limit = MaxPageSize,
        SectionType = "SECTION_TYPE_ZERO_TOUCH",
        CustomerId = new List<long?>
        {
            targetCustomerId
        }
    };

    // Call the API to get a page of Devices. Send a page token from the method
    // argument (might be None). If the page token is None, the API returns the first page.
    var response = service.Partners.Devices.FindByOwner(body, PartnerId).Execute();
    if (response.Devices == null)
    {
        return;
    }

    // Print the devices included in this page of results.
    foreach (Device device in response.Devices)
    {
        Console.WriteLine("Device: {0}", device.Name);
    }
    Console.WriteLine("---");

    // Check to see if another page of devices is available. If yes,
    // fetch and print the devices.
    if (response.NextPageToken != null)
    {
        this.PrintDevices(response.NextPageToken);
    }
}

// ...
// Pass null to start printing the first page of devices.
PrintDevices(null);

Python

MAX_PAGE_SIZE = 10;

# ...
def print_devices(page_token):
  """Demonstrates how to loop through paginated lists of devices.

  Args:
    page_token: The token specifying which result page to return.
  """

   # Create the body to find the customer's devices.
  request_body = {'limit':MAX_PAGE_SIZE, \
    'pageToken':page_token, \
    'customerId':[target_customer_id], \
    'sectionType':'SECTION_TYPE_ZERO_TOUCH'}

  # Call the API to get a page of Devices. Send a page token from the method
  # argument (might be None). If the page token is None,
  # the API returns the first page.
  response = service.partners().devices().findByOwner(partnerId=PARTNER_ID,
    body=request_body).execute()

  # Print the devices included in this page of results.
  for device in response['devices']:
    print 'Device: {0}'.format(device['name'])
  print '---'

  # Check to see if another page of devices is available. If yes,
  # fetch and print the devices.
  if 'nextPageToken' in response:
    print_devices(response['nextPageToken'])

# ...
# Pass None to start printing the first page of devices.
print_devices(None);

Дальнейшие действия

Теперь, когда вы знаете, как работает API, попробуйте примеры из краткого руководства для Java, .NET или Python. Вы можете использовать colab, чтобы посмотреть примеры вызовов API и поэкспериментировать с ними.