Usage

1) Overview

Endpoints

  • GET /lce/api/device_classes (filters optional)

  • GET /lce/api/device_classes/{device_class_identifier} (ID, GUID, or name)

  • POST /lce/api/device_classes (create or update, keyed by GUID)

  • DELETE /lce/api/device_classes/{device_class_identifier} (ID, GUID, or name)

  • GET /lce/api/icons (the icons that can be assigned)

  • GET /lce/api/device_classes/{device_class_identifier}/icon

  • PUT /lce/api/device_classes/{device_class_identifier}/icon (assign or unassign)

The Device Classes API lists, creates, updates and deletes device classes. No other platform API authors device classes, so until now a PowerPack that needed one had to write the master.definitions_dev_classes table directly. This API replaces those direct database writes with validated, audited changes that keep the device class’s PowerPack revision up to date.

A device class is what discovery assigns a device to, and what Dynamic Applications are aligned with:

  • Discovery matches a device against the identifiers of the device classes (class_identifier_1, class_identifier_2, discovery_qualifier and the agent identifiers) to decide which device class it belongs to

  • Dynamic Applications are aligned with a device class through its class_type, a number allocated by the platform when the device class is created

Important

A device class is keyed by its GUID, not its id. A device class authored on one system, for example as part of a PowerPack, keeps its GUID on every other system it is installed on, while its id and class_type are allocated locally and differ from system to system. POST therefore creates or updates by guid: see 6) Creating and updating device classes.

Query parameters

The query parameters behave as they do in the Dynamic Applications API, which documents them in full.

pretty (GET + POST)

All endpoints that return device classes support a pretty boolean query parameter. Defaults to true.

  • pretty=true

    • Enums are serialized as their string names ("device_type": "COMPONENT")

  • pretty=false

    • Enums are serialized as their integer values ("device_type": 2)

Note

Regardless of pretty, request payloads accept enums as either integers or string names (case-insensitive).

fields and exclude (GET + POST)

fields is an optional comma-separated allowlist of the fields to include in the response, and exclude an optional comma-separated blocklist of the fields to remove from it. When both are provided, fields is applied first, then exclude. On POST they only apply to the entities returned with retrieve=true.

  • Return only the identifiers of every device class: fields=id,guid,class_name,description

  • Leave out the system-specific fields: exclude=id,class_type,last_edited

fields and exclude affect response serialization only. A path that does not exist is ignored (no error). validation_errors is always included when present, whatever fields and exclude specify.

retrieve (POST only)

POST /lce/api/device_classes supports a retrieve boolean query parameter. Defaults to false.

  • retrieve=true: the response includes an entities list with each device class as it is stored after the request, in payload order. This is how to read back the id, guid and class_type allocated to a new device class.

  • retrieve=false: the response includes only the results list.

commit (POST + DELETE)

POST /lce/api/device_classes and DELETE /lce/api/device_classes/{device_class_identifier} support a commit boolean query parameter. Defaults to true.

  • commit=true: the changes are committed.

  • commit=false: the request runs exactly as it would otherwise, validation included, and is then rolled back, so nothing is changed. The response is the one the committed request would have returned. Combine it with retrieve=true on POST to preview the resulting device classes, or use it on DELETE to check whether a device class can be deleted.

require_all_filters and filter[...] (GET list only)

GET /lce/api/device_classes accepts filters of the forms:

filter[<field>][<operator>]=<value>
filter[<field>][not][<operator>]=<value>

The supported operators are is, contains, gt (single value only), lt (single value only) and search (single value only, not negatable). Values may be comma-separated to express multi-value matching, and for is the special value null (case-insensitive) is a SQL NULL check on the fields that accept null, such as pp_guid.

When multiple filters are provided, require_all_filters controls how they are combined:

  • require_all_filters=true: all filters must match (AND logic). This is the default.

  • require_all_filters=false: any filter may match (OR logic).

Every stored field of a device class can be filtered on: id, guid, class_name, description, category (by id), device_type, is_snmp, class_identifier_1, class_identifier_2, discovery_qualifier, agent_identifier_1, agent_identifier_2, root_device, weight, tier_id, image, pp_guid, class_type and last_edited. category_name is not a stored field and cannot be filtered on.

Note

Unlike the other listing endpoints of this service, filters are optional. With no filter[...] parameter, GET /lce/api/device_classes lists every device class. When filters are provided and match nothing, the response is 404; with no filters, an empty system returns 200 with an empty list.

limit and offset (GET list only)

GET /lce/api/device_classes pages through the device classes, ordered by id:

  • limit: the maximum number of device classes to return. Defaults to all of them.

  • offset: the number of matching device classes to skip. Defaults to 0.

