All guides

Guide · Planning, buying and running AI

AI for Unbilled Work: Finding the Jobs You Finished and Never Invoiced

McGuire Flanigan · Updated November 1, 2026 · 12 min read

Unbilled work is a set difference, not a prediction. Reconcile what your crews completed against what your ledger invoiced, classify every gap by cause, age it from the day the work closed, and put the correcting lines in front of a person.

Unbilled Work Is Set Arithmetic. Treat It Like Arithmetic.

The category calls this revenue leakage detection, or unbilled revenue analysis, or sometimes revenue assurance, and the vocabulary has drifted far enough from the mechanics that most of what you will read is a percentage and a warning. Here is the mechanism stated plainly. Work performed is an enumerated list. Work invoiced is an enumerated list. Unbilled work is what remains when you subtract the second from the first. There is no estimation anywhere in that sentence.

This matters because it changes what you should buy and what you should believe. A vendor describing an AI model that predicts which jobs were probably missed is describing a probabilistic guess at a question that has a definite answer. The definite answer is sitting in two databases you already own, in fields that already exist, waiting for something to read both of them in one place.

So why does it not happen? Because the set difference needs two sets, and the two sets live in systems owned by two different functions. Your operational platform, whichever one it is, knows what your crews finished. Your ledger knows what your customers were billed. The office lead who could reconcile them has a month-end close, a phone that rings, and a spreadsheet somebody built in 2019 that imports two exports and has never quite handled partial invoices correctly. The reconciliation is nobody's job, so it is a month-end ritual, performed late, at the moment in the month when everyone is most tired.

The in-platform report is the most seductive wrong answer. Every field service and shop management system ships something called an unbilled jobs report, an open work order list, or a work-in-progress summary, and every one of them is comparing your platform to your platform. It can see that a ticket is unfinished. It cannot see that a ticket finished last Tuesday and no invoice ever appeared in the ledger, because the ledger is not in its data model. A report that cannot see half of the difference cannot report a difference. The gap lives precisely in the space between the two systems, which is the one place neither vendor has any reason to look.

Once you accept that framing, several things get easier. Detection stops being a research project and becomes a nightly job. Trust becomes possible, because every reported gap names an identifier on each side and you can verify it in seconds. And the honest scope of the work becomes clear: this is not a model that needs training data and a quarter of tuning. It is a reconciliation that needs two authenticated reads, a join key, and a classified output.

What Is Sitting In the Gap Right Now

Set your monthly volume, your average ticket, and what you honestly believe your unbilled rate is. The defaults are a nine-technician shop that has never run the reconciliation. Nothing is submitted, and no contact information is required.

Everything that reached a terminal state, whether or not it was invoiced.

Mix of maintenance work and larger repair orders, averaged honestly.

Most operators guess low. Anything under one percent across two systems is optimistic.

From the day the work closed to the day somebody catches it. Month-end means roughly thirty.

Commercial and fleet accounts always top this list, because consolidated billing hides a missing line inside a folder of thirty others.

Detecting gaps faster does not recover everything, and pretending otherwise would be dishonest. Older gaps have colder customer memory and a higher write-off rate. At a 32 day detection lag the recoverable share is roughly 52 percent, or about $12,660 a year.

Illustrative estimate from the inputs above. Your own numbers will differ; this is not a measured result or client data.

One Month, Five Stages, Twenty-One Gaps

Follow a single month of work through the reconciliation. Each stage names the real system entity it reads and states where this process usually breaks, because the break is almost never in the arithmetic.

Work Performed Enumerated

What Happens

The first list is every unit of work that was actually performed in the window. A job that reached a terminal state counts. So does a ticket that was signed off by a technician even though the parent status is still open, because the signature is the evidence and the status is metadata. This is the list nobody at the business maintains, and building it honestly is half the work.

The enumeration reads closed work orders with their line items, labor hours, and parts issue records. Where the field is populated, the work order number is captured as the join key that will tie this list to the ledger. Where it is not populated, the gap is recorded as a data-quality item on the report rather than silently dropped.

