Hashlogics
Blog

HVAC job costing: where the margin actually goes

You can pull revenue by job in seconds. True cost is a different question, and it's scattered across four systems that don't agree with each other.

The short version

4 things that decide this

  1. 01Your FSM tells you revenue by job easily. It rarely tells you true cost, because labour, equipment, subs, permits and warranty callbacks live in the FSM, QuickBooks or a similar accounting system, payroll and the ad platforms, and the join key between them is loose or missing.
  2. 02True job cost includes labour with drive time and callback time counted, materials at real landed cost, permit fees, subcontractor cost, and any warranty work charged back to the original job.
  3. 03Your FSM's margin report and your accounting numbers disagree because they're measuring different things: the FSM often uses list price and a rough labour estimate, while QuickBooks reflects what actually got paid out.
  4. 04A monthly view worth having tracks margin by job type and by technician, A/R aging, and callbacks counted as a cost against the original job, not written off as a separate line.
The question owners can't answer

You know revenue by job. You don't know cost

Ask most HVAC owners which jobs made money last month, and you'll get a feeling, not a number. It's not that they don't care. Revenue by job is easy: your FSM shows it on one screen. Cost is the hard half, and almost nobody's system was built to answer it cleanly.

That gap costs you real money over a season. It's more than accuracy on a spreadsheet. An unprofitable job type gets repeated for years because nobody can prove it's the problem. You end up pricing by feel instead of by margin. And a technician gets judged on how much revenue they bring in. Rarely does anyone check how much of it survives after the real costs land, which rewards the wrong behavior.

Where the pieces actually live

Four systems, and none of them talk to each other

Your FSM holds the job record: what was sold, what was invoiced, and often a rough estimate of labour and materials cost. That's true whether you run ServiceTitan, Housecall Pro, FieldEdge or something else. The estimate is a planning number, built before the job happened. It isn't a record of what the job actually cost.

Your accounting system, usually QuickBooks, holds what you actually paid: the real materials invoice, the real payroll run, the real subcontractor check. It knows the truth about cost. It rarely knows which job that cost belongs to unless someone tags it by hand every time.

Payroll holds the hours, but not always split by job. A technician who touched three jobs in a day, with drive time between them, is the hard case. Your ad platforms hold something too: what you paid to generate the lead. That number almost never makes it into a job's cost, even though it's a real expense tied to that specific sale.

None of these four systems was designed with the others in mind. What should connect a payroll entry to a job record to a materials invoice is one shared job number. Too often, someone types that number by hand into three different places, and the link breaks constantly.

What real cost actually includes

Labour, drive time, callbacks: the parts most reports skip

True job cost is more than the FSM's line item for labour. Drive time counts. A job across town costs more than an identical one down the street, even when the invoice looks the same. Unbilled callback time counts too, and it's the one people skip most. If a technician goes back to fix something for free, that visit's labour and materials belong to the original job's cost. They shouldn't sit in a separate bucket that never gets totaled.

Equipment cost needs to reflect what you actually paid your distributor, freight and handling included, not a list price pulled from a catalog. Truck and overhead allocation matter too, even in rough form. A van, insurance and tools cost something every day, whether or not that day produced revenue. Permits and subcontractor payments are usually captured somewhere, but rarely tied back to the job that triggered them. And the marketing cost of the lead itself is real money spent on that specific sale, even where it never shows up next to the job in any report you've seen.

Put all of that together for one job, and you'll often find your real margin sits several points below what the FSM's quick estimate suggested. That gap isn't an accounting error. It's the cost of things your FSM was never built to track.

  • 01Labour: drive time and unbilled callback time, on top of the invoiced hours.
  • 02Materials: at real landed cost from the distributor invoice, not list price.
  • 03Overhead: truck, insurance and tools allocated even roughly across the jobs that used them.
  • 04Acquisition: what you paid to generate the lead, tied back to the job it produced.
Why the two numbers never agree

Your FSM's margin report and QuickBooks are answering different questions

You've probably pulled a margin number from your FSM, then checked it against QuickBooks, and gotten two different answers for the same month. Neither one is wrong. They're measuring different things.

