This report provides a detailed breakdown of rate conflict audit: find pricing errors before clients do for managed service providers.
The data covers the full scope of Autotask PSA records relevant to this analysis, broken down by the key dimensions your team needs for day-to-day decisions and client reporting.
Who should use this: Account managers, finance teams, and MSP owners managing renewals
How often: Monthly for pipeline review, 90 days before expiry for renewal preparation
EVALUATE ROW("TotalContracts", COUNTROWS('BI_Autotask_Contracts'), "TotalRevenue", SUM('BI_Autotask_Billing_Items'[total_amount]), "AvgValue", DIVIDE(SUM('BI_Autotask_Billing_Items'[total_amount]), COUNTROWS('BI_Autotask_Contracts')), "Companies", DISTINCTCOUNT('BI_Autotask_Contracts'[company_id]))
| Rate Category | Count | Share | Status |
|---|---|---|---|
| Total rate records | 220 | 100% | All contracts |
| Valid rates (>$0) | 153 | 69.5% | Billable |
| Zero-rate entries | 67 | 30.5% | Revenue risk |
| Rate range (valid) | $1 to $149/hr | No standard rate card | |
| Distinct billing roles | 13 | Roles defined | |
| Avg rate records per contract | 2.0 | 110 contracts | |
30.5% of all contract rate entries are set to $0. That's a significant data quality gap. Zero rates mean technicians can log hours against those contracts without generating any billable revenue. Whether intentional (for non-billable contract types) or accidental, each one needs to be reviewed. The rate range of $1 to $149/hr across valid entries suggests there's no standardized rate card, which raises the chance of setup errors each time a new contract or role is added.
-- Valid vs zero rate entries
EVALUATE
SUMMARIZECOLUMNS(
"Rate Category",
IF('BI_Autotask_Contract_Rates'[contract_hourly_rate] = 0,
"Zero Rate", "Valid Rate"),
"Entry Count", COUNTROWS('BI_Autotask_Contract_Rates'),
"Pct of Total", DIVIDE(
COUNTROWS('BI_Autotask_Contract_Rates'),
CALCULATE(COUNTROWS('BI_Autotask_Contract_Rates'), ALL('BI_Autotask_Contract_Rates'))
)
)
-- Rate range and role count
EVALUATE
ROW(
"Min Valid Rate", CALCULATE(
MIN('BI_Autotask_Contract_Rates'[contract_hourly_rate]),
'BI_Autotask_Contract_Rates'[contract_hourly_rate] > 0
),
"Max Rate", MAX('BI_Autotask_Contract_Rates'[contract_hourly_rate]),
"Distinct Roles", DISTINCTCOUNT('BI_Autotask_Contract_Rates'[role_name])
)
| Issue Type | Count | Percentage | Risk Level |
|---|---|---|---|
| Projects with no contract assigned | 31 | 11.1% | High |
| Time entries with no contract | 4,293 | 5.2% | Medium |
| Non-billable time entries | 9,530 | 11.5% | Low–Medium |
| Projects with contract assigned | 248 | 88.9% | OK |
| Total projects audited | 279 | 100% | Full scope |
31 projects have no contract assigned. Any time logged against those projects goes unlinked to a billing agreement, making it impossible to invoice correctly without manual intervention. At 4,293 time entries with no contract reference, that's a meaningful volume of hours floating in the system with no clear billing path. The non-billable entry count (9,530) is a separate category but worth tracking alongside these figures to distinguish intentional non-billable work from hours that are simply miscategorized.
-- Projects without contract
EVALUATE
ROW(
"Total Projects", DISTINCTCOUNT('BI_Autotask_Projects'[project_id]),
"Projects No Contract", CALCULATE(
DISTINCTCOUNT('BI_Autotask_Projects'[project_id]),
ISBLANK('BI_Autotask_Projects'[contract_id])
),
"Projects With Contract", CALCULATE(
DISTINCTCOUNT('BI_Autotask_Projects'[project_id]),
NOT(ISBLANK('BI_Autotask_Projects'[contract_id]))
)
)
-- Time entries without contract
EVALUATE
ROW(
"Total Time Entries", COUNTROWS('BI_Autotask_Time_Entries'),
"TE No Contract", CALCULATE(
COUNTROWS('BI_Autotask_Time_Entries'),
ISBLANK('BI_Autotask_Time_Entries'[contract_id])
),
"Non Billable Entries", CALCULATE(
COUNTROWS('BI_Autotask_Time_Entries'),
'BI_Autotask_Time_Entries'[is_billable] = FALSE()
)
)
Overall, 75.6% of logged hours are billable. That's the baseline. The question is whether the non-billable 24.4% is intentional or a symptom of rate conflicts and missing contract assignments. If projects without contract links are absorbing billable hours, the effective billable rate is lower than it looks on the surface. A deeper clean-up of the 31 unlinked projects and the 4,293 orphan time entries would give a clearer picture of what's actually being recovered as revenue.
EVALUATE
ROW(
"Total Hours Logged", SUM('BI_Autotask_Time_Entries'[hours_worked]),
"Billable Hours", CALCULATE(
SUM('BI_Autotask_Time_Entries'[hours_worked]),
'BI_Autotask_Time_Entries'[is_billable] = TRUE()
),
"Non Billable Hours", CALCULATE(
SUM('BI_Autotask_Time_Entries'[hours_worked]),
'BI_Autotask_Time_Entries'[is_billable] = FALSE()
),
"Billable Ratio", DIVIDE(
CALCULATE(
SUM('BI_Autotask_Time_Entries'[hours_worked]),
'BI_Autotask_Time_Entries'[is_billable] = TRUE()
),
SUM('BI_Autotask_Time_Entries'[hours_worked])
)
)
Review each one. Non-billable contract types may be intentional, but accidental zero rates are revenue leaks. For every role on those contracts that should be billable, no revenue is generated regardless of how many hours are logged. Start with contracts that have the highest time entry volume and verify whether the zero rate is by design.
Time entries on unlinked projects can't be invoiced correctly. The billing path from time entry to invoice requires a contract reference. Assign contracts before work starts, or at minimum before the next billing cycle closes. For recurring work, check whether a default contract is configured at the company level in Autotask.
These entries are billing orphans. They exist in Autotask but have no contract link, meaning they fall outside the normal invoicing flow. A monthly cleanup process would prevent accumulation. Filter by date range and sort by resource to identify who is most often logging against unlinked projects, then trace the root cause.
The majority of your project portfolio is properly set up. The 248 linked projects represent a solid baseline. Focus remediation effort on the 31 exceptions rather than treating this as a systemic failure. The rate conflict issues are concentrated and fixable with targeted effort.
-- Contracts with at least one zero-rate entry
EVALUATE
CALCULATETABLE(
SUMMARIZE(
'BI_Autotask_Contract_Rates',
'BI_Autotask_Contract_Rates'[contract_id],
'BI_Autotask_Contract_Rates'[contract_name],
"Zero Rate Count", CALCULATE(
COUNTROWS('BI_Autotask_Contract_Rates'),
'BI_Autotask_Contract_Rates'[contract_hourly_rate] = 0
),
"Total Rate Records", COUNTROWS('BI_Autotask_Contract_Rates')
),
CALCULATE(
COUNTROWS('BI_Autotask_Contract_Rates'),
'BI_Autotask_Contract_Rates'[contract_hourly_rate] = 0
) > 0
)
ORDER BY [Zero Rate Count] DESC
A contract rate conflict occurs when the hourly rate on a time entry doesn't match the contract's specified billing rate for that role. In Autotask, contracts define rates per billing role (e.g., Senior Engineer, Project Manager). If the rate on a time entry is $0 when the contract should bill $125/hr, or if the entry references the wrong contract entirely, that's a rate conflict. The result is either missed revenue or an incorrect invoice.
Some zero-rate entries are intentional. Managed service agreements with a flat monthly fee, warranty contracts, or non-billable service arrangements may have roles deliberately set to $0 because billing happens separately. The problem is when zero rates appear on contracts that should be billing by the hour. This happens when someone creates a new contract or adds a new role without completing the rate setup. The field defaults to $0 and gets overlooked.
In Autotask, open the project and navigate to the contract assignment field. Select the appropriate contract for that client. For recurring work, check whether a default contract is configured at the company level so new projects inherit the contract automatically. Going forward, make contract assignment a required step in your project creation checklist. For the 31 currently unlinked projects, prioritize the ones with the most recent time entries or the highest hour volumes first.
They get logged in Autotask but can't be tied to a billing agreement. This means they typically fall outside the invoicing run unless someone manually identifies and reassigns them. Over time, these orphan entries accumulate and either get written off or require expensive manual reconciliation at billing time. Setting up a monthly review process to catch and fix these before billing runs saves time and prevents revenue loss.
Monthly is the right cadence for most MSPs. Rate conflicts and missing assignments tend to accumulate gradually, and catching them before the billing cycle closes is far easier than retroactively fixing invoices. A quick audit at the start of each month, before you run billing, takes a few minutes with this report and can prevent disputes that take hours to resolve. If your team is adding new contracts or clients frequently, run it bi-weekly during high-growth periods.
Connect Proxuma Power BI to your PSA, RMM, and M365 environment, use an MCP-compatible AI to ask questions, and generate custom reports - in minutes, not days.
See more reports Get started