From connectwise-psa
Manages ConnectWise Manage time entries: create, update, search, track billable/non-billable time with work types, roles, approvals, and sheets.
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin connectwise-psaThis skill uses the workspace's default tool permissions.
Time entries in ConnectWise PSA track time spent on tickets, projects, and other activities. Accurate time tracking is essential for billing, resource management, and profitability analysis. This skill covers time entry CRUD operations, work types, work roles, billing settings, and approval workflows.
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.
Time entries in ConnectWise PSA track time spent on tickets, projects, and other activities. Accurate time tracking is essential for billing, resource management, and profitability analysis. This skill covers time entry CRUD operations, work types, work roles, billing settings, and approval workflows.
Base: /time/entries
Time can be logged against different record types:
| Charge To Type | Description |
|---|---|
ServiceTicket | Time against service tickets |
ProjectTicket | Time against project tickets |
ChargeCode | Time against charge codes (internal) |
Activity | Time against activities |
| Field | Type | Required | Description |
|---|---|---|---|
id | int | System | Auto-generated unique identifier |
company | object | Yes* | {id: companyId} - Required for ChargeCode |
chargeToId | int | Yes | ID of ticket/project/activity |
chargeToType | string | Yes | ServiceTicket, ProjectTicket, etc. |
member | object | Yes | {id: memberId} - Who logged time |
timeStart | datetime | Yes | Start time |
timeEnd | datetime | Yes | End time |
| Field | Type | Required | Description |
|---|---|---|---|
actualHours | decimal | Alt | Hours worked (instead of start/end) |
hoursDeduct | decimal | No | Hours to deduct (break time) |
| Field | Type | Required | Description |
|---|---|---|---|
billableOption | string | No | Billable, DoNotBill, NoCharge, NoDefault |
workType | object | No | {id: workTypeId} |
workRole | object | No | {id: workRoleId} |
hourlyRate | decimal | System | Calculated rate |
agreement | object | No | {id: agreementId} |
| Field | Type | Required | Description |
|---|---|---|---|
notes | string | No | Time entry notes |
internalNotes | string | No | Internal notes (not on invoice) |
addToDetailDescriptionFlag | boolean | No | Add notes to ticket description |
addToInternalAnalysisFlag | boolean | No | Add to internal analysis |
addToResolutionFlag | boolean | No | Add to resolution |
| Field | Type | Required | Description |
|---|---|---|---|
status | string | System | Open, Rejected, Approved, Billed |
emailResourceFlag | boolean | No | Email resource on approval |
emailContactFlag | boolean | No | Email contact |
emailCcFlag | boolean | No | Email CC recipients |
emailCc | string | No | CC email addresses |
Work types categorize the nature of work performed.
| Type | Description | Typical Billing |
|---|---|---|
| Regular | Normal work hours | Billable |
| Overtime | After-hours work | 1.5x rate |
| Training | Training time | Non-billable |
| Travel | Travel time | Varies |
| Remote | Remote support | Billable |
| On-site | On-site work | Billable |
| Administrative | Admin tasks | Non-billable |
GET /time/workTypes
Work roles determine billing rates based on skill level.
| Role | Description | Typical Rate |
|---|---|---|
| Level 1 Tech | Help desk | $75-100/hr |
| Level 2 Tech | Desktop support | $100-125/hr |
| Level 3 Tech | Systems admin | $125-150/hr |
| Engineer | Senior engineer | $150-200/hr |
| Consultant | Expert consultant | $200-250/hr |
| Project Manager | PM work | $125-175/hr |
GET /time/workRoles
| Option | Description |
|---|---|
Billable | Time is billable at standard rate |
DoNotBill | Time excluded from billing |
NoCharge | Time shows on invoice at $0 |
NoDefault | Use ticket/agreement default |
billableOption (if set)billTime settingPOST /time/entries
Content-Type: application/json
{
"chargeToId": 54321,
"chargeToType": "ServiceTicket",
"member": {"id": 123},
"timeStart": "2024-02-15T09:00:00Z",
"timeEnd": "2024-02-15T10:30:00Z",
"workType": {"id": 1},
"workRole": {"id": 2},
"billableOption": "Billable",
"notes": "Diagnosed email delivery issue. Identified blocked sender.",
"addToDetailDescriptionFlag": true
}
POST /time/entries
Content-Type: application/json
{
"chargeToId": 54321,
"chargeToType": "ServiceTicket",
"member": {"id": 123},
"timeStart": "2024-02-15T09:00:00Z",
"actualHours": 1.5,
"workType": {"id": 1},
"workRole": {"id": 2},
"billableOption": "Billable",
"notes": "Configured DNS records and tested mail flow."
}
POST /time/entries
Content-Type: application/json
{
"chargeToId": 10,
"chargeToType": "ChargeCode",
"company": {"id": 12345},
"member": {"id": 123},
"timeStart": "2024-02-15T08:00:00Z",
"actualHours": 0.5,
"workType": {"id": 3},
"billableOption": "DoNotBill",
"notes": "Weekly team meeting"
}
GET /time/entries/{id}
PATCH /time/entries/{id}
Content-Type: application/json
{
"notes": "Updated notes with additional details.",
"actualHours": 2.0
}
DELETE /time/entries/{id}
Note: Cannot delete billed time entries.
GET /time/entries?conditions=member/id=123 and timeStart>=[2024-02-01]
Time entries for a ticket:
conditions=chargeToId=54321 and chargeToType="ServiceTicket"
Time entries by member:
conditions=member/id=123
Time entries by date range:
conditions=timeStart>=[2024-02-01] and timeStart<[2024-03-01]
Unbilled time entries:
conditions=status="Open" and billableOption="Billable"
Time entries for company:
conditions=company/id=12345
Approved time waiting for billing:
conditions=status="Approved" and billableOption="Billable"
My time this week:
conditions=member/id=123 and timeStart>=[2024-02-12] and timeStart<[2024-02-19]
/time/sheets
GET /time/sheets?conditions=member/id=123 and year=2024 and period=7
| Status | Description |
|---|---|
| Open | Time sheet open for editing |
| Submitted | Submitted for approval |
| Approved | Approved by manager |
| Rejected | Returned for correction |
PATCH /time/sheets/{id}
Content-Type: application/json
{
"status": "Submitted"
}
| Status | Description |
|---|---|
| Open | Pending approval |
| Approved | Approved for billing |
| Rejected | Rejected, needs correction |
| Billed | Already invoiced |
PATCH /time/entries/{id}
Content-Type: application/json
{
"status": "Approved"
}
PATCH /time/entries/{id}
Content-Type: application/json
{
"status": "Rejected",
"internalNotes": "Please add more detail about work performed."
}
POST /time/entries/bulk
Content-Type: application/json
{
"ids": [1001, 1002, 1003],
"operation": {
"status": "Approved"
}
}
Charge codes are used for non-ticket time (meetings, training, etc.).
GET /time/chargeCodes
| Code | Description | Billable |
|---|---|---|
| MTNG | Internal meetings | No |
| TRNG | Training | No |
| ADMIN | Administrative | No |
| PTO | Paid time off | No |
| PROJ | Project work | Yes |
| ONCALL | On-call time | Varies |
| Error | Cause | Resolution |
|---|---|---|
| chargeToId required | Missing ticket/project ID | Include chargeToId |
| member required | Missing member reference | Include member: {id: x} |
| timeStart required | Missing start time | Include timeStart field |
| Invalid work type | Work type doesn't exist | Query workTypes endpoint |
| Cannot delete | Time already billed | Cannot delete billed entries |
| Invalid status | Invalid status value | Use Open, Approved, Rejected |