Why your Partner Center recon file never matches your invoice

One subscription throws several rows a month, and some of them are negative. If you add up the Quantity column you get the wrong number every single time.

This is the thing nobody explains properly, and it is why licence reconciliation quietly costs small MSPs real money. It is not carelessness. The file is shaped in a way that makes the obvious approach wrong.

The mistake everyone makes first

You download the licence-based reconciliation file, open it, filter to a client, sum Quantity, and compare that to what you invoiced. It seems like the only sensible thing to do.

Here is one real client, one product, one month:

ChargeStartDateOfferNameChargeTypeQuantity
2026-07-01Microsoft 365 Business PremiumcycleCharge38
2026-07-14Microsoft 365 Business PremiumaddQuantity4
2026-07-22Microsoft 365 Business PremiumremoveQuantity-2
2026-07-09Microsoft 365 Business PremiumcustomerCredit-1
Sum of the Quantity column39
Seats actually live at month end40

The sum says 39. The client has 40. The difference is the customerCredit row, which is money, not seats. It represents a refund for an outage or a billing correction. Counting it as a licence is like subtracting a discount from your headcount.

The rule Group by client and product, then add only the charge types that change the quantity. Credits, term extensions and immediate cancellations are financial events. They belong in your accounting, never in your seat count.

Every ChargeType, and whether it moves the seat count

New commerce (NCE) subscriptions use these values. This is the vocabulary that matters:

ChargeTypeWhat happenedCounts as seats?
cycleChargeThe normal monthly or annual charge. Your baseline.Yes
newSubscription purchased mid-period.Yes
renewTerm renewed.Yes
addQuantitySeats added mid-term, prorated.Yes
removeQuantitySeats removed. Arrives negative.Yes
moveQuantitySeats shifted between offers.Yes
convertTrial converted to paid, or SKU converted.Yes
customerCreditA refund or correction. Financial only.No
extendTermTerm lengthened. No seat change.No
cancelImmediateCancelled inside the window, with a refund.No

Legacy subscriptions use human-readable strings instead: Cycle fee, Cycle instance prorate, Cancel fee, Purchase fee. An MSP mid-migration will hold both formats at once, sometimes in the same month. Any script that matches only one vocabulary silently drops the other, and dropping rows looks exactly like a client who owes you nothing.

The renames that still cost money six years later

In April 2020 Microsoft renamed the Office 365 SMB plans. The trap is not that names changed. It is that one name moved to a different product:

Old name on your invoiceWhat it is today
Office 365 Business PremiumMicrosoft 365 Business Standard
Office 365 Business EssentialsMicrosoft 365 Business Basic
Office 365 BusinessMicrosoft 365 Apps for Business
Microsoft 365 BusinessMicrosoft 365 Business Premium
Read that first row twice "Office 365 Business Premium" became Business STANDARD. Meanwhile a different old plan became Business Premium. So an invoice line that still says the old name describes the cheaper product, while the word "Premium" points at the dearer one. If you priced that line by its name rather than its SKU, the rate has been wrong ever since, and it is wrong in whichever direction nobody has checked.

Microsoft's own price list styles the enterprise plans differently again: Microsoft Office 365 (Plan E3) in one export is Microsoft 365 E3 in another. Same licence, two spellings, no shared word order.

Then the second half of the problem, which is worse

Suppose you have solved the charge types and you know a client owns 40 Business Premium seats. Now you have to find that product on your own invoice. Your invoice does not say "Microsoft 365 Business Premium". It says one of these, because a human typed it:

The last one is the killer. Email & Office Bundle shares not a single word with Microsoft 365 Business Premium. No amount of string matching will ever connect them. Any tool claiming to automate this either asks you once and remembers, or it quietly reports your billed seats as unbilled, which is worse than useless, because a confident wrong answer gets sent to a client.

Why this survives in well-run shops

Nothing above requires anyone to be sloppy. It requires:

  1. A file where one subscription is several rows, some negative.
  2. Two different charge-type vocabularies depending on migration state.
  3. A rename where a product name moved to a different product.
  4. An invoice written in your own language rather than Microsoft's.
  5. A month-end where this is the twelfth thing on the list.

Each is individually manageable. Together they mean the check is genuinely hard, so it gets done once a year, or when a client queries a bill. Seats added in March get noticed in November, and the eight months in between are simply gone: you paid Microsoft for them and nobody was ever invoiced.

Checking it takes about a minute

There is a page that does the compare. Drop in the recon CSV and your invoice export and it lists what is short, per client, per SKU. It handles the charge-type collapse, the renames and the abbreviations, and it asks you about anything it cannot match instead of guessing.

It runs entirely in your browser. Nothing is uploaded, there is no account, and it is free. Open it.

Written August 2026. The charge-type list follows Microsoft's published licence-based reconciliation file documentation; the rename table follows Microsoft's April 2020 SMB plan announcement. If any of it has drifted, the file itself is the authority, not this page.

Working out which tool to use? The paid options compared. BillingReconcile, Sync 365, Syncro Universal Billing and Gradient MSP, with prices and which ones need a PSA.

No PSA? The manual reconciliation method, step by step.

Every rename with its date: the two that changed the product, and the ones that only changed the name.