Both must be non-negative integers; anything else is rejected with 400. An empty value, such as limit=, is the same as leaving the parameter out. Paging applies after the filters, and a page past the last match is an empty device_classes list rather than a 404, whether or not filters are provided. For example, the second page of 100:

GET /lce/api/device_classes?limit=100&offset=100

2) Authentication & Authorization

Authentication

Requires a valid Skylar One user session.

Access Hooks

To call GET /lce/api/device_classes, GET /lce/api/device_classes/{device_class_identifier}, GET /lce/api/icons or GET /lce/api/device_classes/{device_class_identifier}/icon you must have the following Access Hook:

  • DEV_CLASS_VIEW

To call POST /lce/api/device_classes or DELETE /lce/api/device_classes/{device_class_identifier} you must have the following Access Hooks:

  • DEV_CLASS_VIEW

  • SYS_CUSTOM_DEV_CLASS_PAGE

To call PUT /lce/api/device_classes/{device_class_identifier}/icon you must have the following Access Hooks:

  • DEV_CLASS_VIEW

  • DEV_CLASS_EDIT

DEV_CLASS_EDIT is the hook the GraphQL setDeviceClassIcon mutation checks, not SYS_CUSTOM_DEV_CLASS_PAGE. See 8) Device class icons.


3) The device class

A device class is stored in master.definitions_dev_classes. The API names its fields rather than exposing the column names, several of which are misspelled or misleading in the table.

Field

Type

Column

Required / default

Description

id

integer

id

read-only

The numeric id of the device class on this system. Allocated by the database; it is not portable between systems.

guid

GUID

devtype_guid

generated when omitted

The identity of the device class: 32 hexadecimal characters, in either case (many device classes shipped with the platform have lowercase GUIDs). The value is kept as provided, and lookups by GUID ignore case. It cannot change once the device class exists. See 6) Creating and updating device classes.

class_name

string (1 to 64)

class

required on create

The class of the device class, typically the vendor or platform, such as Microsoft.

description

string (1 to 64)

descript

required on create

The description of the device class, typically the model or type, such as Windows Server 2019.

category

integer

family

required on create

The id of the device category the device class belongs to. A payload may provide the id, the GUID or the exact name of the category. See Categories.

device_type

enum

virtual

PHYSICAL

Whether the device class describes physical, virtual or component devices. See Device types.

is_snmp

boolean

is_snmp

false

Whether devices of the device class are discovered over SNMP. See Identifier rules.

class_identifier_1

string (0 to 255)

identifyer_1

""

The first identifier discovery matches devices against: the sysObjectID of an SNMP device class, or the first class identifier of a component device class.

class_identifier_2

string (0 to 255)

identifyer_3

""

The second identifier discovery matches devices against: the second class identifier of a component device class, or the value the discovery_qualifier OID must have for an SNMP device class. Stored in the identifyer_3 column.

discovery_qualifier

string (0 to 255)

identifyer_2

""

The OID whose value must equal class_identifier_2 for an SNMP device to match the device class.

agent_identifier_1

string (0 to 255)

agent_identifier_1

""

The first identifier agent discovery matches devices against.

agent_identifier_2

string (0 to 255)

agent_identifier_2

""

The second identifier agent discovery matches devices against.

root_device

boolean

root_device

false

Whether devices of the device class are the root of a component tree.

weight

integer (1 to 10)

weight

1

The precedence of the device class when several device classes match a device.

tier_id

integer (0 or more)

tier_id

0

The device class tier the device class belongs to: the id of a row of master.definitions_dev_class_tiers, or 0 for “No Tier”.

image

string (1 to 32)

image

"_generic_unknown.png"

The legacy PNG image file of the device class. Its icon is set with its own endpoint, see 8) Device class icons.

pp_guid

GUID or null

ppguid

null

The GUID of the PowerPack the device class belongs to, in either case. It must be the GUID of a PowerPack installed on the system.

class_type

integer

class_type

read-only

The number Dynamic Applications are aligned with. Allocated when the device class is created and never changed. See Class types.

last_edited

string or null

date_edit

read-only

When the device class was last edited, as an ISO 8601 timestamp such as 2026-01-05T10:00:00. null for a device class that has never been edited.

category_name

string or null

(from the category)

read-only

The name of the category the device class belongs to, for display.

validation_errors

array

(none)

read-only

Only present on a device class whose stored values fail validation. See 10) Validation & error responses.

String values have leading and trailing whitespace removed. A field the model does not define is rejected with 422, and text that cannot be stored as latin1 is rejected with 422.

Note

