Autotask Contracts — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Autotask Contracts (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Contracts in Autotask define the service relationship with clients - what services you provide, how you bill for them, and what service levels apply. Contracts control how time and expenses flow to invoices and are critical for MSP financial management.
autotask-billing.
bundles exist in the catalog independently of any contract; use autotask-product-catalog.
contract objects that do not sync with Autotask; use kaseya-bms-api-patterns.
SLA on its own contract object, which does not sync with Autotask; use halopsa-contracts.
| Type | Description | Billing Method |
|---|---|---|
| Recurring Services | Monthly/annual managed services | Fixed recurring fee |
| Block Hours | Prepaid hour bank | Deduct from balance |
| Time & Materials | Pay as you go | Bill actual time |
| Fixed Price | Project-based fixed fee | Milestone billing |
| Retainer | Prepaid monthly hours | Use or lose |
| Field | Description | Required |
|---|---|---|
id | Unique identifier | System |
contractName | Contract name | Yes |
companyID | Client company | Yes |
contractType | Type of contract | Yes |
status | Contract status | Yes |
startDate | Contract start | Yes |
endDate | Contract end | Yes |
setupFee | One-time setup fee | No |
timeReportingRequiresStartStopTimes | Require start/stop | No |
serviceLevelAgreementID | SLA assignment | No |
| ID | Status | Description |
|---|---|---|
| 1 | Active | Current, billable |
| 2 | Inactive | Suspended |
| 3 | Cancelled | Terminated |
Services define what's included in a contract:
| Field | Description |
|---|---|
serviceName | Name of service |
unitPrice | Price per unit |
unitCost | Cost per unit |
periodType | Monthly, Quarterly, Annual |
isOptional | Required vs optional |
The autotask-mcp server exposes typed contract tools — prefer these over autotask_raw_request. Read tools return contract header fields only (no service lines), keeping responses light.
Tool: autotask_search_contracts
Args: {
"companyID": 12345,
"status": 1,
"searchTerm": "Managed",
"pageSize": 25
}All filters optional: searchTerm (contains-match on contract name), companyID, status, pageSize (default 25, max 500). This is the only read tool for contracts — there is no contractType or end-date filter; filter on contractType/endDate client-side from the returned records.
There is no autotask_get_contract tool. There is no autotask_list_expiring_contracts tool either — autotask_search_contracts is the only read path for contracts. To fetch one contract, call autotask_search_contracts (scoped by companyID when known) and match the target id from the results. To build a 30/60/90-day renewal pipeline or find contracts already past their end date, call autotask_search_contracts with status: 1 (scoped by companyID when reviewing one account, otherwise paged across the portfolio) and filter/sort the returned records client-side by endDate:
endDate on or before today → expired but still Active — the compliance-risk case. Autotask does not auto-deactivate expired contracts, so this is how clients still receiving service on expired paper are found.endDate within the next 30/60/90 days → the renewal call list, in ascending urgency order.Tool: autotask_create_contract
Args: {
"companyID": 12345,
"contractName": "Acme Corp - Managed Services",
"contractType": 1,
"contractCategory": 3,
"startDate": "2026-01-01",
"endDate": "2026-12-31",
"status": 1
}Required: companyID, contractName, contractType, contractCategory, startDate, endDate
For multi-contract onboarding (e.g. one contract per client location), pass up to 50 shells in one call — same fields per item as autotask_create_contract:
Tool: autotask_create_contracts_bulk
Args: {
"contracts": [
{ "companyID": 12345, "contractName": "Acme - HQ", "contractType": 1, "contractCategory": 3, "startDate": "2026-01-01", "endDate": "2026-12-31" },
{ "companyID": 12345, "contractName": "Acme - Branch", "contractType": 1, "contractCategory": 3, "startDate": "2026-01-01", "endDate": "2026-12-31" }
]
}Shells are created sequentially (Autotask has no batch endpoint); a failure on one shell does not abort the rest. Each item reports {index, contractName, success, id | error} — retry only the failures.
Tool: autotask_update_contract
Args: { "id": 54321, "endDate": "2027-12-31", "status": 1 }Only fields provided change — the typical renewal move is extending endDate.
autotask_create_contract_service (required: contractID, serviceID, unitPrice) and autotask_update_contract_service (required: id, contractID) manage the ContractServices line items on a contract.
Raw REST shapes for reference — the typed tools above cover these; reach for autotask_raw_request only for entities without typed tools (ContractBlocks, ContractRetainers, etc.).
POST /v1.0/Contracts
Content-Type: application/json{
"contractName": "Acme Corp - Managed Services",
"companyID": 12345,
"contractType": 1,
"status": 1,
"startDate": "2024-01-01",
"endDate": "2024-12-31",
"setupFee": 500.00,
"timeReportingRequiresStartStopTimes": true,
"serviceLevelAgreementID": 1
}POST /v1.0/ContractServices
Content-Type: application/json{
"contractID": 54321,
"serviceID": 111,
"unitPrice": 150.00,
"adjustedPrice": 150.00,
"quantity": 50,
"effectiveDate": "2024-01-01"
}POST /v1.0/Contracts
Content-Type: application/json{
"contractName": "Acme Corp - Block Hours",
"companyID": 12345,
"contractType": 4,
"status": 1,
"startDate": "2024-01-01",
"endDate": "2024-06-30"
}Then add block hours:
POST /v1.0/ContractBlocks
Content-Type: application/json{
"contractID": 54322,
"datePurchased": "2024-01-01",
"hoursPurchased": 40,
"hourlyRate": 150.00,
"isPaid": true
}Active contracts for a company:
{
"filter": [
{"field": "companyID", "op": "eq", "value": 12345},
{"field": "status", "op": "eq", "value": 1}
]
}Contracts expiring soon:
{
"filter": [
{"field": "status", "op": "eq", "value": 1},
{"field": "endDate", "op": "lte", "value": "2024-03-31"},
{"field": "endDate", "op": "gte", "value": "2024-01-01"}
]
}GET /v1.0/ContractBlocks/query?search={"filter":[{"field":"contractID","op":"eq","value":54322}]}Calculate remaining hours:
hoursPurchased - Sum of time entries against contractautotask_search_contracts with status: 1, windowed client-side by endDate into 30/60/90-day bucketsendDate before today to catch already-lapsed contracts still marked activeContracts can be linked to SLAs:
| SLA Metric | Description |
|---|---|
| Response Time | Time to first response |
| Resolution Time | Time to resolve |
| Uptime | System availability % |
| Business Hours | When SLA applies |
SLA violations trigger alerts and can affect contract terms.
| Code | Message | Resolution |
|---|---|---|
| 400 | Invalid contract type | Use valid contract type ID |
| 400 | EndDate before StartDate | Fix date sequence |
| 409 | Cannot modify - has billing | Adjust dates only |
| 404 | ServiceID not found | Verify service exists |
"CompanyID is required" - Must associate with a company
"StartDate is required" - All contracts need start date
"Invalid service for contract type" - Service must match contract type
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.