3.1 KiB
3.1 KiB
ConnectWise SLA Evaluation Recipe
Reference: sla_evaluation.md — How to evaluate SLA state and score tickets for prioritization using the CW v3 API.
Fields to Read
| Field | Type | Meaning |
|---|---|---|
isInSla |
bool | False = breached |
slaStatus |
string | e.g. "Respond by Tue 04/21 3:37 PM UTC-07" |
respondMinutes |
int | Minutes in "respond" phase |
resPlanMinutes |
int | Minutes in "resplan" phase |
resolveMinutes |
int | Minutes in "resolve" phase |
escalationLevel |
int | Tier (higher = worse) |
priority.level |
string | Critical / High / Medium / Low |
severity |
string | Critical / High / Medium / Low |
impact |
string | Critical / High / Medium / Low |
_info.dateEntered |
ISO string | Canonical creation time |
Composite Scoring Formula
score = 0
if sla_overdue:
score += 1000
elif sla_state == 'Due <24h':
score += 500
elif sla_state == 'Due <72h':
score += 200
score += (escalation or 0) * 50
prio_map = {
'Priority 1 - Critical': 400,
'Priority 2 - High': 200,
'Priority 3 - Medium': 50,
'Priority 4 - Low': 10
}
score += prio_map.get(priority_name, 0)
if severity in ('Critical', 'High'):
score += 100
if impact in ('Critical', 'High'):
score += 100
if date_entered:
age_days = (now - date_entered).total_seconds() / 86400
score += min(int(age_days) * 5, 300)
SLA State Parsing
import re
from datetime import datetime
def parse_sla(sla_status_text):
if not sla_status_text or sla_status_text == 'Resolved':
return sla_status_text or 'No SLA'
m = re.search(r'(Respond|Resolve)\s+by\s+(.+)', sla_status_text, re.IGNORECASE)
if m:
due_text = m.group(2).strip()
try:
dt = datetime.strptime(due_text, '%a %m/%d %I:%M %p %Z%z')
if dt < now:
return 'Overdue'
hours = (dt - now).total_seconds() / 3600
if hours < 24:
return 'Due <24h'
elif hours < 72:
return 'Due <72h'
return 'On Track'
except ValueError:
return 'Due (unparsed)'
return sla_status_text
RMM Alert Categories (for filtering / triage)
Keyword-based categorization of common Sophos/RMM-generated summaries:
| Category | Keywords |
|---|---|
| Firewall Sophos Offline | firewall + sophos |
| Firewall Heartbeat | not sending heartbeat |
| Gateway Down | gateway + down |
| Malware Detection | malicious, c2/ |
| Device Offline | has not contacted |
| Disk/Storage | disk, drive, storage, c: |
| CPU Alert | cpu |
| Memory Alert | memory, ram |
| Reboot Required | reboot, restart |
| AV Alert | antivirus, virus |
Bulk Close Recipe
Update stale "new from RMM" tickets to "Self-Healed":
# 1. Fetch all open tickets
# 2. Filter: status == 'new from RMM' AND _info.dateEntered > 7 days ago
# 3. PATCH each: [{"op": "replace", "path": "/status/id", "value": 425}]
# Status ID 425 = "Self-Healed" on board 6 (Managed Service Alerts)
Never auto-close malware detections without human review.