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:
| ChargeStartDate | OfferName | ChargeType | Quantity |
|---|---|---|---|
| 2026-07-01 | Microsoft 365 Business Premium | cycleCharge | 38 |
| 2026-07-14 | Microsoft 365 Business Premium | addQuantity | 4 |
| 2026-07-22 | Microsoft 365 Business Premium | removeQuantity | -2 |
| 2026-07-09 | Microsoft 365 Business Premium | customerCredit | -1 |
| Sum of the Quantity column | 39 | ||
| Seats actually live at month end | 40 | ||
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.
Every ChargeType, and whether it moves the seat count
New commerce (NCE) subscriptions use these values. This is the vocabulary that matters:
| ChargeType | What happened | Counts as seats? |
|---|---|---|
cycleCharge | The normal monthly or annual charge. Your baseline. | Yes |
new | Subscription purchased mid-period. | Yes |
renew | Term renewed. | Yes |
addQuantity | Seats added mid-term, prorated. | Yes |
removeQuantity | Seats removed. Arrives negative. | Yes |
moveQuantity | Seats shifted between offers. | Yes |
convert | Trial converted to paid, or SKU converted. | Yes |
customerCredit | A refund or correction. Financial only. | No |
extendTerm | Term lengthened. No seat change. | No |
cancelImmediate | Cancelled 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 invoice | What it is today |
|---|---|
| Office 365 Business Premium | Microsoft 365 Business Standard |
| Office 365 Business Essentials | Microsoft 365 Business Basic |
| Office 365 Business | Microsoft 365 Apps for Business |
| Microsoft 365 Business | Microsoft 365 Business Premium |
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:
M365 BPMicrosoft 365 Bus. Prem.Micosoft 365 Business Premuim, two typos and still the right productEmail & Office Bundle, your own product name, sold at your own price
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:
- A file where one subscription is several rows, some negative.
- Two different charge-type vocabularies depending on migration state.
- A rename where a product name moved to a different product.
- An invoice written in your own language rather than Microsoft's.
- 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.