Annual Maintenance Contracts: How to Structure, Price and Track Them
Post 4 Sep 2026 maintenance contractsrecurring revenueservice pricingcontract renewalsCRM
Annual maintenance contracts lose money for exactly two reasons: pricing based on an arbitrary percentage of the equipment's value instead of the actual cost of a service visit, and an unwritten scope that turns every customer phone call into a free obligation. Fix both with a single page — scope, exclusions, response levels — and a cost formula that starts from the number of planned visits rather than an inherited number.
Why most maintenance contracts lose money despite being "guaranteed revenue"
The loss never shows up on signing day. It shows up in month seven. Four causes repeat:
An open-ended scope that absorbs emergency call-outs nobody priced. Spare parts with no clear answer on who pays. A technician whose hours are booked against a project rather than the contract, making maintenance look profitable when it isn't. And contracts that expire in silence because no one owned the end date.
Contract structure: scope, exclusions, and response levels
Three elements, written plainly:
- Scope: exactly which assets are covered (serial number, location), how many preventive visits per year, and what each visit includes.
- Exclusions: misuse, faults caused by power supply or environment, consumable parts, modifications made by a third party. An exclusion you didn't write down will be read in the customer's favour.
- Response levels: time to respond and time to arrive on site, tiered by severity. For example: a fault that stops production → on site within 8 working hours; a partial fault → 24 hours.
Three pricing models: percentage, bottom-up, and tiered subscription
| Model | When it works | The risk |
|---|---|---|
| Percentage of equipment value | Uniform assets, known failure history | Disconnects price from real cost |
| Bottom-up cost | Mixed equipment or dispersed sites | Needs accurate visit data |
| Tiered subscription (Silver/Gold) | Many customers with different needs | Requires discipline to prevent "free upgrades" |
The safest approach in practice: calculate bottom-up, then present the result as tiered packages.
How to calculate the true cost of a visit before you price
Visit cost = (technician hours × fully loaded hourly cost) + travel and accommodation + average value of parts consumed + a share of overhead.
Then: Contract price = (preventive visits + expected emergency visits) × visit cost + margin.
Expected emergency visits are not a guess. Pull them from last year's ticket log for the same equipment type. If you have no log, start recording one today and price conservatively this year.
From supply to contract: when to offer maintenance, and who offers it
The best moment to introduce the contract is inside the supply quotation itself, as a priced optional line — not after the warranty expires. The rep who closed the supply deal is the one who should raise it, because the relationship is live and the budget is still open. Once the warranty ends, the customer is comparing you with a cheaper workshop.
Make it a written rule: no supply order closes without a linked maintenance opportunity, even if its status is "deferred".
The renewal calendar: scheduled visits, expiry, and pre-expiry alerts
Every contract has three dates that must be recorded, not remembered: preventive visit dates, the expiry date, and the date you open the renewal file (60–90 days before expiry). When those dates are generated automatically the moment a contract goes live in your system — as they are in Effistar — renewal stops being a surprise and becomes a scheduled task with a named owner.
## Metrics that show the health of your contract portfolio- Renewal rate: contracts renewed ÷ contracts due for renewal.
- Visit compliance rate: visits completed on schedule ÷ visits planned.
- Actual contract margin: revenue minus real visit and parts costs — per contract, not for the portfolio as a whole.
- Maintenance penetration: customers under contract ÷ total supply customers.
Start tomorrow with one action: pull the list of contracts expiring within 90 days and assign each one to a person by name.