The platform shows a device class by its name: its class_name and description joined by " | ", such as Microsoft | Windows Server 2019. The name is not a field of the device class, but it is what the name of the results of POST and DELETE contains, and it is accepted wherever a device class identifier is. Names are not unique: several device classes can share a class and description, told apart by their identifiers. See 4) Identifying a device class.

Device types

device_type is stored in the virtual column as an integer. It is serialized by name with pretty=true (the default) and by value with pretty=false, and either is accepted in a payload:

Name

Value

Meaning

PHYSICAL

0

A physical device, typically discovered by its sysObjectID.

VIRTUAL

1

A virtual device, created rather than discovered.

COMPONENT

2

A component device, discovered by a Dynamic Application of its parent device.

Class identifiers

The identifiers are what discovery matches a device against to choose its device class. What each one means depends on the kind of device class:

  • SNMP device class (is_snmp true): class_identifier_1 is the sysObjectID devices are matched against. To tell apart devices that share a sysObjectID, a discovery qualifier can be added: discovery_qualifier is an OID, and class_identifier_2 the value it must have.

  • Component device class (device_type COMPONENT): class_identifier_1 and class_identifier_2 are the class identifiers the discovering Dynamic Application reports.

  • Agent discovery: agent_identifier_1 and agent_identifier_2 are matched against what the agent reports.

All of them default to an empty string. Note the column names: class_identifier_2 is stored in identifyer_3, and discovery_qualifier in identifyer_2.

For example, an SNMP device class qualified by the value of sysDescr:

{
  "class_name": "Cisco Systems",
  "description": "Catalyst 9300",
  "category": "Network",
  "device_type": "PHYSICAL",
  "is_snmp": true,
  "class_identifier_1": "1.3.6.1.4.1.9.1.2494",
  "discovery_qualifier": "1.3.6.1.2.1.1.1.0",
  "class_identifier_2": "Catalyst 9300"
}

Identifier rules

The identifiers must be consistent with the kind of device class. These are the rules of the platform’s own device class editor, and a device class that breaks one is rejected with 422:

  • A COMPONENT device class cannot have is_snmp true.

  • A PHYSICAL device class with is_snmp true must have a numeric OID as its class_identifier_1 (such as 1.3.6.1.4.1.9.1.2494, a leading dot is allowed), unless agent_identifier_1 is set.

  • On such a device class, when discovery_qualifier or class_identifier_2 is set, discovery_qualifier must be a numeric OID.

  • A device class that is neither SNMP nor a component must have an empty class_identifier_1.

The rules are checked against the complete result of a request, so a stored device class that breaks one is rejected on every update, whatever field the update changes, until the payload fixes it. Every broken rule is listed in the error message.

Categories

Every device class belongs to a device category (master.definitions_dev_cats), such as Servers or Network. In a payload, category accepts any of:

  • the id of the category, as an integer or a string of digits (901 or "901")

  • the GUID of the category (its family_guid), in either case, such as "B3A8C1E0D0F4C1A2B3C4D5E6F7A8B9C0"

  • the exact name of the category, such as "Servers"

A response always returns category as the id, together with the read-only category_name. The category’s GUID is stored with the device class (family_guid) and kept in step whenever the category changes.

A request is rejected with 422 when no category matches, or when the name matches several categories (category names are not unique); provide the id or the GUID of the category instead.

Note

The id of a category is local to the system, like the id of a device class. When copying a device class to another system, set category to the GUID or the name of the category rather than sending the retrieved id, which may name a different category there, or none. category_name is read-only and is discarded from a payload, so it cannot be used to set the category.

Class types

class_type is what Dynamic Applications are aligned with, and what devices record as their device class. It is allocated by the service when a device class is created, as the next number after the highest class_type in use, and it never changes afterwards. Concurrent creations wait for one another rather than allocating the same number.

class_type is read-only: it is returned by every read, and discarded from every payload. A device class keeps its guid across systems but not its class_type.


4) Identifying a device class

GET and DELETE on /lce/api/device_classes/{device_class_identifier} accept any of:

  • the numeric id, such as 5001. A numeric identifier is treated as an id, unless it is a 32-digit GUID.

  • the GUID, such as 1F2E3D4C5B6A79881F2E3D4C5B6A7988, in either case

  • the name: the class and description joined by " | ", such as Microsoft | Windows Server 2019

The same applies to GET and PUT on /lce/api/device_classes/{device_class_identifier}/icon.

Important

Requests that change a device class only accept an exact name. DELETE /lce/api/device_classes/{device_class_identifier} and PUT /lce/api/device_classes/{device_class_identifier}/icon accept an id, a GUID or an exact name, and are never fuzzy matched, so a typo cannot select another device class. A name without an exact match returns 404:

{
  "error": "Device Class Not Found",
  "matches": [],
  "message": "No device class found named exactly: Microsoft | Windows Server 2091",
  "success": false
}

The GET endpoints still match names approximately, as described below.

A name is looked up by exact match first. When exactly one device class has the name, it is used. Names are not unique, and when several device classes have the name, the response is 404 with their GUIDs in matches; use one of them instead:

{
  "error": "Device Class Not Found",
  "matches": [
    "2A3B4C5D6E7F80912A3B4C5D6E7F8091",
    "a7c3e9f1b5d2486c9e0f1a2b3c4d5e6f"
  ],
  "message": "Several device classes are named 'Cisco Systems | Catalyst 9300'. Provide the GUID of the device class instead. Their GUIDs are in the matches field",
  "success": false
}

On the GET endpoints, when there is no exact match and the name is at most 64 characters long, it is matched approximately, and a confident fuzzy match is used. When the fuzzy match is not confident, the response is 404 with the closest names in matches:

{
  "error": "Device Class Not Found",
  "matches": [
    "Microsoft | Windows Server 2019",
    "Microsoft | Windows Server 2022"
  ],
  "message": "Device Class name is too ambiguous. There were multiple Device Classes that matched. Please provide a more specific name. Provided name: Microsoft Windows Server. Similar matches found in matches field",
  "success": false
}

A name longer than 64 characters (after removing surrounding whitespace) is only looked up by exact match, and returns 404 with no matches when there is none: No device class found named exactly: <name>.

Note

A name is used as-is in the path, URL-encoded as usual. It contains spaces and a |: Microsoft | Windows Server 2019 is Microsoft%20%7C%20Windows%20Server%202019. A name may also contain a /, as hundreds of the platform’s device classes do (such as 3Com | 3Com NB:G crew dualwide w/Ae); the path accepts it. Encoding it as %2F makes no difference, as the server decodes the path before routing it. The one exception is a name that ends in /icon, which the path cannot tell apart from the icon endpoints of section 8: address such a device class by its id or GUID. Prefer the GUID in automation: it is exact, unique and portable.


5) Retrieving device classes

GET /lce/api/device_classes

Lists the device classes, ordered by id. With no filter[...] parameter every device class is listed; with filters, only the device classes that match.

{
  "device_classes": [
    {
      "agent_identifier_1": "",
      "agent_identifier_2": "",
      "category": 901,
      "category_name": "Servers",
      "class_identifier_1": "1.3.6.1.4.1.311.1.1.3.1.3",
      "class_identifier_2": "",
      "class_name": "Microsoft",
      "class_type": 5001,
      "description": "Windows Server 2019",
      "device_type": "PHYSICAL",
      "discovery_qualifier": "",
      "guid": "1F2E3D4C5B6A79881F2E3D4C5B6A7988",
      "id": 5001,
      "image": "_generic_unknown.png",
      "is_snmp": true,
      "last_edited": "2026-01-05T10:00:00",
      "pp_guid": "6450441E71B0EB1933D18A6C6252CF28",
      "root_device": false,
      "tier_id": 0,
      "weight": 1
    }
  ]
}

GET /lce/api/device_classes/{device_class_identifier}

Returns one device class, by id, GUID or name (see 4) Identifying a device class), as a single object in the same form as an entry of device_classes.

Reads never fail because of stored data. A device class written outside this API can hold values that fail validation, such as an empty description; it is returned as stored, with a validation_errors list describing each problem:

"validation_errors": [
  {"field": "description", "message": "String should have at least 1 character"}
]

A retrieved device class is a valid payload

Every device class returned by a GET (or in the entities of a POST) can be sent straight back to POST /lce/api/device_classes. The read-only fields category_name, class_type, last_edited and validation_errors are discarded from payloads, and the other fields are compared with what is stored, so sending back an unchanged device class writes nothing.

To change a device class, retrieve it, edit the fields that need to change, and post it back. A device class with validation_errors is rejected with 422 until the invalid values are corrected in the payload.


6) Creating and updating device classes

POST /lce/api/device_classes

Creates or updates one or more device classes. The request body is any of:

  • a single device class object

  • an array of device class objects

  • an object with a device_classes array, which is the form GET /lce/api/device_classes returns

The request must be sent as JSON with a Content-Type of application/json.

GUID-keyed upsert

Each device class of the payload is matched to a stored device class by its guid:

Payload

Result

guid of an existing device class, in either case

Updates that device class. Its stored GUID is kept, and returned, whatever the case of the payload’s. Only the fields provided are applied, merged with the stored values, and only the fields whose value actually changes are written. Any id is ignored.

