Skip to main content

Inventory Reporting & Management

Background

The Inventory Reporting & Management API is useful to create detailed inventory reports of sites, rooms, and devices. Some examples include device aggregations, device queries, device count, and room & site information.

Reminder

The API Playground is scoped to your authenticated user's Poly Lens access.

Deprecated Queries

Poly Lens APIs have evolved as we've worked to optimize the device querying experience. Two queries, devices and searchDevices, are now deprecated. While both of these queries still work, they're not optimized for querying large batches of device data. The new deviceSearch query implements pagination and supports returning results of more than 10k entries.

Query Devices using deviceSearch

deviceSearch is a core query in the Lens API. It's used to retrieve details about all devices within your Poly Lens Account (Tenant) and is the primary entry point for device inventory, status, and metadata.

The deviceSearch query returns results in a connection-based structure using edges and nodes. This pattern is a GraphQL standard for handling lists of data with support for pagination, sorting, and filtering.

  • edges are a wrapper around the node (device). They allow us to use (or add) things like pagination and sort order, without changing the structure of the device data.
  • nodes are the actual thing we're asking for, such as a device and its metadata.

deviceSearch uses the DeviceFindArgs input type for argument parameters, which include:

  • filter: The parameters to narrow down which devices are returned
  • nextToken:The continuation token (for pagination)
  • pageSize: The maximum number of result objects to include in the page results (min 1, max 5000, default 10)
  • sort: The direction and field name to sort the results

The deviceSearch queries on this page progress from basic to more advanced examples.

Basic Query Example

We'll begin with a simple query that returns the following fields for all devices in your Poly Lens Account (Tenant):

  • name: The user-assigned or default name
  • id: The unique identifier
  • connected: true if currently connected to the network and communicating with Poly Lens
  • hardwareModel: The hardware model name
  • softwareVersion: The current software version installed
Reminder

By default, deviceSearch returns 10 results per request. pageSize: 10 isn't auto-populated in the API Playground Variables field. You can adjust pageSize to any value between 1 and 5000.

To keep the sample response concise, we'll change pageSize to 2.

Test this query in the GraphQL Playground

  query allDevices($params: DeviceFindArgs) {
deviceSearch(params: $params) {
edges {
node {
name
id
connected
hardwareModel
softwareVersion
}
}
}
}

Variables

{
"params": {
"pageSize": 2
}
}

Sample Response

{
"data": {
"deviceSearch": {
"edges": [
{
"node": {
"name": "Poly Lens Desktop",
"id": "ce542b2b-0e3e-4f29-eab7-4d2243d14b42",
"connected": true,
"hardwareFamily": "Lens App Family",
"hardwareModel": "Lens Desktop",
"softwareVersion": "2.1.1.2761"
}
},
{
"node": {
"name": "DFR Dev Lab X70",
"id": "00e0db775ba0",
"connected": true,
"hardwareFamily": "Studio X Family Large",
"hardwareModel": "Studio X70",
"softwareVersion": "4.4.3.438012"
}
}
]
}
}
}

Pagination and pageInfo Metadata

To manage pagination, use the pageInfo object, which includes:

  • totalCount: The total number of results
  • countOnPage: The number of results returned on this page
  • nextToken: The token to retrieve the next page. Use null to return the first page.
  • hasNextPage: true if there are more results available

Sorting Results with deviceSort

To sort results, use the deviceSort input, which includes:

  • direction: Sort order - ASC (Ascending) or DESC (Descending)
  • name: The name of the field to sort by (e.g., id, name, hardwareModel)

Using Filters to Target Specific Devices

Returning all devices in every query is usually inefficient and impractical. Most use cases require filtering or grouping the data to focus on specific device types, statuses, or configurations. The deviceSearch query offers a comprehensive set of filter options to support various levels of granularity.

The following examples explore applying filters to narrow down your query results.

Filter by activeApplicationName

To identify the provider mode your Poly devices are running, use the activeApplicationName field.

This is done by passing two filter variables:

  • field: the field name to filter by (e.g., activeApplicationName)

  • contains: the field value to search for (e.g., "Zoom", "Microsoft", "Poly")

This filter effectively tells the API: "Return all devices where the activeApplicationName field contains the string 'xyz'."

