ConnectWise Automate Alerts · diff
git:20260804.792c422 to git:20260817.2671d27
1 added, 1 removed. Audit A to A.
---
name: "ConnectWise Automate Alerts"
description: >
ConnectWise Automate alert management: alert sources (monitors, scripts,
events), severity levels, lifecycle states, acknowledgment, resolution,
history tracking, and PSA ticket creation from alerts.
when_to_use: >-
When listing active alerts, acknowledging alerts, viewing alert history, and creating tickets
from alerts. Use when: automate alert, automate notification, alert acknowledgment, alert
history, alert ticket, monitor alert, labtech alert, or automate incident.
---
# ConnectWise Automate Alert Management
## Overview
Alerts in ConnectWise Automate are notifications generated by monitors, scripts, or system events that require attention. This skill covers alert listing, acknowledgment, history tracking, and ticket creation workflows.
## Anti-triggers
- **The rule that produced the alert** — thresholds, templates and
assignment are monitor configuration; use
`connectwise-automate-monitors`.
- **The PSA ticket raised from an alert** — this skill covers dispatching
it; the ticket's board, status, priority and SLA clock live in
ConnectWise PSA. Use `connectwise-psa-tickets`.
- **Another RMM's alerts** — Datto RMM, NinjaOne, Atera and Auvik all use
- the word; use `datto-rmm-alerts`, `ninjaone-rmm-alerts`,
+ the word; use `datto-rmm-alerts`, `ninjaone-alerts`,
`atera-alerts` or `auvik-alerts`.
## Key Concepts
### Alert Sources
| Source | Description | Example |
|--------|-------------|---------|
| **Monitor** | Generated by monitor threshold | CPU > 90% |
| **Script** | Generated by script execution | Backup failed |
| **Event Log** | Windows Event Log trigger | Security event |
| **System** | Automate system events | Agent offline |
| **Manual** | User-created alerts | Maintenance note |
### Alert Severity Levels
| Level | Value | Description | Response Time |
|-------|-------|-------------|---------------|
| `Information` | 1 | Informational only | Review at convenience |
| `Warning` | 2 | Potential issue | Investigate within hours |
| `Error` | 3 | Failure detected | Respond within SLA |
| `Critical` | 4 | Severe/emergency | Immediate response |
### Alert Lifecycle
```
Generated → Active → Acknowledged → Resolved
│ │
│ └── Ticket Created
│
└── Auto-Cleared (if condition clears)
```
### Alert Status
| Status | Description |
|--------|-------------|
| `New` | Just generated, unread |
| `Active` | Open, unacknowledged |
| `Acknowledged` | Someone is working on it |
| `Resolved` | Issue fixed, alert closed |
| `Cleared` | Condition auto-cleared |
| `Suppressed` | Temporarily hidden |
See [references/fields.md](references/fields.md) for the complete Alert and AlertHistory field reference.
## API Patterns
Alerts are managed through `/cwa/api/v1/Alerts` endpoints using a SQL-like `condition` query parameter for filtering (not standard REST query params):
```http
GET /cwa/api/v1/Alerts?condition=Status in ('New','Active')&pageSize=100
Authorization: Bearer {token}
```
Action endpoints (`Acknowledge`, `Resolve`, `Suppress`, `CreateTicket`) are POST requests to `/Alerts/{alertID}/{Action}` and most require a `Notes` field in the body. A bulk acknowledgment endpoint exists at `/Alerts/BulkAcknowledge` for handling related alerts together.
See [references/api.md](references/api.md) for the complete endpoint catalog with request/response examples (list, filter by client/severity, acknowledge, resolve, add note, create ticket, get history, suppress, bulk acknowledge).
## Workflows
### Get Critical Alerts Dashboard
```javascript
async function getCriticalAlertsDashboard(client) {
const criticalAlerts = await client.request(
`/Alerts?condition=Severity >= 3 and Status in ('New','Active')&pageSize=100`
);
const dashboard = {
totalCritical: criticalAlerts.length,
byClient: {},
byCategory: {},
oldest: null
};
for (const alert of criticalAlerts) {
// Group by client
const clientName = alert.ClientName || 'Unknown';
if (!dashboard.byClient[clientName]) {
dashboard.byClient[clientName] = [];
}
dashboard.byClient[clientName].push({
id: alert.AlertID,
subject: alert.Subject,
computer: alert.ComputerName,
severity: alert.Severity,
age: getAlertAge(alert.TimeGenerated)
});
// Group by category
const category = alert.Category || 'Uncategorized';
dashboard.byCategory[category] = (dashboard.byCategory[category] || 0) + 1;
// Track oldest
if (!dashboard.oldest || new Date(alert.TimeGenerated) < new Date(dashboard.oldest.TimeGenerated)) {
dashboard.oldest = alert;
}
}
return dashboard;
}
function getAlertAge(timeGenerated) {
const now = new Date();
const generated = new Date(timeGenerated);
const diffMs = now - generated;
const diffMins = Math.floor(diffMs / 60000);
if (diffMins < 60) return `${diffMins} minutes`;
if (diffMins < 1440) return `${Math.floor(diffMins / 60)} hours`;
return `${Math.floor(diffMins / 1440)} days`;
}
```
### Acknowledge and Create Ticket Workflow
```javascript
async function acknowledgeAndCreateTicket(client, alertId, options = {}) {
const {
notes = 'Acknowledged and ticket created',
priority = 2,
boardId = 1
} = options;
// Get alert details
const alert = await client.request(`/Alerts/${alertId}`);
// Acknowledge the alert
await client.request(`/Alerts/${alertId}/Acknowledge`, {
method: 'POST',
body: JSON.stringify({ Notes: notes })
});
// Create ticket
const ticketResponse = await client.request(`/Alerts/${alertId}/CreateTicket`, {
method: 'POST',
body: JSON.stringify({
TicketSubject: alert.Subject,
Priority: alert.Severity >= 3 ? 1 : priority,
BoardID: boardId,
Notes: `Auto-created from Automate alert\n\n${alert.Message}`
})
});
return {
alert: {
id: alertId,
subject: alert.Subject,
status: 'Acknowledged'
},
ticket: {
id: ticketResponse.TicketID,
number: ticketResponse.TicketNumber
}
};
}
```
### Alert Triage by Client
```javascript
async function triageAlertsByClient(client, clientId) {
const alerts = await client.request(
`/Alerts?condition=ClientID = ${clientId} and Status in ('New','Active')&pageSize=200`
);
const triage = {
client: clientId,
total: alerts.length,
critical: [],
error: [],
warning: [],
info: []
};
for (const alert of alerts) {
const summary = {
id: alert.AlertID,
subject: alert.Subject,
computer: alert.ComputerName,
source: alert.SourceName,
age: getAlertAge(alert.TimeGenerated)
};
switch (alert.Severity) {
case 4: triage.critical.push(summary); break;
case 3: triage.error.push(summary); break;
case 2: triage.warning.push(summary); break;
default: triage.info.push(summary);
}
}
return triage;
}
```
### Bulk Alert Resolution
```javascript
async function bulkResolveAlerts(client, alertIds, notes) {
const results = [];
for (const alertId of alertIds) {
try {
await client.request(`/Alerts/${alertId}/Resolve`, {
method: 'POST',
body: JSON.stringify({ Notes: notes })
});
results.push({ alertId, status: 'resolved' });
} catch (error) {
results.push({ alertId, status: 'failed', error: error.message });
}
// Respect rate limits
await sleep(100);
}
return {
resolved: results.filter(r => r.status === 'resolved').length,
failed: results.filter(r => r.status === 'failed').length,
details: results
};
}
```
### Alert Escalation Check
```javascript
async function checkAlertEscalation(client) {
const alerts = await client.request(
`/Alerts?condition=Status = 'Active' and Severity >= 2&pageSize=500`
);
const escalations = [];
const now = new Date();
for (const alert of alerts) {
const generated = new Date(alert.TimeGenerated);
const ageMinutes = (now - generated) / 60000;
// Escalation rules based on severity and age
let shouldEscalate = false;
let reason = '';
switch (alert.Severity) {
case 4: // Critical
if (ageMinutes > 15) {
shouldEscalate = true;
reason = 'Critical alert unacknowledged for 15+ minutes';
}
break;
case 3: // Error
if (ageMinutes > 60) {
shouldEscalate = true;
reason = 'Error alert unacknowledged for 1+ hour';
}
break;
case 2: // Warning
if (ageMinutes > 240) {
shouldEscalate = true;
reason = 'Warning alert unacknowledged for 4+ hours';
}
break;
}
if (shouldEscalate) {
escalations.push({
alertId: alert.AlertID,
subject: alert.Subject,
client: alert.ClientName,
computer: alert.ComputerName,
severity: alert.Severity,
ageMinutes: Math.round(ageMinutes),
reason
});
}
}
return escalations;
}
```
## Error Handling
### Common Alert API Errors
| Error | Status | Cause | Resolution |
|-------|--------|-------|------------|
| Alert not found | 404 | Invalid AlertID | Verify alert exists |
| Already resolved | 400 | Alert already closed | Check current status |
| Permission denied | 403 | No access to alert | Check user permissions |
| Invalid status | 400 | Invalid status transition | Follow lifecycle rules |
| Ticket creation failed | 400 | PSA integration error | Check ticket board config |
See [references/examples.md](references/examples.md) for a sample error response, a safe-resolve helper that checks status before resolving, and a full multi-step alert response workflow template.
## Best Practices
1. **Acknowledge promptly** - Shows someone is working on it
2. **Add meaningful notes** - Document investigation steps
3. **Create tickets for tracking** - Long-running issues need tickets
4. **Use bulk operations** - Handle related alerts together
5. **Set up escalation rules** - Don't let alerts age
6. **Filter by severity** - Focus on critical first
7. **Review alert history** - Understand recurring patterns and audit old/stale alerts
8. **Suppress during maintenance** - Avoid alert fatigue
9. **Link to documentation** - Reference runbooks in notes
## Related Skills
- [ConnectWise Automate Monitors](../monitors/SKILL.md) - Alert sources
- [ConnectWise Automate Computers](../computers/SKILL.md) - Alert targets
- [ConnectWise Automate Scripts](../scripts/SKILL.md) - Remediation scripts
- [ConnectWise Automate API Patterns](../api-patterns/SKILL.md) - Authentication and pagination