# ConnectWise Automate Alerts

> ConnectWise Automate alert management: alert sources (monitors, scripts, events), severity levels, lifecycle states, acknowledgment, resolution, history tracking, and PSA ticket creation from alerts.

- Skill: `wyre-ai/connectwise-automate-alerts` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add wyre-ai/connectwise-automate-alerts`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wyre-ai/connectwise-automate-alerts/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: WYRE-AI (https://skillmd.com/u/wyre-ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/wyre-ai/connectwise-automate-alerts

---


# 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-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