The query below asks for Poly devices running Zoom Rooms, the Zoom Rooms APK version, and includes pagination. This includes Poly Touch Controllers that are paired to Poly Video Codecs running Zoom Rooms.

Note

The provider name passed into the contains field is case sensitive.

Test this query in the GraphQL Playground

query zoomDevices($params: DeviceFindArgs) {
deviceSearch(params: $params) {
edges {
node {
name
id
connected
serialNumber
hardwareModel
activeApplicationName
activeApplicationVersion
room {
name
floor
}
connections {
name
id
connected
}
}
}
pageInfo {
totalCount
countOnPage
nextToken
hasNextPage
}
}
}

Variables

{
"params": {
"pageSize": 2,
"filter": {
"contains": "Zoom",
"field": "activeApplicationName"
},
"sort": {
"fields": [
{
"direction": "ASC",
"name": "id"
}
]
}
}
}

Sample Response

{
"data": {
"deviceSearch": {
"edges": [
{
"node": {
"name": "DFR StudioX70",
"id": "00f2cd543a5b",
"connected": true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "Studio X70",
"activeApplicationName": "Zoom Rooms",
"activeApplicationVersion": "6.1.0.5144",
"room": {
"name": "Jedi Enclave",
"floor": "2"
},
"connections": [
{
"name": "Poly TC8",
"id": "00e0ca2a5643",
"connected": false
},
{
"name": "Poly TC10",
"id": "00e0bc1ad311",
"connected": true
}
]
}
},
{
"node": {
"name": "Poly TC10",
"id": "00e0ab8803ab",
"connected": true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "TC10",
"activeApplicationName": "Zoom",
"activeApplicationVersion": "6.4.1.6706",
"room": {
"name": "Endor 501",
"floor": "5"
},
"connections": [
{
"name": "DFR Dev Lab G62",
"id": "00e0aa3ca3b6",
"connected": true
}
]
}
}
],
"pageInfo": {
"totalCount": 65,
"countOnPage": 2,
"nextToken": "NHU2MTybWpic2Jt",
"hasNextPage": true
}
}
}
}

Filter with OR: Conditions

You can use the OR: filter to match multiple activeApplicationName values in a single request. This is helpful if you want to query all devices running either Microsoft Teams Rooms or Zoom Rooms.

This includes Poly Touch Controllers that are paired to Poly Video Codecs running Zoom Rooms.

Test this query in the GraphQL Playground

query msftAndZoomDevices($params: DeviceFindArgs) {
deviceSearch(params: $params) {
edges {
node {
name
id
connected
serialNumber
hardwareModel
activeApplicationName
activeApplicationVersion
room {
name
floor
}
connections {
name
id
connected
}
}
}
pageInfo {
countOnPage
totalCount
hasNextPage
nextToken
}
}
}

Variables

{
"params": {
"pageSize": 2,
"filter": {
"OR": [
{
"contains": "Zoom",
"field": "activeApplicationName"
},
{
"contains": "Microsoft",
"field": "activeApplicationName"
}
]
},
"sort": {
"fields": [
{
"direction": "ASC",
"name": "id"
}
]
}
}
}

Sample Response

{
"data": {
"deviceSearch": {
"edges": [
{
"node": {
"name": "DFR Dev Lab X52",
"id": "00a0dc617b05",
"connected:" true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "Studio X52",
"activeApplicationName": "Microsoft Teams",
"activeApplicationVersion": "1449/1.0.96.2025031102",
"room": {
"name": "Endor 301",
"floor": "3"
},
"connections": [
{
"name": "Trio C60",
"id": "64162ab36978",
"connected": true
},
{
"name": "Poly TC10",
"id": "00a0ca3ab0b4",
"connected": true
}
]
}
},
{
"node": {
"name": "Poly TC8",
"id": "00e0ca521c23",
"connected": true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "TC8",
"activeApplicationName": "Zoom",
"activeApplicationVersion": "6.4.2.6801",
"room": {
"name": "Endor 101",
"floor": ""
},
"connections": [
{
"name": "DFR Studio X30",
"id": "00c5ef345e2d",
"connected": true
}
]
}
},
],
"pageInfo": {
"countOnPage": 2,
"totalCount": 33,
"hasNextPage": true,
"nextToken": "cHknJlcjBueTMwZg=="
}
}
}
}

