
A bill is arithmetic, and arithmetic on money is rarely exact. Thirty-one days into a thirty-day rate. A discount of 22% on $18.00. Fifty thousand messages billed in blocks of a thousand when you sent fifty thousand and one. Every one of those has a fraction, and somebody absorbs it.
Most billing systems decide that case by case, usually by whichever way the language rounds by default. Ours decided once: the fraction goes to the customer, every time, without needing a reason.
Why it is a rule and not a judgement
The alternative is a policy that says "round fairly", which in practice means each developer decides at the moment they write the line — and their decision is invisible, because a rounding is one character. Math.floor and Math.ceil differ by a penny and by an entire posture, and code review does not reliably catch the difference.
A fixed direction is checkable. Anyone can read a money function and see whether it rounds the way the rule says, without knowing what the number means.
Where it actually applies
| Situation | What is not exact | Which way we go |
|---|---|---|
| A discount on a line | 22% of $18.00 is $3.96 | Round the discount up |
| A refund for unused days | 25 of 30 days of $54.00 | Round the refund up |
| Days in a period | 30.5 days in the month | Round the period down, so a day is worth more |
| A part day | 10 minutes remaining | Count it as a whole unused day |
| Metered blocks | 50,001 messages in blocks of 1,000 | Charge the whole blocks used, floor the remainder |
Note that the direction is not always "up". It is always *toward the customer*, which for a discount means up and for the divisor in a daily rate means down. Stating it as "always round up" would get half of these wrong.
And before any of that: no floats
Every amount in the system is an integer in the currency’s minor unit. $18.00 is 1800. Nothing is ever a floating-point number, at any point, in any layer — not in the database, not in the API, not on the way to a page.
0.1 + 0.2 === 0.30000000000000004
That is not a curiosity. It is a line on an invoice
that does not add up, and a customer who is right.A currency’s minor unit is not always two decimal places either — the yen has none, the dinar has three — so the exponent comes from the currency rather than from an assumption that everything is cents.
The corollary: never show a number we cannot stand behind
The same rule has a second half that costs us more than the pennies do: if we cannot compute a figure honestly, we do not display one.
Our usage page shows last month’s metered charge and, for the month in progress, a statement that it is being counted — not a running estimate. A part-month priced now and re-priced at close would bill its first days twice, so the honest thing to say is that the meter is running.
None of this is expensive. Across a year of invoices these decisions add up to a rounding error, which is the point: it costs almost nothing, and it means nobody ever has to check our arithmetic to know it was not tilted.
Every price, in public
Per unit, per month, with the edges named. Including the ones that are awkward to explain.
See the pricing