# Filtering Devices

> Filter the device list with $filterV2: conditions, operators, fields and inventory filters.

Source: https://docs.capaone.com/capaone/mcp-and-api/filtering-devices/  
Product: CapaOne — a separate CapaSystems product; do not apply this page to any other.

The device list takes a structured `$filterV2` document in its `filter` query parameter. So does
`device/group-by`, which counts the devices per value of a field. The MCP server's `search_devices`
and `group_devices` tools use the same conditions.

## Structure

```text title="filter"
{
  "$filterV2": {
    "search": "laptop",
    "anyOf": [
      { "allOf": [ <condition>, <condition> ] },
      { "allOf": [ <condition> ] }
    ]
  }
}
```

- `anyOf` holds groups combined with **OR**. A device matches if it matches any group.
- Each group's `allOf` holds conditions combined with **AND**.
- `search` is free text matched against `name`, `userInventory.fullName` and
  `userInventory.userPrincipalName`. With both `search` and `anyOf`, a device must match both.
- Without a `filter` parameter, every device is returned.

URL-encode the JSON when you put it in the query string.

## Conditions

```json title="condition"
{
  "field": "software.failedPatchCount",
  "operator": "GT",
  "values": ["0"],
  "negate": false
}
```

- `field`: a field from the tables below.
- `operator`: one of that field's operators.
- `values`: one or more values, always as strings, also for numbers, booleans and dates, for
  example `["16"]` or `["true"]`.
- `negate`: optional. `true` inverts the condition, so `CONTAINS` becomes "does not contain". On an
  inventory field, it matches the devices that have no such row. It doesn't pick out the other rows:
  to leave rows out, for example Microsoft's applications, request them all and drop those yourself.

## Operators

| Operator | Matches when |
|---|---|
| `EQ` | Equal to the value. |
| `IN` | Equal to any of the values. |
| `CONTAINS` | Contains any of the values (OR). |
| `STARTS_WITH / ENDS_WITH` | Starts or ends with the value. |
| `ALL` | The array contains every one of the values. `tags` only. |
| `GT / GTE / LT / LTE` | Greater than, greater than or equal, less than, less than or equal. Numbers and dates. |
| `EXISTS` | The field has a value. An empty list, such as a device without tags, has none. The value must be exactly `"true"` or `"false"`. |
| `WITHIN_LAST_DAYS / _WEEKS / _MONTHS / _YEARS` | Dates only, counted back from now: `WITHIN_LAST_DAYS` `["1"]` is the last 24 hours. The value must be one positive whole number, for example `["30"]`. |

| Field type | Operators |
|---|---|
| `STRING` | EQ, CONTAINS, STARTS_WITH, ENDS_WITH, IN, EXISTS |
| `NUMBER` | EQ, GT, GTE, LT, LTE, IN, EXISTS |
| `BOOLEAN` | EQ, EXISTS |
| `DATE` | EQ, GT, GTE, LT, LTE, EXISTS, WITHIN_LAST_DAYS, WITHIN_LAST_WEEKS, WITHIN_LAST_MONTHS, WITHIN_LAST_YEARS |
| `ID` | EQ, IN, EXISTS |

## Fields

| Field | Type | Notes |
|---|---|---|
| `id` | ID | Alias for `_id`. |
| `_id` | ID | |
| `name` | STRING | |
| `deviceType` | STRING | |
| `online` | BOOLEAN | |
| `virtual` | BOOLEAN | |
| `state` | STRING | |
| `lastUpdate` | DATE | |
| `lastCheckIn` | DATE | |
| `osName` | STRING | |
| `osVersion` | STRING | |
| `platform` | STRING | |
| `osSerial` | STRING | |
| `motherboardUuid` | STRING | |
| `motherboardSerial` | STRING | |
| `tags` | STRING | An array. Also supports `ALL`. |
| `webUrl` | STRING | |
| `agentVersion` | STRING | |
| `osStartUp` | DATE | |
| `serviceStartUp` | DATE | |
| `software.compliant` | BOOLEAN | |
| `software.patchCount` | NUMBER | |
| `software.failedPatchCount` | NUMBER | |
| `software.severity` | STRING | |
| `driver.compliant` | BOOLEAN | |
| `driver.patchCount` | NUMBER | |
| `driver.isSupported` | BOOLEAN | |
| `userInventory.userPrincipalName` | STRING | |
| `userInventory.fullName` | STRING | |

## Inventory fields

You can also filter on these fields of a device's hardware, software and driver inventory, spaces
included. Any other field of these inventories returns `400`.

- `hardwareInventory.<Category>.<Field>`: one row per disk, battery and so on in that category.
- `softwareInventory.<Field>` and `driverInventory.<Field>`: one row per application or driver.

