Layered & additive stacking
This is the single most important idea in TaxLens. Every accommodation tax is modeled as its own single-jurisdiction layer, every matching layer fires independently, and their amounts sum. There is no stored 'combined rate' anywhere — and that is by design.
The principle
A stay in a real city is taxed by several authorities at once. In Fort Worth, Texas the state levies a hotel occupancy tax, the city levies its own, and a convention-center district levies a third. Each authority sets its rate independently and remits to itself. TaxLens mirrors that reality exactly: each authority's tax is a separate row, and the engine fires every row that matches and adds the results.
This is the industry-standard layered tax model. It keeps each authority's liability attributable on its own line, which is what per-jurisdiction remittance reporting and invoice reconciliation both depend on.
Author every layer as its own rate
The corollary is a hard authoring rule: never store a combined total. The Texas 6% and the Fort Worth 9% are two rows, at two nodes — not a single "15%" parked on the city. The same goes everywhere:
- US state lodging tax + city occupancy tax → two rows.
- Canadian provincial sales tax + municipal accommodation tax → two rows.
- Japan prefecture tax + village tax → two rows.
- Barcelona's regional Catalan IEET + municipal recargo → two rows.
Why it matters beyond tidiness: when one authority changes its rate — a state raises HOT by a point — exactly one row updates, and every city beneath it reflects the change automatically. A combined-total scheme would force a manual edit to every descendant and quietly drift out of date.
See the layers fire
Resolve the raw layers in force on a chain, then run a real calculation and watch each one appear as its own component in tax_breakdown.components, tagged with the node it came from.
The active layers on the Fort Worth chain — each row is its own standalone layer at its own node (the live data may carry a city layer as a single combined row rather than the split shown in the diagram above).
Sign in to run this against the live API. Read-only — nothing is saved.
One calculation — every matching layer fires independently and the components carry their own jurisdiction_code.
{
"jurisdiction_code": "US-TX-FTW",
"stay_date": "2026-07-01",
"nights": 2,
"nightly_rate": 500,
"currency": "USD",
"property_type": "hotel"
}Sign in to run this against the live API. Read-only — nothing is saved.
There is no aggregate rate field you have to trust blindly: the total is just the sum of the components, and each component names its authority. See the request shape in detail in Tax categories and the full response in How a calculation works.
Replacement, expressed as exemption rules
Sometimes the law isn't additive — a special zone replaces the national rate rather than adding to it. TaxLens does not model this with a special "replacement rate". The engine is structurally additive; replacement is expressed as an exemption rule attached to the ancestor rate, scoped by jurisdiction code.
Take Tierra del Fuego (AR-TF), a special customs and tax regime in Argentina. Rather than authoring a 0% VAT rate at AR-TF, we leave Argentina's national IVA rate intact and hang an exemption rule on it that fires only for descendants of AR-TF:
{
"rule_type": "exemption",
"conditions": {
"operator": "AND",
"rules": [
{ "field": "jurisdiction_code", "op": "starts_with", "value": "AR-TF" }
]
},
"action": { "type": "exempt" },
"legal_reference": "Ley 19.640 — Special Customs and Tax Regime for Tierra del Fuego"
}For an AR-TF stay the rule fires, the national VAT is waived, and the response still shows that VAT component — flagged as exempted by the rule, with its legal basis attached. For any other Argentine stay the rule's condition fails and VAT applies normally. The same pattern handles the EU VAT cascade: France's mainland VAT carries an exemption scoped to French Guiana (FR-GF, the DOM-TOM code the rule matches — the same rule also covers the other overseas codes FR-GP / FR-MQ / FR-RE / FR-YT and the Pacific COM codes), and Greece's national accommodation VAT carries one scoped to the qualifying small Aegean islands, each paired with the local reduced rate that fires in its place.
Where to go next
Layers can be different kinds of tax that compute differently — see Tax categories. Some layers even fold another layer into their base — see VAT base composition. And rules decide which layers fire for a given booking — see Rules.