From kaseya-autotask
Manages Autotask tickets for creation, updates, searches, queues, statuses, priorities, SLAs, escalations, validations, workflow automations, and metrics in service desk operations.
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin autotaskThis skill uses the workspace's default tool permissions.
Autotask tickets are the core unit of service delivery in the PSA. Every client request, incident, problem, and change flows through the ticketing system. This skill covers comprehensive ticket management including business logic, SLA calculations, escalation rules, and performance metrics.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Analyzes BMad project state from catalog CSV, configs, artifacts, and query to recommend next skills or answer questions. Useful for help requests, 'what next', or starting BMad.
Autotask tickets are the core unit of service delivery in the PSA. Every client request, incident, problem, and change flows through the ticketing system. This skill covers comprehensive ticket management including business logic, SLA calculations, escalation rules, and performance metrics.
Based on the Autotask API, these are the standard ticket status values:
| Status ID | Name | Description | Business Logic |
|---|---|---|---|
| 1 | NEW | Newly created ticket | Default for new tickets, SLA clock starts |
| 2 | IN_PROGRESS | Actively being worked | Resource should be assigned |
| 5 | COMPLETE | Issue resolved | Requires resolution field, stops SLA |
| 6 | WAITING_CUSTOMER | Awaiting customer response | SLA clock may pause |
| 13 | WAITING_MATERIALS | Waiting for parts/equipment | SLA clock may pause |
| 14 | ESCALATED | Escalated to higher tier | Requires escalation reason |
NEW (1) ──────────────────────────────> COMPLETE (5)
│ ↑
↓ │
IN_PROGRESS (2) ──────────────────────────>─┤
│ │ │
│ ↓ │
│ WAITING_CUSTOMER (6) ──────────────>─┤
│ │ │
│ ↓ │
│ WAITING_MATERIALS (13) ────────────>─┘
│
↓
ESCALATED (14) ─────> IN_PROGRESS (2) ────> COMPLETE (5)
Validation Rules:
| Priority ID | Name | Response SLA | Resolution SLA | Business Context |
|---|---|---|---|---|
| 4 | CRITICAL | 1 hour | 4 hours | Complete business outage |
| 3 | HIGH | 2 hours | 8 hours | Major productivity impact |
| 2 | MEDIUM | 4 hours | 24 hours | Single user/workaround exists |
| 1 | LOW | 8 hours | 72 hours | Minor issue/enhancement |
Note: In Autotask, lower numbers = lower priority. Priority 4 is most urgent.
| Field | Type | Required | Description |
|---|---|---|---|
id | int | System | Auto-generated unique identifier |
ticketNumber | string | System | Human-readable (e.g., T20240215.0001) |
title | string(255) | Yes | Brief issue summary |
description | text | No | Detailed description |
companyID | int | Yes | Company/account reference |
companyLocationID | int | No | Site/location within company |
contactID | int | No | Primary contact for ticket |
| Field | Type | Required | Description |
|---|---|---|---|
status | int | Yes | Current status (see codes above) |
priority | int | Yes | Urgency level (1-4) |
queueID | int | Yes | Service queue for routing |
issueType | int | No | Primary category |
subIssueType | int | No | Sub-category |
ticketType | int | No | Service Request, Incident, Problem, Change |
ticketCategory | int | No | Additional categorization |
| Field | Type | Required | Description |
|---|---|---|---|
assignedResourceID | int | No | Technician assigned |
assignedResourceRoleID | int | No | Role for billing |
creatorResourceID | int | System | Who created the ticket |
lastActivityResourceID | int | System | Last person to update |
| Field | Type | Required | Description |
|---|---|---|---|
createDate | datetime | System | When ticket was created |
dueDateTime | datetime | No | SLA due date/time |
completedDate | datetime | System | When marked complete |
firstResponseDateTime | datetime | System | First response timestamp |
resolutionPlanDateTime | datetime | No | Expected resolution time |
resolvedDateTime | datetime | System | Actual resolution time |
lastActivityDate | datetime | System | Last update timestamp |
| Field | Type | Required | Description |
|---|---|---|---|
contractID | int | No | Associated contract |
contractServiceID | int | No | Specific service on contract |
contractServiceBundleID | int | No | Service bundle |
estimatedHours | decimal | No | Estimated effort |
hoursToBeScheduled | decimal | No | Hours remaining |
| Field | Type | Required | Description |
|---|---|---|---|
resolution | text | Conditional | Required when completing |
resolutionType | int | No | Resolution category |
const SLA_DEFAULTS = {
CRITICAL: { response: 1, resolution: 4 }, // hours
HIGH: { response: 2, resolution: 8 },
MEDIUM: { response: 4, resolution: 24 },
LOW: { response: 8, resolution: 72 }
};
// Calculate SLA due dates
function calculateSLADueDate(ticket, contractSLA) {
const now = new Date();
const priority = ticket.priority || 2; // Default to MEDIUM
// Use contract SLA if available, otherwise defaults
const responseHours = contractSLA?.responseTimeHours || SLA_DEFAULTS[priority].response;
const resolutionHours = contractSLA?.resolutionTimeHours || SLA_DEFAULTS[priority].resolution;
return {
responseBy: addHours(now, responseHours),
resolveBy: addHours(now, resolutionHours),
businessHoursOnly: true
};
}
| Status | SLA Clock |
|---|---|
| NEW | Running |
| IN_PROGRESS | Running |
| WAITING_CUSTOMER | Paused (configurable) |
| WAITING_MATERIALS | Paused (configurable) |
| ESCALATED | Running |
| COMPLETE | Stopped |
function checkEscalationRules(ticket) {
const reasons = [];
const now = new Date();
// SLA Violation
if (ticket.dueDateTime && new Date(ticket.dueDateTime) < now) {
const hoursOverdue = Math.floor(
(now - new Date(ticket.dueDateTime)) / (1000 * 60 * 60)
);
reasons.push(`SLA violated by ${hoursOverdue} hours`);
escalationLevel = Math.min(3, Math.floor(hoursOverdue / 4) + 1);
}
// Stale Waiting Status
if (ticket.status === 6 && ticket.lastActivityDate) {
const daysSinceActivity = Math.floor(
(now - new Date(ticket.lastActivityDate)) / (1000 * 60 * 60 * 24)
);
if (daysSinceActivity > 7) {
reasons.push(`No customer response for ${daysSinceActivity} days`);
}
}
// Critical Without Assignment
if (ticket.priority === 4 && !ticket.assignedResourceID) {
reasons.push('Critical ticket without assigned resource');
}
return { requiresEscalation: reasons.length > 0, reasons };
}
| Level | Trigger | Action |
|---|---|---|
| 1 | SLA 0-4 hours overdue | Notify assigned resource |
| 2 | SLA 4-8 hours overdue | Notify team lead |
| 3 | SLA 8+ hours overdue | Notify management |
function calculateTicketMetrics(tickets) {
const completedTickets = tickets.filter(t => t.status === 5);
// Average Resolution Time (hours)
const avgResolutionTime = completedTickets.reduce((sum, t) => {
if (t.createDate && t.completedDate) {
return sum + (new Date(t.completedDate) - new Date(t.createDate));
}
return sum;
}, 0) / completedTickets.length / (1000 * 60 * 60);
// SLA Compliance Rate
const ticketsWithSLA = tickets.filter(t => t.dueDateTime);
const slaCompliant = ticketsWithSLA.filter(t => {
if (t.status === 5) {
return new Date(t.completedDate) <= new Date(t.dueDateTime);
}
return new Date() <= new Date(t.dueDateTime);
}).length;
const slaCompliance = (slaCompliant / ticketsWithSLA.length) * 100;
return {
totalTickets: tickets.length,
averageResolutionTime: avgResolutionTime.toFixed(2),
slaCompliance: slaCompliance.toFixed(1) + '%',
escalatedCount: tickets.filter(t => t.status === 14).length
};
}
{
"statusDistribution": {
"NEW": 12,
"IN_PROGRESS": 45,
"WAITING_CUSTOMER": 8,
"WAITING_MATERIALS": 3,
"ESCALATED": 2,
"COMPLETE": 156
},
"priorityDistribution": {
"CRITICAL": 1,
"HIGH": 15,
"MEDIUM": 38,
"LOW": 22
}
}
Tool: autotask_create_ticket
Args: {
"companyID": 12345,
"title": "Unable to access email - multiple users affected",
"description": "Sales team (5 users) reporting Outlook showing disconnected since 9am.",
"queueID": 8,
"priority": 3,
"status": 1,
"contactID": 67890
}
Required: companyID, title, status, priority, queueID
Tool: autotask_update_ticket
Args: {
"ticketId": 54321,
"status": 2,
"assignedResourceID": 29744150,
"assignedResourceRoleID": 29683459
}
Only fields provided will be changed. Common update scenarios:
| Scenario | Fields to Set |
|---|---|
| Assign technician | assignedResourceID + assignedResourceRoleID (both required together) |
| Change status | status (see status codes above) |
| Complete ticket | status: 5 (resolution via ticket note) |
| Escalate | status: 14 |
| Update priority | priority |
| Change due date | dueDateTime (ISO 8601 format) |
| Reassign contact | contactID |
Tool: autotask_search_tickets
Args: {
"companyId": 12345,
"status": 1,
"assignedResourceId": 29744150,
"searchTerm": "email",
"pageSize": 25
}
Filters: companyId, status, priority, queueId, assignedResourceId, searchTerm, pageSize
Tool: autotask_get_ticket_details
Args: { "ticketId": 54321 }
Tool: autotask_create_ticket_note
Args: {
"ticketId": 54321,
"title": "Status Update",
"description": "Identified root cause as KB5034441 update. Applying fix.",
"noteType": 1,
"publish": 0
}
noteType: 1=Internal, 2=External. publish: 0=No, 1=Yes (visible to client portal).
POST /v1.0/Tickets
Content-Type: application/json
{
"companyID": 12345,
"title": "Unable to access email - multiple users affected",
"description": "Sales team (5 users) reporting Outlook showing disconnected since 9am. Webmail working.",
"queueID": 8,
"priority": 3,
"status": 1,
"issueType": 5,
"subIssueType": 12,
"contactID": 67890,
"dueDateTime": "2024-02-15T17:00:00Z"
}
Open tickets for company with includes:
{
"filter": [
{"field": "companyID", "op": "eq", "value": 12345},
{"field": "status", "op": "noteq", "value": 5}
],
"includeFields": ["Company.companyName", "AssignedResource.firstName", "AssignedResource.lastName"]
}
SLA-breached tickets:
{
"filter": [
{"field": "dueDateTime", "op": "lt", "value": "2024-02-15T12:00:00Z"},
{"field": "status", "op": "in", "value": [1, 2, 6, 13, 14]}
]
}
Tickets by date range:
{
"filter": [
{"field": "createDate", "op": "between", "value": ["2024-02-01", "2024-02-29"]}
]
}
PATCH /v1.0/Tickets
Content-Type: application/json
Setting to Complete (requires resolution):
{
"id": 54321,
"status": 5,
"resolution": "Cleared Outlook cache and repaired Office installation. Monitored for 30 minutes, email flow restored."
}
Setting to Escalated (requires reason):
{
"id": 54321,
"status": 14,
"escalationReason": "Complex Exchange hybrid configuration issue requires senior engineer"
}
POST /v1.0/TicketNotes
Content-Type: application/json
Internal Note:
{
"ticketID": 54321,
"title": "Initial Triage",
"description": "Issue started after KB5034441 update. Known Outlook cache corruption issue.",
"noteType": 1,
"publish": 0
}
External Note (visible to client):
{
"ticketID": 54321,
"title": "Status Update",
"description": "We've identified the cause of the issue. A technician is working on the fix and will have it resolved within the hour.",
"noteType": 2,
"publish": 1
}
function validateStatusTransition(currentStatus, newStatus, ticket) {
const requiredFields = [];
const warnings = [];
switch (newStatus) {
case 5: // COMPLETE
if (!ticket.resolution) requiredFields.push('resolution');
if (currentStatus === 1) warnings.push('Completing without In Progress step');
break;
case 2: // IN_PROGRESS
if (!ticket.assignedResourceID) warnings.push('No resource assigned');
break;
case 14: // ESCALATED
if (!ticket.escalationReason) requiredFields.push('escalationReason');
break;
}
return {
canTransition: requiredFields.length === 0,
requiredFields,
warnings
};
}
| Code | Message | Resolution |
|---|---|---|
| 400 | Invalid field value | Verify picklist IDs for your instance |
| 400 | Status transition not allowed | Check workflow rules |
| 401 | Unauthorized | Verify API credentials |
| 403 | Insufficient permissions | Check resource security level |
| 404 | Entity not found | Confirm ticket/company exists |
| 409 | Conflict/Locked | Ticket being edited by another user |
| 429 | Rate limited | Implement exponential backoff |
| Error | Cause | Fix |
|---|---|---|
| CompanyID required | Missing company | All tickets need a company |
| QueueID invalid | Queue not found | Query /v1.0/Queues for valid IDs |
| Resolution required | Completing without resolution | Add resolution text |
| Status transition invalid | Invalid workflow | Check allowed transitions |