Your FSM's margin report is usually built at estimate time, using list prices and a standard labour rate, before anyone knows what the job will actually cost. QuickBooks reflects what actually happened, weeks later: the real distributor invoice, the real payroll run, the real check to a subcontractor. One is a forecast, and one is a record. Comparing them directly means comparing a plan to an outcome, and they were never going to match exactly.

Picking one system as the source of truth and ignoring the other isn't the fix. You need a view that pulls the plan from the FSM and the actuals from accounting, then reconciles them against the same job. That reconciliation is the part almost nobody does by hand, because it's tedious and the job numbers rarely match cleanly across systems.

What reconciles automatically, and what stays a decisionLive
  1. Payroll hoursMatched to the job number, drive time included
  2. Materials invoicePulled from the distributor bill, not the FSM's estimate
  3. Callback labourCharged back to the original job, not a separate bucket
  4. A warranty repair eaten for a good customerStill your team's call, with the real numbers in front of them

Reconciliation is mechanical. Deciding what to do about a thin-margin job type stays with the owner.

A monthly view worth having

What an owner should be able to see, in one place

None of these are exotic metrics. They're just scattered across systems that were never asked to combine.

The viewWhat it showsWhere it comes from today
Margin per job typeWhich service lines actually make moneyFSM job records, reconciled against accounting
Margin per technicianPerformance measured on profit, not booked revenuePayroll hours joined to job records
A/R agingCash that's earned but not yet collectedAccounting system, usually already tracked but rarely reviewed monthly
Callbacks as a costWarranty labour and materials charged to the original jobFSM callback records, rarely linked back to the first visit
What to pull from where, and what automates

This is a connection problem, not a new system

You don't need to replace ServiceTitan, Housecall Pro, FieldEdge or your own custom setup to get this view. Those systems just need to feed the same reconciliation as QuickBooks and payroll. Right now they mostly sit in separate silos, reconciled by hand once a quarter, if at all.

What automates well is the joining. A payroll entry, a materials invoice and a callback record all get matched to the job they belong to, then rolled up into margin by job type and by technician every month, with nobody rebuilding a spreadsheet. What doesn't automate is the judgment call on a job that looks unprofitable for a defensible reason, like a warranty repair you chose to eat for a good customer. Your team still makes that call with the numbers in front of them. A report doesn't make it for you.

Questions, answered
01Do we need to replace QuickBooks or our FSM for this to work?+

No. The value comes from connecting what you already run: your FSM, your accounting system and payroll, so their numbers reconcile against the same job. Replacing a working system rarely earns back what it costs to switch.

02How far back should we reconcile to see a useful pattern?+

Three to six months is usually enough to see whether a job type or a technician's numbers are consistent or a one-off. A single month can be misleading if it included an unusual job or a slow week.

03What if our FSM doesn't break out labour and materials separately?+

That's common, and it's part of what we look at during an audit: how granular your current data actually is, and what level of job costing detail is realistic to build from it without asking your team to change how they work.

04Can this work for a shop that still tracks costs mostly on paper or in spreadsheets?+

Yes, though it usually means more manual entry gets automated first before the reconciliation itself can run cleanly. We confirm what's realistic for your current setup during the audit rather than assuming a particular starting point.

By Abdul Basit, CEO, HashlogicsUpdated
Start

Let’s deploy working AI into your business.

We build AI agents and automation, ship them into the tools you already run, then stay on under an agreed service level. A senior engineer reads every brief, and your call gets scheduled within 24 hours.

What happens next

  1. 01

    You send a brief or book a call

    Two minutes, whichever you prefer.

  2. 02

    A senior engineer replies within 24 hours

    Not a sales rep.

  3. 03

    Honest scoping, in writing

    And if we’re not the right fit, we say so.

Abdul Basit, CEO of Hashlogics

“I started Hashlogics because too many teams ship a demo, get paid, and disappear. We build to a standard we’d run ourselves — and we stay to keep it running.”

Abdul Basit · CEO · a direct line

Not ready to talk? Take the checklist.

12 questions to ask any AI agency before you sign. They separate a demo shop from a team that ships to production.

Get the checklist

Free · no newsletter