guid that does not exist on the system

Creates a device class with that GUID, kept in the case provided. Any id is ignored.

no guid

Creates a device class with a generated GUID.

id without a guid

Rejected with 400. A device class is not updated by id: provide the guid of the existing device class to update it, or omit the id to create one. This is checked before anything else about the device class, such as its category.

The GUID is the key of a device class and its id is local to a system, so a provided id never selects or changes anything: a device class copied from another system keeps its GUID but not its id.

class_name, description and category are required to create a device class; every other field has a default (see the table in section 3). An update needs only the guid and the fields that change:

{
  "guid": "1F2E3D4C5B6A79881F2E3D4C5B6A7988",
  "weight": 10
}

The whole payload is handled in a single transaction. Every device class is validated before any is written, and if any device class fails, nothing is written.

Validation rules

Beyond the type and range of each field, a device class must satisfy, against the complete result (the stored values updated with the payload):

  • Its identifiers are consistent with its kind. See Identifier rules.

  • Its category exists. category must resolve to exactly one category (see Categories).

  • Its tier exists. tier_id, when not 0 (“No Tier”), must be the id of a row of master.definitions_dev_class_tiers.

  • Its PowerPack exists. pp_guid, when not null, must be the GUID of a PowerPack installed on the system.

  • Its text can be stored. Every string must be encodable as latin1.

  • Its GUIDs are unique in the payload. The same guid may not appear twice, compared without regard to case (400).

Device classes may share a class_name and description, as they do on the platform; the name is not a uniqueness rule.

A rule that fails rejects the whole request with 422 (400 for a duplicate GUID), naming the device class and the rule.

PowerPack revisions and the audit log

Every device class that is created or changed is recorded in the audit log, such as User 'em7admin' added a Device Class named 'Acme | Gadget Component', ID: 5004. The revision of each PowerPack whose device classes change is incremented, by the number of its device classes that changed. A device class moved from one PowerPack to another increments both. A PowerPack that is no longer installed is skipped, so a device class whose PowerPack was removed can still be updated and deleted.

A device class that is posted unchanged writes nothing: it is not audited, it does not increment a revision, and its last_edited is not updated. Its entry in results has "new": false, like an update.

Response

{
  "results": [
    {
      "guid": "7C1D9E2B4A6F48B1A3C5D7E9F0B2C4D6",
      "id": 5004,
      "name": "Acme | Gadget Component",
      "new": true
    }
  ],
  "success": true
}

results holds one entry per device class, in payload order: its id, guid, name and whether it is new. With retrieve=true, the response also holds an entities list with each device class as stored, in the same order.


7) Deleting a device class

DELETE /lce/api/device_classes/{device_class_identifier}

Deletes a device class, identified by id, GUID or name (see 4) Identifying a device class).

{
  "result": {
    "guid": "3B4C5D6E7F8091A23B4C5D6E7F8091A2",
    "id": 5003,
    "name": "Acme | Widget Component"
  },
  "success": true
}

Important

A device class that is in use cannot be deleted. When devices belong to the device class, or Dynamic Applications are aligned with it (both through its class_type), the request is refused with 409 and a references object listing what still uses it:

{
  "error": "Device Class In Use",
  "message": "Device class 'Cisco Systems | Catalyst 9300' cannot be deleted while it is in use: 1 device(s) belong to it and 1 Dynamic Application(s) are aligned to it",
  "references": {
    "devices": 1,
    "dynamic_applications": [
      {
        "guid": "0F1E2D3C4B5A69780F1E2D3C4B5A6978",
        "id": 1207,
        "name": "Cisco: Catalyst Inventory"
      }
    ]
  },
  "success": false
}

devices is the number of devices of the device class, and dynamic_applications the id, guid and name of each Dynamic Application aligned with it. Reassign or delete the devices and unalign the Dynamic Applications before deleting the device class.

Note

This is stricter than the platform’s own device class editor, which refuses a deletion only when devices belong to the device class, and silently unaligns its Dynamic Applications. This API also refuses while Dynamic Applications are aligned, so that an alignment is never removed as a side effect of a deletion.

Deleting a device class also deletes its icon assignment (its row in master_ap2.dev_class_icon) and its legacy fallback icon mapping (its row in master.definitions_dev_class_svg_icons), invalidates the platform’s device class cache (the ent_device_class entry of master.cache_data), as the platform’s editor does, records the deletion in the audit log and increments the revision of its PowerPack, unless that PowerPack is no longer installed.

The device class cache is invalidated on deletion only. Creating and updating a device class leave it alone, as the platform’s device class editor does.