| Field | Type |
|---|---|
| `hardwareInventory.Computer.Manufacturer` | STRING |
| `hardwareInventory.Computer.Model` | STRING |
| `hardwareInventory.Memory.Total Memory.value` | NUMBER |
| `hardwareInventory.Processors.Cores` | NUMBER |
| `hardwareInventory.Drives.Name` | STRING |
| `hardwareInventory.Drives.Size.value` | NUMBER |
| `hardwareInventory.Drives.Free Space.value` | NUMBER |
| `hardwareInventory.Drives.Encrypted` | BOOLEAN |
| `hardwareInventory.Disks.Name` | STRING |
| `hardwareInventory.Disks.Size.value` | NUMBER |
| `hardwareInventory.Batteries.Maximum Capacity.value` | NUMBER |
| `hardwareInventory.Bios Information.Manufacturer` | STRING |
| `hardwareInventory.Bios Information.Version` | STRING |
| `hardwareInventory.System Information.Manufacturer` | STRING |
| `hardwareInventory.Operating System.Architecture` | STRING |
| `hardwareInventory.Operating System.Has Pending Reboot` | BOOLEAN |
| `hardwareInventory.Trusted Platform Module.Enabled` | BOOLEAN |
| `softwareInventory.Name` | STRING |
| `softwareInventory.Version` | STRING |
| `softwareInventory.Publisher` | STRING |
| `softwareInventory.InstallDate` | DATE |
| `softwareInventory.Size` | NUMBER |
| `softwareInventory.IsSystemComponent` | BOOLEAN |
| `softwareInventory.UserAccount` | STRING |
| `softwareInventory.AppCode` | STRING |
| `softwareInventory.Language` | STRING |
| `softwareInventory.Platform` | NUMBER (32 or 64) |
| `softwareInventory.Uninstall` | STRING |
| `softwareInventory.UpgradeCode` | STRING |
| `driverInventory.Name` | STRING |
| `driverInventory.Driver Version` | STRING |
| `driverInventory.Driver Date` | DATE |
| `driverInventory.Manufacturer` | STRING |

## Custom inventory fields

Custom inventory is data your organization's own scripts write on its devices with
[`$cs.CustomInventory_SetValue`](/capainstaller/powerpacks/cs-custominventory-setvalue/), for
example a device's office location.
[Getting Started with Custom Inventory](/capaone/windows-management/getting-started-with-custom-inventory/)
walks you through a first script. The fields are your organization's own, so this page can't list
them. `GET …/mcp/customInventory/fields` lists the ones your devices report, and the MCP tool
`list_filterable_fields` includes them:

```json title="GET …/mcp/customInventory/fields"
[
  {
    "category": "Installations",
    "field": "Installer Size",
    "path": "customInventory.Installations.Installer Size.value",
    "type": "NUMBER",
    "unit": "bytes",
    "devices": 180
  },
  {
    "category": "Office",
    "field": "City",
    "path": "customInventory.Office.City",
    "type": "STRING",
    "unit": null,
    "devices": 212
  }
]
```

- Use a field's `path` in a condition, to choose the fields a search returns, in `orderBy` and as
  the `field` of `device/group-by`. A field your devices don't report returns `400`.
- A field takes the operators of its `type`, listed under [Operators](#operators).
- A value with a unit, such as a size or a date, has a `path` that ends with `.value`. Filter on it
  in that unit: `Installer Size` above is in bytes.
- A category holds one or more instances, for example one per application, each named by its
  `Instance` field. A condition matches a device when one of its instances matches. Conditions on
  the same category in one `allOf` group must match the same instance.
- `devices` is how many devices report the field. The list is updated every hour, so a field a
  device reports for the first time can be filtered on within an hour. The list holds at most 1,000
  fields, the ones most devices report.

The devices that report version 24.08 of 7-Zip, as an instance of the Installations category:

```json title="filter"
{
  "$filterV2": {
    "anyOf": [
      {
        "allOf": [
          { "field": "customInventory.Installations.Instance", "operator": "EQ", "values": ["7-Zip"] },
          { "field": "customInventory.Installations.Version", "operator": "EQ", "values": ["24.08"] }
        ]
      }
    ]
  }
}
```

## Choosing fields

By default each device comes back as a summary. Add `projection` to get exactly the fields you
need instead, for example `projection=name,motherboardSerial,hardwareInventory.Computer.Model`:

```json title="device"
{
  "id": "6750a85194b9b276ae01744a",
  "name": "DKSOLLAP014",
  "motherboardSerial": "PW0EYTGZ",
  "hardwareInventory.Computer.Model": ["ThinkPad P1 Gen 7"]
}
```

- Any field you can filter on, including inventory fields, at most 20. An unknown field returns
  `400`.
- `orderBy` takes the same field names, for example
  `orderBy=hardwareInventory.Computer.Model,desc`. An unknown field returns `400`.
- `id` is always included.
- Inventory fields come back as a list, one value per disk, battery, application or custom
  inventory instance.
- With conditions on that inventory in every `anyOf` group, only the rows the filter matched come
  back. Filtering on `softwareInventory.Name` TeamViewer and asking for
  `softwareInventory.Version` gives the TeamViewer version alone.
- Software and driver fields need such a filter, or the request returns `400`. For all applications
  of one device, use the `get_device` MCP tool with `include` `software`. Hardware and custom
  inventory fields without one return every row.

## Examples

Online devices with missing software patches, or devices tagged both finance and laptop:

```json title="filter"
{
  "$filterV2": {
    "anyOf": [
      {
        "allOf": [
          { "field": "online", "operator": "EQ", "values": ["true"] },
          { "field": "software.compliant", "operator": "EQ", "values": ["false"] }
        ]
      },
      {
        "allOf": [
          { "field": "tags", "operator": "ALL", "values": ["finance", "laptop"] }
        ]
      }
    ]
  }
}
```

Devices with 8 or more CPU cores and an unencrypted drive:

```json title="filter"
{
  "$filterV2": {
    "anyOf": [
      {
        "allOf": [
          { "field": "hardwareInventory.Processors.Cores", "operator": "GTE", "values": ["8"] },
          { "field": "hardwareInventory.Drives.Encrypted", "operator": "EQ", "values": ["false"] }
        ]
      }
    ]
  }
}
```

:::note[Invalid filters]
An unknown field, an operator the field doesn't support or a malformed value returns `400` with a
message naming the problem. Nothing is silently ignored.
:::