Combine OR: & AND: Filters

To extend the previous example, you can filter devices based on both Provider Mode (activeApplicationName) and Hardware Model (hardwareModel) using a combination of OR: and AND: filters.

The following is a query that returns devices where:

  • activeApplicationName contains Zoom or Microsoft, and

  • hardwareModel contains Studio X

Test this query in the GraphQL Playground

query StudioXZoomMsft($params: DeviceFindArgs) {
deviceSearch(params: $params) {
edges {
node {
name
id
connected
serialNumber
hardwareModel
activeApplicationName
activeApplicationVersion
room {
name
floor
}
connections {
name
id
connected
}
}
}
pageInfo {
countOnPage
totalCount
hasNextPage
nextToken
}
}
}

Variables

{
"params": {
"pageSize": 2,
"filter": {
"AND": [
{
"contains": "Studio X",
"field": "hardwareModel"
},
{
"OR": [
{
"contains": "Zoom",
"field": "activeApplicationName"
},
{
"contains": "Microsoft",
"field": "activeApplicationName"
}
]
}
]
},
"sort": {
"fields": [
{
"direction": "ASC",
"name": "id"
}
]
}
}
}

Sample Response

{
"data": {
"deviceSearch": {
"edges": [
{
"node": {
"name": "DFR Dev Lab X52",
"id": "00a0dc617b05",
"connected:" true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "Studio X52",
"activeApplicationName": "Microsoft Teams",
"activeApplicationVersion": "1449/1.0.96.2025031102",
"room": {
"name": "Endor 301",
"floor": "3"
},
"connections": [
{
"name": "Trio C60",
"id": "64162ab36978",
"connected": true
},
{
"name": "Poly TC10",
"id": "00a0ca3ab0b4",
"connected": true
}
]
},
},
{
"node": {
"name": "DFR StudioX70",
"id": "00f2cd543a5b",
"connected": true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "Studio X70",
"activeApplicationName": "Zoom Rooms",
"activeApplicationVersion": "6.1.0.5144",
"room": {
"name": "Jedi Enclave",
"floor": "2"
},
"connections": [
{
"name": "Poly TC8",
"id": "00e0ca2a5643",
"connected": false
},
{
"name": "Poly TC10",
"id": "00e0bc1ad311",
"connected": true
}
]
},
}
],
pageInfo": {
"countOnPage": 2,
"totalCount": 15,
"hasNextPage": true,
"nextToken": "Z2F4eHprc3eG92ZWE0NGt4"
}
}
}
}

Querying CCX Hardware Revisions

If you're using Poly Lens to manage your CCX inventory and need to identify which CCX 400 & 500 hardware revisions have been deployed, you can use the Lens APIs to aggregate this data programmatically.

There are two ways to accomplish the task using Lens APIs:

  1. Use the GraphQL Playground to run the query and export the results to .csv.
    1. This approach is best for those who don't write code or scripts.
    2. You'll use Excel to format the .csv results.
  2. Grab the example Query and Arguments from the GraphQL Playground and implement them into your scripting language of choice.
    1. This requires more upfront work but removes the need to parse the data through external tools.

This article details using the GraphQL Playground to query the data and export the results to .csv.

For those using the GraphQL Playground, we'll break the process down into these steps:

  1. Query Structure
    1. Tenants with < 500 CCXs
    2. Tenants with > 500 CCXs
  2. Formatting the .csv Data in Excel
    1. Text to Columns Wizard
    2. Creating Column Headers
    3. Removing Remaining Characters
    4. Format as Table
Reminder

The API Playground is scoped to your authenticated user's access. To scope the data to a specific tenant, you can either create an API Connection or pass a tenantId directly into the arguments of the pre-configured example query.

Query Structure

We'll use the deviceSearch query to return each CCX device's name, hardwareModel, macAddress, hardwareRevision, softwareVersion, room and site. These fields provide the core details required to accomplish the task. If you don't use room or site assignments, or if certain fields aren't relevant to your use case, you can remove them from the query and proceed.

In the Variables section, we filter by hardwareModel to return only CCX 400 and 500 devices. The pageSize is set to 500 CCXs to retrieve more results per request and reduce the number of API calls, helping to avoid rate-limiting.

