Datto RMM Devices ยท diff
git:20260713.1fbd3f3 to git:20260728.b7e78fc
29 added, 405 removed. Audit A to A.
---
name: "Datto RMM Devices"
description: >
- Use this skill when working with Datto RMM devices - listing, searching,
- managing, and monitoring endpoints. Covers device identifiers (UID, hostname, MAC),
- device types (workstation, server, ESXi, network), statuses, user-defined fields (UDF1-30),
- warranty information, and device operations.
+ Datto RMM device management: identifiers (UID, hostname, MAC), device
+ types and statuses, user-defined fields (UDF1-30), warranty data, and
+ device lookup/update/delete operations.
when_to_use: >-
When listing, searching, managing, and monitoring endpoints. Use when: datto device, rmm device,
device status, device lookup, managed device, device hostname, device online, device offline,
endpoint management, or device udf.
---
# Datto RMM Device Management
## Overview
Devices are the core managed entities in Datto RMM. Each device represents an endpoint with the Datto agent installed - workstations, servers, ESXi hosts, or network devices. This skill covers device identification, status monitoring, user-defined fields, and common device operations.
## Key Concepts
### Device Identifiers
Every device has multiple identifiers:
| Identifier | Type | Description | Example |
|------------|------|-------------|---------|
| `deviceUid` | string | Globally unique identifier | `d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a` |
| `deviceId` | integer | Legacy numeric ID | `123456` |
| `hostname` | string | Computer name | `ACME-DC01` |
| `intIpAddress` | string | Internal IP address | `192.168.1.100` |
| `extIpAddress` | string | External/public IP | `203.0.113.50` |
| `macAddresses` | array | Network interface MACs | `["00:1A:2B:3C:4D:5E"]` |
### Device Types
| Type | Description | Typical Use |
|------|-------------|-------------|
| `Desktop` | Workstation/PC | End-user computers |
| `Laptop` | Portable workstation | Mobile workers |
| `Server` | Windows/Linux server | Infrastructure |
| `ESXi Host` | VMware hypervisor | Virtualization |
| `Network Device` | Router/switch/firewall | SNMP-monitored |
| `Printer` | Network printer | Print infrastructure |
### Device Status
| Status | Description | Business Impact |
|--------|-------------|-----------------|
| `online` | Agent checking in | Normal operation |
| `offline` | No agent communication | May require attention |
| `rebooting` | Restart in progress | Temporary state |
| `unknown` | Status undetermined | Check connectivity |
- ## Field Reference
-
- ### Core Device Fields
-
- ```typescript
- interface Device {
- // Identifiers
- uid: string; // Unique device ID
- deviceId: number; // Legacy numeric ID
- hostname: string; // Computer name
- description: string; // Custom description
-
- // Site Association
- siteUid: string; // Parent site UID
- siteName: string; // Site display name
-
- // Type and Status
- deviceType: DeviceType; // Desktop, Laptop, Server, etc.
- deviceClass: string; // device, esxihost, printer, etc.
- status: DeviceStatus; // online, offline, rebooting
-
- // Network
- intIpAddress: string; // Internal IP
- extIpAddress: string; // External IP
- macAddresses: string[]; // MAC addresses
-
- // Operating System
- operatingSystem: string; // "Windows 11 Pro"
- osType: string; // "Windows", "macOS", "Linux"
- osVersion: string; // "10.0.22631"
- osSerialNumber: string; // Windows product key
-
- // Hardware
- manufacturer: string; // "Dell Inc."
- model: string; // "OptiPlex 7090"
- serialNumber: string; // Hardware serial
-
- // Agent Info
- agentVersion: string; // "2.5.0.1234"
- agentPlatform: string; // Platform agent was installed from
-
- // Timestamps (Unix milliseconds)
- lastSeen: number; // Last agent check-in
- lastReboot: number; // Last system restart
- createdAt: number; // When device was added
- warrantyExpiry: number; // Warranty end date
-
- // User-Defined Fields
- udf1: string; // Custom field 1
- udf2: string; // Custom field 2
- // ... up to udf30
-
- // Counts
- openAlertCount: number; // Active alerts
- patchStatus: PatchStatus; // Patch compliance
- }
-
- type DeviceType = 'Desktop' | 'Laptop' | 'Server' | 'ESXi Host' | 'Network Device' | 'Printer';
- type DeviceStatus = 'online' | 'offline' | 'rebooting' | 'unknown';
- ```
-
- ### User-Defined Fields (UDF)
-
- Datto RMM provides 30 custom fields per device:
-
- | Field | Type | Max Length | Description |
- |-------|------|------------|-------------|
- | `udf1` - `udf30` | string | 255 chars | Custom data fields |
-
- **Common UDF Uses:**
- - `udf1`: Asset tag
- - `udf2`: Department
- - `udf3`: Primary user
- - `udf4`: Location/floor
- - `udf5`: Purchase date
- - `udf6`: Lease expiration
-
- ## API Patterns
-
- ### List All Devices
-
- ```http
- GET /api/v2/devices?max=250
- Authorization: Bearer {token}
- ```
-
- **Response:**
- ```json
- {
- "devices": [
- {
- "uid": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a",
- "hostname": "ACME-DC01",
- "siteUid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "siteName": "Acme Corporation",
- "deviceType": "Server",
- "status": "online",
- "intIpAddress": "192.168.1.10",
- "operatingSystem": "Windows Server 2022 Standard",
- "lastSeen": 1707991200000,
- "openAlertCount": 2
- }
- ],
- "pageDetails": {
- "count": 250,
- "nextPageUrl": "/api/v2/devices?max=250&page=abc123"
- }
- }
- ```
-
- ### Get Single Device
-
- ```http
- GET /api/v2/device/{deviceUid}
- Authorization: Bearer {token}
- ```
-
- **Response:**
- ```json
- {
- "uid": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a",
- "hostname": "ACME-DC01",
- "description": "Primary Domain Controller",
- "siteUid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "siteName": "Acme Corporation",
- "deviceType": "Server",
- "deviceClass": "device",
- "status": "online",
- "intIpAddress": "192.168.1.10",
- "extIpAddress": "203.0.113.50",
- "macAddresses": ["00:1A:2B:3C:4D:5E"],
- "operatingSystem": "Windows Server 2022 Standard",
- "osVersion": "10.0.20348",
- "manufacturer": "Dell Inc.",
- "model": "PowerEdge R640",
- "serialNumber": "ABC1234567",
- "agentVersion": "2.5.0.1234",
- "lastSeen": 1707991200000,
- "lastReboot": 1707800000000,
- "createdAt": 1680000000000,
- "warrantyExpiry": 1750000000000,
- "udf1": "ASSET-00123",
- "udf2": "IT Infrastructure",
- "udf3": "John Admin",
- "openAlertCount": 2,
- "patchStatus": {
- "patchesApproved": 5,
- "patchesPending": 2,
- "patchesFailed": 0
- }
- }
- ```
-
- ### Get Devices by Site
-
- ```http
- GET /api/v2/site/{siteUid}/devices?max=250
- Authorization: Bearer {token}
- ```
-
- ### Update Device
-
- ```http
- POST /api/v2/device/{deviceUid}
- Authorization: Bearer {token}
- Content-Type: application/json
-
- {
- "description": "Updated description",
- "udf1": "NEW-ASSET-TAG",
- "udf2": "Finance Department"
- }
- ```
-
- ### Delete Device
-
- ```http
- DELETE /api/v2/device/{deviceUid}
- Authorization: Bearer {token}
- ```
+ ### Field Reference
- **Note:** Deleting a device removes it from Datto RMM but does not uninstall the agent.
+ Devices carry identifier, site, type/status, network, OS, hardware, agent, and
+ timestamp fields, plus 30 user-defined fields (`udf1`-`udf30`, 255 char max,
+ commonly used for asset tag, department, primary user, location, purchase
+ date, lease expiration). See [references/fields.md](references/fields.md)
+ for the complete `Device` interface and UDF table.
- ## Workflows
+ ## Common Workflows
### Device Lookup by Hostname
```javascript
async function findDeviceByHostname(client, hostname) {
// Fetch all devices (with pagination)
const allDevices = [];
let url = '/api/v2/devices?max=250';
while (url) {
const response = await client.request(url);
allDevices.push(...response.devices);
url = response.pageDetails?.nextPageUrl;
}
// Search case-insensitive
const matches = allDevices.filter(d =>
d.hostname.toLowerCase().includes(hostname.toLowerCase())
);
if (matches.length === 0) {
return { found: false, suggestions: [] };
}
if (matches.length === 1) {
return { found: true, device: matches[0] };
}
return {
found: false,
ambiguous: true,
suggestions: matches.map(d => ({
hostname: d.hostname,
uid: d.uid,
site: d.siteName
}))
};
}
```
- ### Device Lookup by IP Address
-
- ```javascript
- async function findDeviceByIP(client, ipAddress) {
- const allDevices = await fetchAllDevices(client);
-
- const device = allDevices.find(d =>
- d.intIpAddress === ipAddress || d.extIpAddress === ipAddress
- );
-
- return device || null;
- }
- ```
-
- ### Device Lookup by MAC Address
-
- ```javascript
- async function findDeviceByMAC(client, macAddress) {
- const normalizedMAC = macAddress.toUpperCase().replace(/[:-]/g, ':');
- const allDevices = await fetchAllDevices(client);
-
- const device = allDevices.find(d =>
- d.macAddresses?.some(mac =>
- mac.toUpperCase().replace(/[:-]/g, ':') === normalizedMAC
- )
- );
-
- return device || null;
- }
- ```
-
- ### Offline Device Report
-
- ```javascript
- async function getOfflineDevices(client, options = {}) {
- const {
- siteUid,
- offlineThresholdMinutes = 30
- } = options;
-
- const url = siteUid
- ? `/api/v2/site/${siteUid}/devices?max=250`
- : '/api/v2/devices?max=250';
-
- const allDevices = await fetchAllPaginated(client, url);
- const now = Date.now();
- const threshold = offlineThresholdMinutes * 60 * 1000;
-
- return allDevices.filter(device => {
- if (device.status === 'offline') return true;
- if (!device.lastSeen) return true;
-
- // Check if last seen exceeds threshold
- return (now - device.lastSeen) > threshold;
- }).map(device => ({
- hostname: device.hostname,
- uid: device.uid,
- site: device.siteName,
- lastSeen: new Date(device.lastSeen).toISOString(),
- offlineMinutes: Math.floor((now - device.lastSeen) / 60000)
- }));
- }
- ```
-
- ### Bulk UDF Update
-
- ```javascript
- async function bulkUpdateUDF(client, updates) {
- // updates: [{ deviceUid, udf1, udf2, ... }, ...]
-
- const results = [];
-
- for (const update of updates) {
- try {
- const { deviceUid, ...fields } = update;
- await client.request(`/api/v2/device/${deviceUid}`, {
- method: 'POST',
- body: JSON.stringify(fields)
- });
- results.push({ deviceUid, success: true });
- } catch (error) {
- results.push({ deviceUid, success: false, error: error.message });
- }
-
- // Respect rate limits
- await sleep(100);
- }
-
- return results;
- }
- ```
-
- ## Error Handling
-
- ### Common Device API Errors
-
- | Error | Status | Cause | Resolution |
- |-------|--------|-------|------------|
- | Device not found | 404 | Invalid UID | Verify device exists |
- | Invalid field value | 400 | UDF too long | Max 255 characters |
- | Permission denied | 403 | API key restrictions | Check API permissions |
- | Device locked | 409 | Concurrent update | Retry after delay |
-
- ### Error Response Example
-
- ```json
- {
- "errorCode": "DEVICE_NOT_FOUND",
- "message": "Device with UID 'd4e5f6a7-...' not found",
- "details": {
- "deviceUid": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a"
- }
- }
- ```
-
- ### Device Validation
-
- ```javascript
- function validateDeviceUpdate(fields) {
- const errors = [];
-
- // Check UDF lengths
- for (let i = 1; i <= 30; i++) {
- const field = `udf${i}`;
- if (fields[field] && fields[field].length > 255) {
- errors.push(`${field} exceeds 255 character limit`);
- }
- }
-
- // Validate description
- if (fields.description && fields.description.length > 1000) {
- errors.push('Description exceeds 1000 character limit');
- }
-
- return {
- valid: errors.length === 0,
- errors
- };
- }
- ```
-
- ## Best Practices
-
- 1. **Use UID not hostname for lookups** - UIDs are guaranteed unique
- 2. **Cache device lists** - Full device list changes infrequently
- 3. **Use site-scoped queries** - Reduce data transfer when possible
- 4. **Monitor offline devices** - Set up alerts for extended offline status
- 5. **Standardize UDF usage** - Document which UDFs are used for what
- 6. **Handle pagination** - Always process `nextPageUrl`
- 7. **Normalize MAC addresses** - Handle different formats (colons, dashes, none)
- 8. **Check lastSeen vs status** - Status may lag behind actual connectivity
- 9. **Track agent versions** - Plan upgrades based on version distribution
- 10. **Document warranty info** - Use UDFs for hardware lifecycle management
-
- ## Device Status Business Logic
-
- ### Determining True Online Status
-
- ```javascript
- function getDeviceEffectiveStatus(device) {
- const now = Date.now();
- const lastSeenMinutesAgo = (now - device.lastSeen) / 60000;
-
- if (device.status === 'online' && lastSeenMinutesAgo < 15) {
- return 'online';
- }
-
- if (device.status === 'rebooting') {
- return 'rebooting';
- }
-
- if (lastSeenMinutesAgo > 60) {
- return 'offline';
- }
-
- if (lastSeenMinutesAgo > 30) {
- return 'stale';
- }
-
- return device.status;
- }
- ```
-
- ### Device Health Summary
+ Equivalent lookups by IP and MAC address, an offline-device report, and a
+ bulk UDF update helper follow the same pagination pattern - see
+ [references/examples.md](references/examples.md) for the full
+ implementations, including UDF/description length validation.
- ```javascript
- function getDeviceHealthSummary(device) {
- const issues = [];
+ ## API Patterns
- // Check online status
- if (device.status !== 'online') {
- issues.push({ severity: 'warning', message: `Device is ${device.status}` });
- }
+ - `GET /api/v2/devices?max=250` - list all devices (paginated via `pageDetails.nextPageUrl`)
+ - `GET /api/v2/device/{deviceUid}` - get a single device
+ - `GET /api/v2/site/{siteUid}/devices?max=250` - devices scoped to a site
+ - `POST /api/v2/device/{deviceUid}` - update device fields (description, UDFs)
+ - `DELETE /api/v2/device/{deviceUid}` - remove device from Datto RMM (does not uninstall the agent)
- // Check open alerts
- if (device.openAlertCount > 0) {
- const severity = device.openAlertCount > 5 ? 'critical' : 'warning';
- issues.push({
- severity,
- message: `${device.openAlertCount} open alert(s)`
- });
- }
+ See [references/api.md](references/api.md) for full request/response examples.
- // Check patch status
- if (device.patchStatus?.patchesFailed > 0) {
- issues.push({
- severity: 'warning',
- message: `${device.patchStatus.patchesFailed} failed patch(es)`
- });
- }
+ ## Gotchas
- // Check warranty
- if (device.warrantyExpiry && device.warrantyExpiry < Date.now()) {
- issues.push({
- severity: 'info',
- message: 'Warranty expired'
- });
- }
+ - **Deleting a device does not uninstall the agent** - it only removes the device record from Datto RMM.
+ - **UDF values are capped at 255 characters**; `description` is capped at 1000. Both fail with 400 `Invalid field value` when exceeded.
+ - **`status` can lag behind real connectivity.** Combine it with `lastSeen` to determine effective status - see `getDeviceEffectiveStatus` in [references/examples.md](references/examples.md).
+ - **MAC addresses arrive in inconsistent formats** (colons, dashes, none) - normalize before comparing.
+ - **Use `deviceUid`, not hostname, for lookups and updates** - hostnames are not guaranteed unique across sites.
+ - Respect rate limits on bulk operations (e.g., a short sleep between sequential per-device requests).
- return {
- healthy: issues.length === 0,
- issues
- };
- }
- ```
+ See [references/errors.md](references/errors.md) for the full device API error table.
## Related Skills
- [Datto RMM Alerts](../alerts/SKILL.md) - Device alert management
- [Datto RMM Audit](../audit/SKILL.md) - Device hardware/software inventory
- [Datto RMM Jobs](../jobs/SKILL.md) - Running jobs on devices
- [Datto RMM Sites](../sites/SKILL.md) - Site-level device management
- [Datto RMM API Patterns](../api-patterns/SKILL.md) - Authentication and pagination