Methodology & Accuracy
Last reviewed: August 12, 2026. Worked examples expanded October 2026, pending the next review; every figure in them is recomputed by the engine on each build.
An invoice is a document someone checks with a calculator. This page documents exactly how the figures are produced, and — just as importantly — what this tool deliberately does not do.
It is also the page the guides rest on. What each of the three documents is for is set out in invoice, receipt or quote; the fields are covered in what to put on an invoice; the two ways a tax can sit on a price in sales tax vs VAT; numbering in how to number invoices; due dates in payment terms. Three further guides walk the arithmetic below at greater length: how invoice totals are computed, inclusive vs exclusive tax arithmetic and receipts, quotes and the bottom-line label. All of them are listed on the guides page, and every figure in them is produced by the same engine as the figures here.
Money is held in whole cents, never as a decimal
Every amount is stored as an integer number of cents. Decimal fractions cannot be represented
exactly in binary floating point: 0.1 + 0.2 evaluates to
0.30000000000000004. That is a curiosity in isolation and a dispute on a
hundred-line invoice, where the accumulated fractions produce a subtotal that does not match the
column above it. Integer cents make the arithmetic exact.
The conversion happens once, on the way in. A price typed as a decimal is multiplied by one hundred and rounded half away from zero to an integer number of cents, and from that point every sum, percentage and division on the page is done on integers. The largest amount the engine will hold is $1,000,000,000,000.00; a figure beyond it is refused with a message rather than silently truncated. Display runs the other way: the integer is split into whole units and a two-digit remainder, which is why every amount on a document prints with exactly two decimal places and never with three.
Rounding happens once, at the line
Each line is quantity × unit price, rounded to a cent immediately, and the subtotal is the sum of those rounded lines. The alternative — keeping full precision and rounding only the total — is marginally more accurate and visibly wrong to a reader, because the printed lines would not add up to the printed subtotal. The document has to reconcile in the hand of the person holding it.
Rounding is half away from zero (0.5 → 1, −0.5 → −1), which is how people round by hand.
Banker's rounding is better behaved statistically and would surprise every user, so it is not
used. The engine also rounds a sub-cent unit price to a printable price before
multiplying, for the same reason. Handed 3 dowels at a unit price given as
0.125 — the raw input, not a printed amount — it prints
3 × $0.13 = $0.39, a line a reader can multiply, rather than a line whose printed figures do not multiply to its
amount. On the form that rule is a guard rather than something a document will show, because a
money field refuses more than two decimal places — the parser table further down shows the
refusal.
A five-line invoice, line by line
Take a fictional invoice from Alder Street Joinery to Marlow Café with five lines: a site survey at $180.00, 3.5 metres of oak shelving at $64.00 a metre, 3.3333 hours of fitting at $45.00 an hour, 7 brass brackets at $3.99 each, and 1.75 litres of sanding sealer at $11.46 a litre. Each line goes through the line calculation on its own:
| Line | Quantity | Unit price | Amount |
|---|---|---|---|
| Site survey | 1 | $180.00 | $180.00 |
| Oak shelving (metres) | 3.5 | $64.00 | $224.00 |
| Fitting (hours) | 3.3333 | $45.00 | $150.00 |
| Brass brackets | 7 | $3.99 | $27.93 |
| Sanding sealer (litres) | 1.75 | $11.46 | $20.06 |
| Subtotal | $601.99 | ||
Two lines show the rules at work. The fitting line multiplies 3.3333 hours by $45.00; the exact product is $149.9985, and the line rounds it to $150.00 before anything else happens. The sealer line multiplies 1.75 litres by $11.46; the exact product is $20.055, which sits exactly half a cent between two printable amounts, and half away from zero takes it up to $20.06. Add the five printed amounts by hand and they come to $601.99, which is exactly the subtotal the engine prints. Had it kept the exact products and rounded once at the end, the subtotal would read $601.98 — $0.01 short of the column above it, and the first thing a careful reader would query.
Order of operations
Subtotal → discount → taxable base → tax → shipping → total → amount paid → balance due. The discount comes off before tax, because tax is owed on what was actually charged. Shipping is added after tax, which is a simplification: some jurisdictions tax freight, and this tool does not model that. If yours does, add shipping as a line item instead so it falls inside the taxable base.
The same invoice through the totals
Now give that invoice a 10% discount, tax added on top at 8.875%, shipping of $12.50, and a deposit of $200.00 already received. The totals are computed in the order above, each step reading the result of the one before it:
- Subtotal: the five rounded lines, $601.99.
- Discount: 10% of the subtotal, rounded half-up to $60.20. A flat discount, had there been one, would be added to this figure in cents.
- Taxable base: subtotal less discount, $541.79. This — not the subtotal — is the figure the tax is computed on.
- Tax: 8.875% of the taxable base, rounded once to $48.08.
- Shipping: $12.50, added after tax and therefore outside it.
- Total: taxable base plus tax plus shipping, $602.37.
- Amount paid: $200.00.
- Balance due: total less amount paid, $402.37.
The order is the substance. Had the discount been taken after the tax instead of before it, the tax would have been charged on the full $601.99 and come to $53.43 rather than $48.08 — a difference of $5.35 on this one document, charged on money the client was never asked for.
The discount floor
A fictional 2-day equipment hire at $40.00 a day has a subtotal of $80.00. Give it a 50% discount and a further flat discount of $60.00. The percentage alone comes to $40.00; the flat amount is added to it, and together they exceed the subtotal. The engine caps the discount at the subtotal: the discount line reads $80.00, the taxable base is $0.00, and the tax at 10% on that base is $0.00. Shipping of $9.00 is added after tax, so the total is $9.00. A discount can empty the goods and the tax on them; it never reaches the shipping line, because shipping is not part of the base the discount is taken from.
Overpayment
A fictional invoice for first-stage design work at $150.00, with no tax, against which $175.00 has already been received. The total is $150.00, the amount paid is $175.00, and the balance due is $0.00 rather than a negative $25.00. The engine floors the balance at zero and prints no credit line; the amount paid still prints, so both sides can see what was received.
Inclusive tax is extracted, not added
With tax set to “added on top”, $120.00 at 20% becomes $144.00 — the tax of $24.00 sits on top. With tax set to “already included”, the same $120.00 contains $20.00 of tax and the total stays $120.00: the tax is found by dividing by 1 + the rate, never by subtracting a percentage. Subtracting 20% from a VAT-inclusive price overstates the tax by a fifth — one-fifth of the correct figure. Here it would claim $24.00 against the $20.00 the engine finds, $4.00 too much — and it is a common arithmetic error on hand-made invoices. Both figures above were computed by the engine when this page was built.
The same pair at two more rates
The pattern holds at any rate. A fictional single line of $250.00 was run through both modes at 5%, 15% and 20%, and the last column shows what subtracting the percentage from the gross would have claimed instead:
| Rate | Added on top: tax | Added on top: total | Included: tax | Included: total | Subtracting the percentage |
|---|---|---|---|---|---|
| 5% | $12.50 | $262.50 | $11.90 | $250.00 | $12.50 |
| 15% | $37.50 | $287.50 | $32.61 | $250.00 | $37.50 |
| 20% | $50.00 | $300.00 | $41.67 | $250.00 | $50.00 |
Read the “included” column against the last one. At 15% the engine finds $32.61 inside $250.00; subtracting 15% of the gross would claim $37.50, overstating the tax by $4.89. At 20% the overstatement is $8.33 on $41.67 — a fifth of the correct figure, as above. The error grows with the rate because it is the rate: before rounding to a cent, the subtracted figure is always one-plus-the-rate times the correct one, so the overstatement is the rate times the correct tax. When the tax is included, the total stays at the gross $250.00 in every row, because the tax is already inside it; when it is added on top, the total rises by exactly the tax. With tax set to none, no tax line is produced and the total is the taxable base plus shipping.
Which mode describes your prices is not something the engine decides. It computes whichever you select, and the sales tax vs VAT guide explains the two conventions without telling you which one applies to you.
What the fields accept
Numbers arrive as text, and the parser's job is to read what was typed without guessing between conventions that contradict each other. Dot-decimal, comma-decimal and correctly grouped thousands are all accepted; a currency symbol is stripped, and in a rate field a trailing percent sign is stripped; spaces between digit groups are ignored. A mix of separators is accepted only when the last one is unambiguously the decimal mark and the earlier ones form valid groups of three. Money fields take up to two decimal places, rates and quantities up to four. The tax-rate, discount, shipping and amount-paid fields are optional: left blank, each is read as zero and no message is shown. The rows below are real calls to the three parsers, made when this page was built, with the message each refusal shows on the form:
| Field | Typed | Result |
|---|---|---|
| Money (unit price) |
$1,250.50
|
Accepted as $1,250.50 |
| Money (unit price) |
1.250,50
|
Accepted as $1,250.50 |
| Money (unit price) |
1 250,5
|
Accepted as $1,250.50 |
| Money (unit price) |
1,250
|
Accepted as $1,250.00 |
| Money (unit price) |
1.250
|
Accepted as $1,250.00 |
| Money (unit price) |
0.999
|
Refused: “Enter a valid unit price with at most 2 decimal places.” |
| Money (unit price) |
12.50.3
|
Refused: “Enter a valid unit price without ambiguous separators.” |
| Money (unit price) |
-40
|
Refused: “Unit price cannot be negative.” |
| Money (amount paid) |
twelve
|
Refused: “Enter a valid amount paid.” |
| Rate (tax rate) |
8.875%
|
Accepted as 8.875% |
| Rate (tax rate) |
7,5
|
Accepted as 7.5% |
| Rate (tax rate) |
20 %
|
Accepted as 20% |
| Rate (discount) |
0.12345
|
Refused: “Enter a valid discount with at most 4 decimal places.” |
| Quantity |
3.3333
|
Accepted as 3.3333 |
| Quantity |
1.250
|
Accepted as 1.25 |
| Quantity |
2.25.1
|
Refused: “Enter a valid quantity without ambiguous separators.” |
| Quantity |
0.12345
|
Refused: “Enter a valid quantity with at most 4 decimal places.” |
| Quantity |
-2
|
Refused: “Quantity cannot be negative.” |
One rule in that table is worth knowing. A lone three-digit group after a single separator is
read as a thousands group in a money field — 1.250 becomes
$1,250.00 — and as a fraction in a quantity or rate field, where
1.250 becomes 1.25. A money field prefers that reading because a
printable price has two decimals and a thousands group has three, whereas a fractional quantity
is ordinary. If you mean a fraction in a money field, two decimal places are unambiguous.
What the engine refuses
Beyond the parsers, the line, totals and document builders check the document itself and return a message instead of a figure when something cannot be computed. A rate above its ceiling is refused, not reduced to the ceiling, and a malformed date is refused rather than guessed at. Each message below was produced by a real call when this page was built, so the limits quoted in them are the limits in force:
| Situation | Message |
|---|---|
| A line whose description is blank | Every line needs a description. |
| A negative unit price | Unit price cannot be negative. |
| A quantity of 1,000,001 | That quantity is too large. |
| A unit price ten times the largest amount the engine holds | That amount is larger than this tool supports. |
| A document with no lines | Add at least one line item. |
| A document with 201 lines | A document holds at most 200 lines. |
| A discount of 150% | The discount cannot exceed 100%. |
| A tax rate of 101% | The tax rate cannot exceed 100%. |
| A tax rate with five decimal places | The tax rate can have at most four decimal places. |
| Notes one character over the limit | Notes are limited to 600 characters. |
| A due date before the document date | The second date cannot be before the document date. |
| A document date of 30 February | Choose a valid document date. |
| A sender name left blank | Enter who the document is from. |
The two rate ceilings in those messages are the constants listed further down. The message quotes the constant rather than restating it, which is why this page can promise the two agree.
How to read the document
The document builder assembles the totals together with the document's kind, and the kind decides what the bottom line is called: Balance due on an invoice, Amount paid on a receipt, Quote total on a quote. A receipt that said “Balance due” would invite a second payment, and a quote that said it would read as a demand for money not yet owed. A fictional job — 4 hours of fitting at $45.00, tax added on top at 10%, with $100.00 entered as already received — built three times:
| Document | Number | Date | Already-paid field | Bottom-line label | Bottom-line figure |
|---|---|---|---|---|---|
| INVOICE | INV-20261001 | 1 October 2026 | $100.00 | Balance due | $98.00 |
| RECEIPT | RCT-20261001 | 1 October 2026 | — | Amount paid | $198.00 |
| QUOTE | QTE-20261001 | 1 October 2026 | — | Quote total | $198.00 |
Two things in that table are easy to misread. The amount already received is only honoured on the invoice, where the balance due drops to $98.00. A receipt is the record that the whole amount arrived, so its bottom line carries the document total of $198.00 under “Amount paid” and the amount-paid field is ignored; expecting a receipt to show a balance is the misreading the label exists to prevent. A quote has nothing paid against it yet, so its bottom line is the same total under “Quote total”. The second is the number: left blank, the document is given a date-stamped number of the form INV-20261001, which is a placeholder rather than a sequence — how to number invoices covers what a sequence needs, and sequential numbering across sessions is one of the things this tool does not do.
The date prints as 1 October 2026 rather than in a numeric form, so a reader who writes the month first and one who writes the day first see the same day. The tax line is labelled with whatever you type into the tax-label field; left blank, it reads “Tax” when tax is added on top and “VAT (included)” when tax is marked as already included, with the rate printed beside it. The bottom-line label guide walks the three documents through a full example, and invoice, receipt or quote covers when to send which.
Limits
- Up to 200 lines per document; tax rates up to 100% and discounts up to 100%.
- Quantities are held to four decimal places, so billed hours like 3.3333 do not drift.
- A discount can reduce a document to zero, never below it.
- Overpayment shows a balance due of zero rather than a negative amount.
- Ten currency symbols are offered. The symbol is a label printed on the document — no conversion is performed and no exchange rate is applied, so every figure stays in the currency you entered.
- A logo can be added from an image file of up to 15 MB — the one size ceiling the normaliser enforces, listed under Constants below. It is re-encoded as PNG or JPEG and drawn with its aspect ratio preserved inside a box of at most 42 × 16 mm — the engine's default logo box; a template that reserves less room for a logo draws it smaller — placed where the chosen template puts its logo. Like everything else, it is read and drawn on your device — never uploaded.
Constants
Each limit above traces to a named constant in the engine or to a check inside it. The values below are read from the engine when this page is built, so they are the values the tool enforces today rather than the values it enforced when the prose was written:
- Tax-rate ceiling: 100%. Discount ceiling: 100%. Both refuse rather than clamp, with the messages shown above. Rates are held to four decimal places.
- Largest amount held: $1,000,000,000,000.00. Unit prices, flat discounts, shipping, amounts paid and line amounts are checked against it; a subtotal or total too large to hold exactly is refused as well.
- Notes: 600 characters.
- Currency symbols: 10, namely $, £, €, ¥, C$, A$, INR, R$, kr, CHF. The symbol is written in front of each figure; the rupee appears as its three-letter code because the fonts built into the PDF do not contain the rupee glyph, and a visible code is safer than a missing character.
- Image decode ceiling: 15 MB. A logo file is normalised on your device before it reaches the PDF — decoded, scaled down to fit the logo box, and re-encoded — and the normaliser refuses outright to decode a file above that size. What is placed into the PDF is the scaled copy, not the original file.
- Lines per document: the ceiling is enforced by the totals calculation, and its message is quoted in the refusals table above.
What this does not do
It is a document generator, not an accounting system and not tax advice. It does not file anything, track payment, chase late payers, apply per-jurisdiction tax rules, validate tax numbers, handle multi-currency conversion, or number your documents sequentially across sessions. It stores nothing: close the tab and the document is gone, so download the PDF. If you need recurring billing or bookkeeping, you need software with an account, and this is deliberately not that.
Nothing leaves your browser
The document is assembled and drawn into a PDF on your own device. Your clients, prices and notes are never uploaded — there is no server to send them to and no database that could leak them. That is a property of the architecture, not a policy we could change quietly.
Tested against hand-computed figures
The money engine is covered by automated tests that check it against figures worked out by hand: the float trap, half-up rounding, line reconciliation across many price and quantity combinations, discount-before-tax ordering, VAT extraction, and the balance-due floor. The worked examples on this site are computed at build time by that same engine, so the prose cannot disagree with the tool. If you believe a figure is wrong, that is exactly the report we want — see the contact page.