The operational system is the failure point, and it fails in the least visible way: a technician signs the job off and the parent ticket stays open. Every report that filters on terminal status silently excludes that work. The enumeration has to treat the signature as authoritative rather than the status field.

Reconciliation Record

Payloads are illustrative records from the Detail Driven Enterprises deployment in Jackson Hole, Wyoming, where this reconciliation runs across Tekmetric, CCC ONE, QuickBooks, Stripe, and Omega EDI on local Linux hardware with hybrid local and cloud inference. Field names are representative of the entities named above rather than a literal API response.

The Class Is the Fix, and the Age Is the Deadline

A leakage percentage is a diagnosis with no treatment attached, which is the same complaint every operator has about every benchmark report they have ever been handed. Twenty-one gaps is barely better. Twenty-one gaps sorted into four classes, each carrying a dollar value and an age measured from the day the work closed, is finally something a person can act on, because the class tells you who owns it and the age tells you how much time you have left.

Never Invoiced

The ticket is terminal, the work is documented, and no invoice exists on the other side. This is the cleanest case and usually the largest. The fix is a drafted invoice and a person to approve it, typically inside a day. At most service businesses this class alone is between forty and fifty percent of the total gap, which is why the simple version of this reconciliation, a closed-ticket-to-invoice match, is worth building even if nothing else gets built.

Partially Invoiced

An invoice exists and it is short. A parts line never got added, a labor clock was rounded down, a disposal or shop-supply fee was dropped in the rush to close out. This class hides much better than the first one, because the customer received a bill and the account looks serviced. Catching it requires comparing the invoice lines against the operational lines rather than comparing counts, and it is the class a spreadsheet reconciliation misses most often.

Scope Drift Beyond the Estimate

The customer approved work beyond the original estimate, the technician performed it, and the approval never became a recorded line. The invoice that follows is correct relative to the estimate and understated relative to the job, so both the customer and the ledger agree with each other and both are wrong. The fix is a reconciliation of estimate plus recorded changes against the final invoice total, with the delta named per job rather than summarized as a percentage.

Stale Ticket Status

The work is complete and signed off, and the parent ticket is still open because a follow-up visit was scheduled and already happened, or the ticket was reopened for a comeback that is long since resolved. This class is excluded from every operational report that filters on terminal status, which means the only way to find it is to trust the signature over the status. It also deserves a second life as a data-quality item, because the same condition quietly corrupts utilization, cycle time, and every work-in-progress number the business reports.

Why age is measured from the job close date, not from the report date. Because the customer's clock started when the work was finished, not when you noticed. A gap reported as thirty-four days old is a conversation with a fleet manager who has already closed their own books on that period, and the recovery rate on those is materially lower than on a gap that is four days old. Measuring from the report date flatters the aging column and hides the real cost of a monthly ritual.

Three Places We Will Tell You to Spend Elsewhere

Not a prediction engine, and be suspicious of anyone selling one

If a vendor describes a model that forecasts which jobs were probably missed, they are describing a guess at a question with a definite answer. Your closed work orders are a list. Your invoices are a list. The difference between two lists is arithmetic. A probabilistic approach to a deterministic question produces a report you cannot fully trust, and an untrustworthy gap report is worse than no report, because the office stops opening it. Ask any vendor in this category one question: can this name the work order number on each side of a gap? If the answer involves a confidence interval, you are buying the wrong method.

Not a reason to replace your field service platform

The reconciliation reads your operational system through its API or its export. It does not care which one you run, and it is not an argument for migrating. If you are considering a platform change for other reasons, that is a separate decision with its own costs, and the weeks of disruption in the middle of a migration will produce more unbilled work than the new platform will ever catch. Existing platforms are the system of record. We run around them, we do not replace them.

Not a substitute for closing tickets and recording changes

This is the honest one. If your technicians never record the parts they used, or your change approvals live in text messages, the reconciliation will report a real but understated gap, because the evidence of performed work is not being captured anywhere. Software can catch a job that was finished and never invoiced. It cannot catch value that nobody wrote down. If that is your situation, fix the capture discipline first, then automate the reconciliation on top of it.

Where the Line Sits on Every Revenue-Adjacent Action