With commit=false, the deletion is validated, the response is the one a committed deletion would return (including a 409), and nothing is deleted. This is how to check whether a device class can be deleted.


8) Device class icons

The icon of a device class is not one of its fields: it is an assignment in master_ap2.dev_class_icon, keyed by the device class’s GUID, made through three endpoints of their own. The image field is the legacy PNG image file name, not the icon.

  • GET /lce/api/icons lists the icons that can be assigned

  • GET /lce/api/device_classes/{device_class_identifier}/icon reads the icon of a device class

  • PUT /lce/api/device_classes/{device_class_identifier}/icon assigns or unassigns it

Together with the device class endpoints, this lets a device class be created and given its icon entirely through this service. Assigning an icon does exactly what the GraphQL setDeviceClassIcon mutation does, which remains an equivalent alternative.

Note

Creating icons is not part of this API. An icon must already exist to be assigned. Upload new icons with the GraphQL createIcon mutation, which validates and compresses the SVG.

Listing icons

GET /lce/api/icons lists the icons in master_ap2.icons, ordered by name. The optional search query parameter keeps only the icons whose name contains it, ignoring case. It is matched literally: % and _ are not wildcards. Surrounding whitespace is ignored, so a blank search lists every icon. size is the size of the icon in bytes:

{
  "icons": [
    { "id": "ckcwaww0000000widgetcomponent1", "name": "Widget", "size": 42 },
    { "id": "ckcwaww0000000windowsserver01", "name": "Windows Server", "size": 42 }
  ]
}

Reading the icon of a device class

GET /lce/api/device_classes/{device_class_identifier}/icon identifies the device class by id, GUID or name (see 4) Identifying a device class) and returns:

{
  "device_class": {
    "guid": "1F2E3D4C5B6A79881F2E3D4C5B6A7988",
    "id": 5001,
    "name": "Microsoft | Windows Server 2019"
  },
  "fallback_icon": { "id": "A1B2C3D4E5F60718293A4B5C6D7E8F90", "name": "Server" },
  "icon": { "id": "ckcwaww0000000windowsserver01", "name": "Windows Server" }
}
  • icon is the icon assigned to the device class (master_ap2.dev_class_icon), or null when none is assigned.

  • fallback_icon is the legacy icon of the device class (master.definitions_dev_class_svg_icons joined to master.definitions_default_svg_icons), which the platform shows when no icon is assigned, or null. It is reported for information only: this API never changes it, except that deleting the device class removes it.

Icons are assigned by GUID, so a device class without a GUID is rejected with 422.

Assigning an icon

PUT /lce/api/device_classes/{device_class_identifier}/icon takes a body naming the icon by its id or its exact name:

{ "icon": "Windows Server" }

or {"icon": null} to unassign the icon. Like setDeviceClassIcon, it replaces the assignment of the device class and records the change in the audit log. It does not increment the revision of the device class’s PowerPack, and it leaves fallback_icon as it is. It supports commit=false, which validates the change and rolls it back.

Unlike setDeviceClassIcon, which always rewrites the assignment, assigning the icon a device class already has, or unassigning when no icon is assigned, changes nothing and writes no audit entry. The response is the same.

The response holds the icons of the device class after the change, in the same form as the GET:

{
  "result": {
    "device_class": {
      "guid": "1F2E3D4C5B6A79881F2E3D4C5B6A7988",
      "id": 5001,
      "name": "Microsoft | Windows Server 2019"
    },
    "fallback_icon": { "id": "A1B2C3D4E5F60718293A4B5C6D7E8F90", "name": "Server" },
    "icon": { "id": "ckcwaww0000000windowsserver01", "name": "Windows Server" }
  },
  "success": true
}

An icon is looked up by id first, then by exact name. When several icons share the name, the request is rejected with 422 and the message lists their ids; pass the id instead. An icon that does not exist is also rejected with 422. The body must be sent as JSON with a Content-Type of application/json (415 otherwise, as for POST). Malformed JSON is rejected with 400 Invalid JSON payload provided, and JSON that is not an object with an icon that is a non-empty string or null with 400 Invalid Icon Request.

Important

PUT /lce/api/device_classes/{device_class_identifier}/icon requires the DEV_CLASS_EDIT access hook, which is what the setDeviceClassIcon mutation checks. It is not the SYS_CUSTOM_DEV_CLASS_PAGE hook that creating, updating and deleting device classes require, so a user can be allowed to do one without the other.


9) Examples

Every example uses the same Skylar One session as every other endpoint in this service. Replace $SL1_HOST and $SL1_COOKIE with your host and session cookie.

Listing device classes

