How it works

Introduction

The zero-touch enrollment API helps device resellers automate their integration. Your organization's sales tools can build in zero-touch enrollment—making your users, and your customers, more productive. Use the API to help your users:

  • Assign purchased devices to a customer's zero-touch enrollment account.
  • Create your customer's zero-touch enrollment account.
  • Attach your organization's telephone and order metadata to devices.
  • Create reports about devices assigned to your customers.

This document introduces the API and explains the patterns. If you want to explore the API yourself, try a quickstart for Java , .NET , or Python .

API concepts

Customers and devices are the core resources you use in the API. To create customers, call create . You can create devices using the claim API methods ( see below ). Your organization can also create customers and devices using the zero-touch enrollment portal .

Device and customer resource relationship

Customer
Companies that your organization sells devices to. Customers have a name and an ID . Use a customer when you want to claim or find their devices. To learn more, see Customer .
Device
A zero-touch enrollment-capable Android or ChromeOS device your organization sells to a customer. Devices have hardware IDs, metadata, and customer claims. Devices are central to the API, so you use them in almost all methods. To learn more, see Device .
DeviceIdentifier
Encapsulates hardware IDs, such as IMEI or MEID, to identify a manufactured device. Use a DeviceIdentifier to target the device you want to find, update, or claim. To learn more, read Identifiers .
DeviceMetadata
Stores key-value pairs of metadata for the device. Use DeviceMetadata to store your organization's metadata. To learn more, read Device metadata .

To list all the API methods and resources your app can use, see the API Reference .

Create customers

For Android devices, the reseller is responsible for creating the customer account on behalf of their customer. The customer will use this account to access the zero-touch portal to configure the provisioning settings for their devices. This is not necessary for ChromeOS devices, who already have a Google Workspace account which they will use to configure their provisioning settings.

You can call the create API method to create customer accounts for zero-touch enrollment. Because your customers see the company name in their zero-touch enrollment portal, your app's user should confirm that it's correct. You can't edit a customer's name after you create the customer.

You need to include at least one corporate email address, associated with a Google Account, to be the owner. You can't use personal Gmail accounts with the API. If the customer needs help with associating the account, send the instructions from Associate a Google Account .

After you create a customer by calling the API, they manage their employees' portal access — you can't edit your customers' users using the API. The snippet below shows how you might create a customer:

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 
 () 

To learn more about the owner and admin roles for employees of your customer, read Portal users .

Claim devices for customers

After your customers purchase devices, they'll want to configure provisioning settings for these devices in their account. Claiming a device adds the device to zero-touch enrollment and gives the customer the ability to configure provisioning settings.

A device's provisioning record has a section for zero-touch enrollment. You assign the device by claiming the record's zero-touch enrollment section for a customer. Call the partners.devices.claim or partners.devices.claimAsync methods with the customer as an argument. Always supply SECTION_TYPE_ZERO_TOUCH as a value for sectionType .

You'll need to unclaim ( see below ) a customer's device before you can claim the same device for a different customer. The claim methods validate the DeviceIdentifier fields, including the IMEI or MEID, or the serial number, the manufacturer name and model, and the attested device ID for ChromeOS devices, when creating a new device.

The snippet below shows how to claim a device:

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 
 () 

Unclaiming devices

Your organization can unclaim a device from a customer. Unclaiming a device removes it from zero-touch enrollment. A reseller might unclaim a device that they want migrated to another account, returned, or that was mistakenly claimed. Call the method partners.devices.unclaim or partners.devices.unclaimAsync to unclaim a device from a customer.

Vendors

You can use vendors to represent reseller partners in your dealer network, local operators within a global reseller network, or any organization that sells devices on your behalf. Vendors help you separate your users, customers, and devices:

  • Vendors you create can’t see your zero-touch enrollment account or each others’ accounts.
  • You can view your vendors’ customers and devices and you can unregister vendors’ devices. However, you can’t assign devices to your vendors’ customers.

