find-contact
Resolve a 3CX contact or extension by email, extension, or name
Close a ConnectWise PSA ticket with resolution notes
$ npx -y skills add wyre-technology/msp-claude-plugins --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
/close-ticketContext preview
What this command does when you run it.
Close a ConnectWise PSA ticket with resolution notes
description: Close a ConnectWise PSA ticket with resolution notes argument-hint: "<ticket_id> <resolution> [status] [time_minutes] [time_notes] [billable]" arguments: [ticket_id, resolution, status, time_minutes, time_notes, billable]
Close a ConnectWise ticket with resolution notes and optional time entry.
1. **Validate ticket exists and get current state**
GET /service/tickets/{id}2. **Resolve closed status**
GET /service/boards/{boardId}/statuses?conditions=closedStatus=true3. **Add resolution note**
POST /service/tickets/{id}/notes
Content-Type: application/json
{
"text": "<resolution>",
"resolutionFlag": true,
"internalAnalysisFlag": false,
"customerUpdatedFlag": true,
"processNotifications": true
}4. **Log time entry (if time_minutes provided)**
POST /time/entries
Content-Type: application/json
{
"chargeToId": <ticket_id>,
"chargeToType": "ServiceTicket",
"timeStart": "<current_datetime>",
"timeEnd": "<current_datetime + time_minutes>",
"actualHours": <time_minutes / 60>,
"notes": "<time_notes or resolution>",
"billableOption": "<Billable or DoNotBill>"
}5. **Update ticket status to closed**
PATCH /service/tickets/{id}
Content-Type: application/json
[
{"op": "replace", "path": "/status/id", "value": <closed_status_id>},
{"op": "replace", "path": "/resolution", "value": "<resolution>"}
]6. **Return closure confirmation**
| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | ticket_id | integer | Yes | - | ConnectWise ticket ID to close | | resolution | string | Yes | - | Resolution notes | | status | string | No | Board default | Closed status name | | time_minutes | integer | No | - | Final time entry in minutes | | time_notes | string | No | - | Notes for time entry | | billable | boolean | No | true | Mark time as billable |
/close-ticket 12345 "Password reset completed and verified with user"
/close-ticket 12345 "Server patched and rebooted successfully" --time_minutes 30 --time_notes "Applied security patches"
/close-ticket 12345 "Hardware replaced under warranty" --time_minutes 60 --billable false
/close-ticket 12345 "Issue resolved" --status "Completed"
/close-ticket 12345 "Configured new email account and tested send/receive functionality" --status "Completed" --time_minutes 45 --time_notes "Email configuration and testing" --billable true
Ticket #12345 Closed Successfully Resolution: "Password reset completed and verified with user" Final State: Company: Acme Corporation Summary: Password reset request Board: Service Desk Status: Closed Priority: Medium (3) Closed By: Jane Technician Closed At: 2026-02-04 15:30:00 Total Time: 1.5 hours URL: https://na.myconnectwise.net/v4_6_release/services/system_io/Service/fv_sr100_request.rails?service_recid=12345
Ticket #12345 Closed Successfully Resolution: "Server patched and rebooted successfully" Time Entry Added: Duration: 30 minutes (0.5 hours) Notes: Applied security patches Billable: Yes Work Type: Remote Support Final State: Company: Acme Corporation Summary: Server maintenance required Board: Managed Services Status: Completed Priority: Medium (3) Closed By: Jane Technician Closed At: 2026-02-04 16:00:00 Time Summary: Previous: 2.0 hours This Entry: 0.5 hours Total: 2.5 hours (all billable) URL: https://na.myconnectwise.net/v4_6_release/services/system_io/Service/fv_sr100_request.rails?service_recid=12345
# Base64 encode credentials: company+publicKey:privateKey
AUTH=$(echo -n "${CW_COMPANY}+${CW_PUBLIC_KEY}:${CW_PRIVATE_KEY}" | base64)
# Add resolution note
curl -s -X POST \
"https://${CW_HOST}/v4_6_release/apis/3.0/service/tickets/${TICKET_ID}/notes" \
-H "Authorization: Basic ${AUTH}" \
-H "clientId: ${CW_CLIENT_ID}" \
-H "Content-Type: application/json" \
-d '{
"text": "Resolution notes here",
"resolutionFlag": true,
"customerUpdatedFlag": true,
"processNotifications": true
}'
# Log time entry
curl -s -X POST \
"https://${CW_HOST}/v4_6_release/apis/3.0/time/entries" \
-H "Authorization: Basic ${AUTH}" \
-H "clientId: ${CW_CLIENT_ID}" \
-H "Content-Type: application/json" \
-d '{
"chargeToId": '"${TICKET_ID}"',
"chargeToType": "ServiceTicket",
"timeStart": "2026-02-04T15:00:00Z",
"timeEnd": "2026-02-04T15:30:00Z",
"actualHours": 0.5,
"notes": "Final work notes",
"billableOption": "Billable"
}'
# Update status to closed
curl -s -X PATCH \
"https://${CW_HOST}/v4_6_release/apis/3.0/service/tickets/${TICKET_ID}" \
-H "Authorization: Basic ${AUTH}" \
-H "clientId: ${CW_CLIENT_ID}" \
-H "Content-Type: application/json" \
-d '[
{"op": "replace", "path": "/status/id", "value": 5},
{"op": "replace", "path": "/resolution", "value": "Resolution notes here"}
]'Error: Ticket #99999 not found The ticket may have been deleted or you may not have pe
One command to supercharge Claude Code for MSP workflows. Then restart Claude Code. That's it. Documentation: mcp.wyre.ai
Repo: wyre-technology/msp-claude-plugins
Resolve a 3CX contact or extension by email, extension, or name
Search for specific threat patterns in Abnormal Security by sender, recipient, attack type, or keywords
Triage recent email threats detected by Abnormal Security by severity and attack type