To determine the total number of CCX devices in your Account (Tenant), run the query and check the totalCount field in the pageInfo response.

If the totalCount is less than 500, refer to Tenants with < 500 CCXs.

If the totalCount exceeds 500, refer to the Tenants with > 500 CCXs.

Access this query in the GraphQL Playground

Poly GraphQL Playground operation and variables image

Tenants with < 500 CCXs

If pageCount returned less than 500 devices, click the table icon in the Response section of the user interface. The results will appear in a table view and display a .csv download button. Download the .csv and proceed to Formatting the .csv Data in Excel.

Poly GraphQL Playground response with csv download

Tenants with > 500 CCXs

The pageInfo fields contain the information required to use pagination. Of the four fields, nextToken is the one we need to use. The Variables > params > nextToken field will be null the first time you run the query.

Poly GraphQL Playground variables field with null nextToken field

Now, run the query and look at the Response section. If the totalCount exceeds the pageSize, nextToken will contain an alphanumeric string.

Poly GraphQL Playground query response with nextToken string

Click the table icon and look at the edges row. You'll see an option to download the .csv results.

Poly GraphQL Playground Pass nextToken String into Arguments

Copy the nextToken string from the query response and paste it into the Variables > params > nextToken field before running the query to fetch the next batch of results. Make sure you download the .csv each time you run the query and fetch the next batch of results.

Poly GraphQL Playground Pass nextToken String into Arguments

Continue copying the nextToken, running the query, and downloading the csv until the response returns nextToken: null.

Poly GraphQL Playground Pass nextToken String into Arguments

Formatting the .csv Data in Microsoft Excel

Each CCX we've queried has the same key and value format. The goal is to create a usable Excel table by filtering/parsing the unnecessary characters, removing the duplicate keys, and creating a column with a single key (as a header) for each CCX corresponding value.

This section covers the more accessible, manual way to format the query results in Excel. If you're an Excel power user, this section won't be helpful for you. Feel free to skip it and perform the Excel formatting magic of your choice.

We'll start by ensuring we have a single .csv as our primary document. If you have less than 500 devices and only one .csv file, you saved a little work and should proceed to the Text to Columns Wizard.

If you have greater than 500 devices and have downloaded multiple .csv files, open the first one and delete row A1. This file will be our primary working document.

For each additional .csv, the process remains the same. Open the file and cut/paste all rows (except A1) into the primary document. After you've moved all rows to the primary document, the result/structure of the file will look similar to this.

Excel formatting and combining all csv&#39;s into a single file

Text to Columns Wizard

The data for each device is in the first cell of each row, even though it spans across the table. To filter and parse this information, select all in Column A, click the Data tab, and click Text to Columns.

Select all data in column A, click data tab, and click text to columns wizard

Text to Columns has limitations, so we can't parse all characters in a single step. However, it gets us most of the way there.

Text to Columns - Step 1 of 3: Choose the Delimited character type and click Next.

text to columns step 1 choose delimited character type

Text to Columns - Step 2 of 3: In the Delimiters section, select Comma, Other, and add a colon (:) into the field.

text to columns step 2 select delimeters comma, other, add semicolon for other

Text to Columns - Step 3 of 3: Select General in the Column data format field. Click Finish.

text to columns step 3 select general column data format

Creating Column Headers

The next step is to create column headers for the values. First, insert a new row at the top of the table. Then, you can cut/paste the key into the row's corresponding column or type it manually. The .csv splits the site name and room name into separate columns. Combine these values into a single column header. Now, you can select and delete all columns containing the same key.

create column headers and delete columns with repetitive keys

Removing Remaining Characters

The } is the last character we need to remove. Using Find and Replace, add a } in the Find what field and a blank space in the Replace with field. Click Replace All and the result is a cleanly formatted table.

find curly bracket and replace with a blank space

Format as Table

Select all the data cells and use Format as Table to make the table easier to read and filter. During this step, make sure to select My table has headers.

format at table with headers

prettier table with filtering

You have now used the GraphQL Playground to query data from your Poly Lens Account (Tenant), parsed the results, and created a usable table to drill into the details. Nice work! 👏🏼

If you have questions about usage, authentication, or integration with the Poly Lens APIs, contact us.