Rate breakdown
Rate breakdown
A US rooftop rate is not one number, it is a stack: Kansas City's 9.125% is the state's 6.5%, plus Wyandotte County's 1%, plus the city's 1.625%. Charging the combined figure is only half the obligation — the seller then remits to each authority separately, and a return needs to know how much of the tax belongs to whom.
That split is knowable only where the rate is stacked. Once the percentages are
summed the information is gone, and no consumer can recover it from the total.
So the source keeps it: a stacked rate carries its
RateComponents, and the engine turns them into a
TaxBreakdown on the assessment.
Reading a breakdown
$assessment = $tax->assess($query);
foreach ($assessment->breakdown?->lines ?? [] as $line) {
printf(
"%-16s %6s%% %s\n",
$line->label(), // "209", "ALAMEDA", or the level when unnamed
$line->percentage, // 1.625
$line->tax->getAmount()
);
}
state 6.5% 6.50
209 1% 1.00
36000 1.625% 1.63
TaxBreakdown also answers the two questions a filing asks:
$assessment->breakdown->total(); // === $assessment->tax
$assessment->breakdown->atLevel(JurisdictionLevel::State); // the state line(s)
The parts sum to the whole
total() equals the assessment's tax exactly, and that is a guarantee, not a
coincidence. The engine allocates the real total across the components rather than
applying each authority's rate to the net on its own.
The difference is not academic. On a $1.00 supply in Kansas City:
| State 6.5% | County 1% | City 1.625% | Sum | |
|---|---|---|---|---|
| Rate applied per authority | 0.07 | 0.01 | 0.02 | 0.10 |
| Allocated from the real total | 0.06 | 0.01 | 0.02 | 0.09 |
The tax actually charged was $0.09. Recomputing per authority invents a cent that was never collected, and a return built from those lines does not reconcile with the invoices behind it.
The remainder goes to the largest fractional shares (the Hamilton method), not to whichever authority the source happened to list first — list order is an implementation detail of the source, not a statement about who is owed the odd cent, and an authority levying 0% must never receive one.
When there is no breakdown
breakdown is null whenever the split is not known, and null means unknown.
A consumer filing per jurisdiction must treat it as missing data — never as "one
authority takes all of it".
It is null when:
- the rate source did not decompose the rate (a flat national rate, a static table, a point-in-polygon service returning one all-in figure);
- the supply was not taxed — reverse-charged, exempt, not-registered, zero-rated;
- a buyer exemption overrode the regime's verdict.
What a source emits
A TaxRateSource populates TaxRate::$components when — and only when — it knows
the split. The components must sum to the rate; a TaxRate whose components do
not reconcile throws RateComponentsDoNotReconcile at construction.
That is deliberately strict. A breakdown that is slightly wrong is worse than none at all: it has exactly the shape of an authoritative split, so it gets remitted on, and the shortfall surfaces at audit rather than at calculation. A source that cannot decompose a rate supplies no components.
new TaxRate('9.125', RateKind::Standard, 'us-tax-data', components: [
new RateComponent(JurisdictionLevel::State, '6.5'),
new RateComponent(JurisdictionLevel::County, '1', '209'),
new RateComponent(JurisdictionLevel::City, '1.625', '36000'),
]);
code and name are provenance, never invention — a source with no published
name for an authority leaves them null rather than deriving a plausible label.
What the shipped US source emits
UsTaxDatasetRateSource decomposes by the
state's rate basis:
| Rate basis | Example | Components |
|---|---|---|
| Component | KS, NC, TX | The state share plus one line per authority the boundary index matched |
| Combined | CA | Two lines: the state share, and the aggregate local remainder |
| — (state-only rate) | any state, no rooftop | None — the state share is the absence of a stack, not a stack of one |
| — (reduced category) | MO grocery | None — a product rule, not a stack of authorities |
A combined-basis record (California's CDTFA place rates) publishes one figure that
already contains the state share, so the per-authority split is not available in
the data. Subtracting the known state share still yields the state/local split that
drives remittance, so it is reported — but the remainder is levelled local, not
city, because it aggregates every district taxing that address. Attributing it to
the named city would put other authorities' money on the city's line.
Known limitation: one taxable base
Every line reports taxableAmount as the supply's full net, because the engine
applies a single taxable base across the stack.
That is correct for the states modelled today, but it would not be for a state that exempts a category at the state level while its localities still tax it — Illinois and Missouri both do this for groceries. Supporting that needs a per-level taxability seam, which does not exist yet, so a per-level base is deliberately not claimed here.