The agent reads, subtracts, classifies, ages, and drafts. Everything that touches a customer, a price, or a promise stays with a person.

Why the never tier holds the money and the promise. A discount, a credit, a write-off, and a quoted price are all the same kind of decision, and it is the kind that depends on a relationship, a history, and a judgment about what the customer is worth over the next three years. No read of two databases produces that. The agent's job is to make sure nobody makes that decision while staring at a gap they cannot see, and to hand the person the full evidence when they do.

Straight Answers

Unbilled Work Is One Stage, Not the Whole Problem

Finding the gap is upstream of everything the accounting side does with it. Once the invoice exists, the next question is whether the customer pays it on time, which is the subject of the overdue invoice work. Before it, there is the broader question of everything that leaks between a completed job and a deposit, of which unbilled work is the largest single component but not the only one. And underneath both is the ledger integration that makes any of it possible.

Read those in the order the money moves: detect the leak, get the invoice out, then get the invoice paid.

The full picture of what escapes between job completion and deposit.

What the cycle looks like once the invoice finally exists.

Collecting it without damaging the account.

Run the Set Difference on Your Last Ninety Days

In thirty minutes we will pull closed work orders and ledger invoices from your two systems, compute the difference, and hand you a classified and aged list of every gap with the dollar value attached. You keep the list whether or not you hire us.

The reconciliation reads ServiceTitan V2, Jobber GraphQL, the Tekmetric Open API, Shopmonkey, Housecall Pro, and CCC ONE CIECA EMS 2.01 exports on the operational side, and the QuickBooks Online Accounting API on the ledger side. AutoLeap has no publicly documented developer API, so it is read through report exports with a slower detection window. Existing platforms stay the system of record.

Questions operators ask

How is this different from the unbilled report inside my field service software?

Your platform's unbilled or open-work report compares your platform to itself. It can tell you a ticket is unfinished. It cannot tell you a ticket finished last Tuesday and the ledger never received an invoice, because it has no view of your ledger at all. The reconciliation on this page needs both systems, which is exactly why neither vendor will ever ship it. If your platform's report were sufficient, you would not have searched for this.

Does it create and send invoices automatically?

It creates drafts and stages them. A person reviews the lines against the work and sends. We hold that line deliberately, and not only for liability reasons. Unbilled work is a set difference, so the detection is reliable, but the remedy is a message to a customer about money, and a wrong line sent to a fleet account costs more to repair than the line was worth. Drafting removes the labor. Sending stays human.

What if my technicians leave tickets open?

They will, and the reconciliation is built for it. A signed-off job line, a completed labor clock, and a documented parts issue are all evidence that work happened, whether or not the parent ticket reached a terminal state. Gaps of that kind are classified as stale ticket status and reported separately, because the fix is different: it is a status hygiene problem plus an invoice, not just an invoice. The stale tickets themselves also get reported as a data-quality item, since the same condition corrupts every other operational report you run.

What if my software has no public API, like AutoLeap?

AutoLeap has no publicly documented developer API. Its integration surface is native integrations, reporting exports, and work-order summaries, and we will say that plainly rather than implying parity with the systems that do publish one. Where AutoLeap is the operational system, the reconciliation reads the report export instead of an API. That works, and it changes the cadence: the oldest undetected gap is bounded by how often the export is generated rather than by webhook latency. It is a real limitation and it is stated as one.

How do I know the gaps it reports are real and not false positives?

Every reported gap carries the identifier from each side so you can check it yourself in about ten seconds. The forward pass names the closed work order with no matching invoice. The reverse pass catches the invoices that a naive match would have wrongly reported as missing, which is where most false positives come from in a spreadsheet reconciliation. And where the join key is absent entirely, the gap is flagged as a data-quality item rather than counted as recoverable revenue. We would rather the report be smaller and trustworthy.

See where AI fits in your operation

Thirty minutes on how the work actually moves. No pack of agents. No obligation to build. If we can help, we will show you the first paths. If we cannot, we will say so.

Sources

  1. api.getjobber.com/api/graphql, api.getjobber.com
  2. api.tekmetric.com/api/v1, api.tekmetric.com

More guides on planning, buying and running ai