Resolve a place
Name a place by jurisdiction id or LAU code, and get the charges in force there on a date, with their rates, exemptions and evidence.
resolve(release, place, on) says which charges apply to a place on a date and what their rates are. It takes no stay and no money: use it to show a hotel its taxes, or to check a place before you quote.
import { resolve } from "./calculator";
const answer = resolve(
release,
{ lau: { country: "es", code: "08019", year: 2024 }, type: "hotel", class: "4" },
"2026-11-12",
);quote takes the same place, so everything on this page about places holds for quotes too.
The place
A place has one of two forms.
By jurisdiction id
| Field | Type | Meaning |
|---|---|---|
jurisdiction | string | A jurisdiction id from the country file, such as es.barcelona. Its first two letters are the country. |
type | string, optional | The property type, from the place's classification, such as hotel. |
class | string, optional | The property class within that type, such as 4. |
By LAU code
LAU codes are Eurostat's codes for local administrative units, roughly one per municipality. Use them when your own data already has them.
| Field | Type | Meaning |
|---|---|---|
lau.country | string | The country id, such as es. |
lau.code | string | The LAU code, such as 08019 for Barcelona. Up to 20 letters, digits, dots, underscores or hyphens. |
lau.year | integer | The LAU edition the code is from. It must be the country's LAU year, which the manifest gives per country as lauYear: 2024 in every country today. |
within | string, optional | A jurisdiction id the place is in. See Codes the release doesn't list. |
type, class | string, optional | As above. |
Type and class
Some rates depend on the kind of property. The most local jurisdiction in the place's chain that has a classification sets the types and classes the place can take. A type or class it doesn't have throws type_not_in_classification or class_not_in_classification.
Leaving them out is not an error. A charge whose rate depends on them comes back as an unknown, type_unknown or class_unknown, and the rest is still answered.
Codes the release doesn't list
A country file lists its municipalities with their LAU codes. A listed code gives that municipality, and within, if given, must be in its chain.
An unlisted code is a municipality the release has nothing on. The calculator places it at within when you give one, which must then be a country or a region, or at the country otherwise. Charges levied by the country or that region still apply. Each level that levies charges in the country and has nothing researched in the chain comes back as a jurisdiction_not_researched unknown. Madrid, 28079, is unlisted today; Coverage and unknowns shows its quote.
The answer
Top level
| Field | Meaning |
|---|---|
release | The id of the release the answer comes from. |
on | The date asked about. |
place.jurisdictions | The place's chain, from the country down: regions, any associations that hold the municipality, the municipality, a zone. |
place.type, place.class | The type and class, when the request gave them. |
charges | The charge versions in force on on, ordered by charge id. |
upcoming | The versions that come into force after on, ordered by charge id, then date. |
unknowns | What the release can't say for this place on that date. See Coverage and unknowns. |
A charge
| Field | Meaning |
|---|---|
charge, version | The charge id and the version: the date it came into force. |
kind, name, nameEn | As on a quote line. |
validFrom, validTo | The dates the version is in force. No validTo means no end date is known. |
rates | The rates that match the place, each with its amount, its exemptions and, when it holds only part of the year, its season. |
inPrice | Whether the law counts the charge as part of the room price. |
vatOnChargeBps | VAT on the charge itself, in basis points, where the law puts VAT on it. |
rounding | How the law rounds the charge, where it says. |
payer, collectedBy | As on a quote line. |
evidence | The ids of the sources behind the version and its rates. |
amount.basis says how the rate is levied: person_night with amountMinor, for example, is an amount per liable guest per night. A rate the release has found but can't price has the basis unpriced, and the answer lists it in unknowns as unpriced_rule.
Barcelona, by LAU code
The request at the top of this page. The answer, trimmed: the first charge is cut and upcoming is shortened to each version's charge, start and end date.
{
"release": "2026-10-11",
"on": "2026-11-12",
"place": {
"jurisdictions": ["es", "es.catalunya", "es.barcelona"],
"type": "hotel",
"class": "4"
},
"charges": [
{
"charge": "es.catalunya.tourist-tax",
"version": "2026-04-01",
"kind": "city_tax",
"name": "Impost sobre les estades en establiments turístics",
"nameEn": "Tax on stays in tourist establishments",
"validFrom": "2026-04-01",
"validTo": "2027-03-31",
"rates": [
{
"amount": { "basis": "person_night", "amountMinor": 340 },
"exemptions": [
{
"id": "aged_16_or_under",
"kind": "age_band",
"maxAge": 16,
"factorBps": 0,
"evidence": ["ev_ac687c6c38ae608e"]
},
{
"id": "after_7_nights",
"kind": "night_cap",
"limit": { "nights": 7 },
"scope": "stay",
"factorBps": 0,
"evidence": ["ev_67e0918d37a6bdb0", "ev_e79e909f95bd4a78"]
}
]
}
],
"inPrice": false,
"payer": "guest",
"collectedBy": ["operator"],
"evidence": ["ev_3e52b0f296a9686f", "ev_8616466e3a257bc8", "ev_0b8eb3499237089f", "ev_c873a3f06bb483bd"]
}
],
"upcoming": [
["es.catalunya.municipal-surcharge", "2027-04-01", "2028-03-31"],
["es.catalunya.municipal-surcharge", "2028-04-01", "2029-03-31"],
["es.catalunya.municipal-surcharge", "2029-04-01", null],
["es.catalunya.tourist-tax", "2027-04-01", null]
],
"unknowns": []
}The first charge, cut above, is Barcelona's municipal surcharge, es.catalunya.municipal-surcharge: €5.00 a person a night, with the same two exemptions. In the real answer each upcoming entry is a full charge, like those in charges.
Errors
resolve throws a TaxDataError as quote does, with a code and a pointer:
| Code | Meaning |
|---|---|
request_invalid | The place or the date doesn't match the schema. |
country_unknown | The place's country isn't in the loaded release. |
jurisdiction_unknown | No such jurisdiction in the country, for jurisdiction or for within. |
lau_year_mismatch | lau.year isn't the country's LAU year. |
place_within_mismatch | within is in another country, isn't in the place's chain, or, for an unlisted code, isn't a country or region. |
type_not_in_classification | The type isn't one the place's classification has. |
class_not_in_classification | The class isn't one the place's classification has for that type. |
A LAU year of 2021 for a Spanish code, for example, throws lau_year_mismatch at /place/lau/year.
Quote a stay
The quote request and every field of the answer, from lines, nights and evidence to unknowns, totals and assumptions, in integer minor units.
Releases and signatures
Release ids, what a release holds, the signed manifest, checking its Ed25519 signature and file hashes, and running the conformance vectors.