Every device class:

curl -sS -b "$SL1_COOKIE" "https://$SL1_HOST/lce/api/device_classes"

The component device classes whose class contains Acme, returning only their identifiers:

curl -sS -g -b "$SL1_COOKIE" \
  "https://$SL1_HOST/lce/api/device_classes?filter[device_type][is]=COMPONENT&filter[class_name][contains]=Acme&fields=id,guid,class_name,description"
{
  "device_classes": [
    {
      "class_name": "Acme",
      "description": "Widget Component",
      "guid": "3B4C5D6E7F8091A23B4C5D6E7F8091A2",
      "id": 5003
    }
  ]
}

-g stops curl from interpreting the [ and ] of the filters.

Retrieving one device class

By GUID:

curl -sS -b "$SL1_COOKIE" \
  "https://$SL1_HOST/lce/api/device_classes/3B4C5D6E7F8091A23B4C5D6E7F8091A2"

By name, URL-encoded:

curl -sS -b "$SL1_COOKIE" \
  "https://$SL1_HOST/lce/api/device_classes/Acme%20%7C%20Widget%20Component"
{
  "agent_identifier_1": "",
  "agent_identifier_2": "",
  "category": 902,
  "category_name": "Component",
  "class_identifier_1": "acme_widget",
  "class_identifier_2": "",
  "class_name": "Acme",
  "class_type": 5003,
  "description": "Widget Component",
  "device_type": "COMPONENT",
  "discovery_qualifier": "",
  "guid": "3B4C5D6E7F8091A23B4C5D6E7F8091A2",
  "id": 5003,
  "image": "_generic_unknown.png",
  "is_snmp": false,
  "last_edited": "2026-01-05T10:00:00",
  "pp_guid": null,
  "root_device": false,
  "tier_id": 0,
  "weight": 1
}

Creating a device class

Create a component device class in the Component category, by category name, and read it back with retrieve=true to learn its allocated class_type:

curl -sS -X POST "https://$SL1_HOST/lce/api/device_classes?retrieve=true" \
  -H "Content-Type: application/json" \
  -b "$SL1_COOKIE" \
  -d '{
        "class_name": "Acme",
        "description": "Gadget Component",
        "category": "Component",
        "device_type": "COMPONENT",
        "class_identifier_1": "acme_gadget",
        "pp_guid": "6450441E71B0EB1933D18A6C6252CF28"
      }'
{
  "entities": [
    {
      "agent_identifier_1": "",
      "agent_identifier_2": "",
      "category": 902,
      "category_name": "Component",
      "class_identifier_1": "acme_gadget",
      "class_identifier_2": "",
      "class_name": "Acme",
      "class_type": 5004,
      "description": "Gadget Component",
      "device_type": "COMPONENT",
      "discovery_qualifier": "",
      "guid": "7C1D9E2B4A6F48B1A3C5D7E9F0B2C4D6",
      "id": 5004,
      "image": "_generic_unknown.png",
      "is_snmp": false,
      "last_edited": "2026-10-05T14:21:37",
      "pp_guid": "6450441E71B0EB1933D18A6C6252CF28",
      "root_device": false,
      "tier_id": 0,
      "weight": 1
    }
  ],
  "results": [
    {
      "guid": "7C1D9E2B4A6F48B1A3C5D7E9F0B2C4D6",
      "id": 5004,
      "name": "Acme | Gadget Component",
      "new": true
    }
  ],
  "success": true
}

Align Dynamic Applications with class_type 5004. To create the device class with a known GUID instead, for example the one it has in a PowerPack, include "guid" in the payload.

Updating a device class

Provide the guid and the fields that change. Preview the result first with commit=false:

curl -sS -X POST "https://$SL1_HOST/lce/api/device_classes?commit=false&retrieve=true" \
  -H "Content-Type: application/json" \
  -b "$SL1_COOKIE" \
  -d '{"guid": "7C1D9E2B4A6F48B1A3C5D7E9F0B2C4D6", "class_identifier_2": "acme_gadget_v2", "weight": 5}'

Then send the same request without commit=false to apply it. The results entry has "new": false.

Copying device classes to another system

Retrieve the device classes of a PowerPack from one system:

curl -sS -g -b "$SL1_COOKIE" \
  "https://$SL1_HOST/lce/api/device_classes?filter[pp_guid][is]=6450441E71B0EB1933D18A6C6252CF28" \
  -o device_classes.json

The retrieved id values can stay in the file: the target system ignores them and matches each device class by its GUID.

Replace each category id with the category’s name or GUID (see Categories), then post the file to the other system, where the PowerPack must be installed. Each device class is created with its original GUID, or updated if that GUID is already there:

curl -sS -X POST "https://$OTHER_HOST/lce/api/device_classes" \
  -H "Content-Type: application/json" \
  -b "$OTHER_COOKIE" \
  -d @device_classes.json

Deleting a device class

Check that the device class can be deleted, then delete it:

curl -sS -X DELETE -b "$SL1_COOKIE" \
  "https://$SL1_HOST/lce/api/device_classes/7C1D9E2B4A6F48B1A3C5D7E9F0B2C4D6?commit=false"

curl -sS -X DELETE -b "$SL1_COOKIE" \
  "https://$SL1_HOST/lce/api/device_classes/7C1D9E2B4A6F48B1A3C5D7E9F0B2C4D6"

Giving a device class an icon

Find the icon:

curl -sS -b "$SL1_COOKIE" "https://$SL1_HOST/lce/api/icons?search=windows"
{
  "icons": [
    { "id": "ckcwaww0000000windowsserver01", "name": "Windows Server", "size": 42 }
  ]
}

Assign it by id, or by its exact name, then read it back:

curl -sS -X PUT "https://$SL1_HOST/lce/api/device_classes/1F2E3D4C5B6A79881F2E3D4C5B6A7988/icon" \
  -H "Content-Type: application/json" \
  -b "$SL1_COOKIE" \
  -d '{"icon": "ckcwaww0000000windowsserver01"}'

curl -sS -b "$SL1_COOKIE" \
  "https://$SL1_HOST/lce/api/device_classes/1F2E3D4C5B6A79881F2E3D4C5B6A7988/icon"

Unassign it, so the platform shows the fallback_icon again:

curl -sS -X PUT "https://$SL1_HOST/lce/api/device_classes/1F2E3D4C5B6A79881F2E3D4C5B6A7988/icon" \
  -H "Content-Type: application/json" \
  -b "$SL1_COOKIE" \
  -d '{"icon": null}'

10) Validation & error responses

Status codes

Status

error

When

400

Invalid Device Class Request

A malformed filter[...], a filter on an unknown field or with an unsupported operator; a payload that is not a device class, a list of them or a device_classes list, or holds no device classes; the same guid twice in one payload; an id without a guid; a limit or offset that is not a non-negative integer; or an identifier that is not a usable name.

400

Invalid Icon Request

A PUT .../icon body that is not an object with an icon that is a non-empty string or null.

400

Invalid JSON payload provided

The POST or PUT .../icon body is not valid JSON.

400

No JSON payload provided

The POST body is empty, {} or [].

401

(authentication error)

Missing or invalid authentication.

403

Forbidden

The user lacks an access hook the endpoint requires. This body has error and message only, without success.

404

Device Class Not Found

No device class matches the identifier, several device classes share the name given (their GUIDs are in matches), or filters match no device class (with an offset of 0). DELETE and PUT .../icon only accept an exact name, and return No device class found named exactly: <name> for any other. A fuzzy name lookup on a GET lists the closest names in matches.

409

Device Class In Use

DELETE of a device class that devices or Dynamic Applications reference. The references object lists them.

415

Unsupported Media Type

The POST or PUT .../icon body is not sent with a Content-Type of application/json.

422

Device Class(es) Failed Validation

A device class fails validation: a missing required field, a value of the wrong type or out of range, an unknown field, identifiers that break a rule of Identifier rules, a category that does not resolve, a tier_id that does not exist, a pp_guid that is not an installed PowerPack, text that cannot be stored as latin1, or a stored value that fails validation and is not corrected in the payload. A pp_guid is only checked when it is new or changed, so a device class whose stored PowerPack was since uninstalled can still be updated. For the icon endpoints: the device class has no valid GUID.

422

Invalid Icon

PUT .../icon: the icon does not exist, or several icons share the name given (the message lists their ids; pass the id instead).

500

Could not get Device Classes, Could not get Device Class, Could not update Device Class(es), Could not delete Device Class, Could not list Icons, Could not get the Icon of a Device Class, Could not set the Icon of a Device Class

An unexpected error, such as a database failure. Nothing is written.

Error body

{
  "error": "Device Class(es) Failed Validation",
  "message": "Device class 'Acme | Gadget Component' has invalid identifiers: A component device class cannot be an SNMP device class",
  "success": false
}

Every error body has success, error and message. A 404 adds matches: the closest names, the GUIDs of the device classes that share a name, or empty, and a 409 adds references.

A field that fails validation is named in the message, with nested locations joined by " -> ":

{
  "error": "Device Class(es) Failed Validation",
  "message": "weight: Input should be less than or equal to 10",
  "success": false
}