Use the portal to create vendors for your organization — you can’t use the API. Your account role must be Owner to create a new vendor. If your organization has vendors, you can call partners.vendors.list to list your vendors and partners.vendors.customers.list to get your vendor’s customers. The following example uses both of these methods to print a report showing the Terms of Service status for the vendors’ customers:

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' 
 ]) 

If you have a collection of devices, you might need to know which reseller or vendor claimed the device. To get the numeric reseller ID, inspect the value of the resellerId field in a device’s claim record.

Your organization can unclaim a vendor-claimed device. For other API calls that modify devices, you should check that your organization claimed the device before calling the API method. The following example shows how you can do this:

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 

Long-running batch operations

The API includes asynchronous versions of the device methods . These methods allow batch processing of many devices, while the synchronous methods process one device for each API request. The asynchronous method names have an Async suffix, for example claimAsync .

Asynchronous API methods return a result before the processing is complete. Asynchronous methods also help your app (or tool) remain responsive for your users while they wait for a long-running operation to complete. Your app should check the status of the operation periodically.

Operations

You use an Operation to track a long-running batch operation. A successful call to an asynchronous method returns a reference to the operation in the response. The JSON snippet below shows a typical response after calling updateMetadataAsync :

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

Each operation contains a list of individual tasks. Call operations.get to find out information about the status and results of tasks contained in the operation. The snippet below shows how you might do this. In your own app, you'll need to handle any errors.

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 
 () 

To find out if an operation finished, check the operation for a done field with a value of true . If done is missing or false , the operation is still running.

Responses

After an operation finishes, the API updates the operation with the result—even if all or none of the individual tasks are successful. The response field is a DevicesLongRunningOperationResponse object detailing the processing of each device in the operation.

Inspect the successCount field to efficiently find out if any tasks failed and avoid iterating through large result lists. The perDeviceStatus field of DevicesLongRunningOperationResponse is a list of OperationPerDevice instances detailing each device in the operation. The list order matches the tasks in the original request.

Each OperationPerDevice task contains a result field and a reminder summary of the request received by the server. Check if the task succeeded or failed using the result field.

The JSON snippet below shows part of a typical response from an operation after a call to updateMetadataAsync :

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

Track progress

If your app needs to track progress, you should periodically refetch the operation. The metadata field contains a DevicesLongRunningOperationMetadata instance to help your app check the latest progress of a running operation. Use the fields of DevicesLongRunningOperationMetadata listed in the following table to track the operation's progress:

Field Typical use
processingStatus Changes from BATCH_PROCESS_PENDING to BATCH_PROCESS_IN_PROGRESS , and then to BATCH_PROCESS_PROCESSED as the operation progresses.
progress The percentage of updates processed. Your app can use this to estimate a finish time. Because the progress value can be 100 while the operation is finishing up, check the done field of an operation to know if it finished and has a result.
devicesCount Shows the number of updates in the operation. This might be different from the number of updates in your request if the API can't parse some of the updates.

The simplified example below shows how an app might use the progress metadata to set polling intervals. In your app, you might need a more sophisticated task runner for polling. You'll also need to add error handling.

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 
 ) 

Choose a polling approach that makes sense for your app's users. Some app users might benefit from regular progress updates if they're waiting for a process to complete.

Paged results

The partners.devices.findByOwner API method might return very large lists of devices. To reduce the response size, this and other API methods (such as partners.devices.findByIdentifier ) support paged results. With paged results, your application can iteratively request and process large lists one page at a time.

After calling the API method, check if the response includes a value for nextPageToken . If nextPageToken isn't null , your app can use it to fetch another page of devices by calling the method again. You need to set an upper limit for the number of devices in the limit parameter. If nextPageToken is null , your app has requested the last page.

The example method below shows how your app might print a list of devices, one page at a time:

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

Next steps

Now that you know how the API works, try out the examples with a quickstart for Java , .NET , or Python . You can use a colab to view examples of API calls and experiment with calling the API yourself.

Design a Mobile Site
View Site in Mobile | Classic
Share by: