Tiered & per-person rates
Tourist taxes are rarely a single flat number. They step up by hotel class or nightly price, and they multiply by guests and nights. This page covers tiered rates and per-person/per-night taxes — including the coarse lever for excluding minors and the precise per-guest path that charges each occupant at its own rate.
Tiered rates
A tiered rate's amount depends on a band — most often the hotel star rating or property class, sometimes the nightly price. A 5★ hotel pays more per person per night than a 2★ one. Tiers are stored on the rate itself; the engine picks the band the booking falls into.
The rate carries a tier_type discriminator that selects the banding logic — one of:
| Field | Type | Description |
|---|---|---|
| property_class | tier_type | A flat amount keyed by property type / class (and optionally star rating). The dominant live shape. |
| single_amount | tier_type | A flat amount for everything in the matched band, banded by star rating or nightly price. |
| threshold | tier_type | The rate changes entirely above a threshold — the band the nightly rate clears wins. |
| marginal_rate | tier_type | A rate applied only to the portion of the base within each band (marginal, like income-tax brackets) — for price-tiered percentage taxes. Supported but rare in the live data. |
Within a tier_type, each individual tier is a small object. The fields the engine reads are value (the flat amount) or rate (the percentage), min / max for the band bounds, and star_rating / property_class for the band key.
Tiering by star rating is the Barcelona pattern: the regional Catalan tax and the municipal recargo both step by hotel class, so a 5★ stay draws the top band of each. Pass star_rating (or property_classification) so the engine can land on the right tier.
Per-person, per-night
A large class of tourist taxes is a flat cash amount charged per guest per night. The category codes carry the basis right in the name — tourism_flat_person_night, occ_flat_person_night, eco_flat_person_night. The engine multiplies the per-unit amount by the chargeable guests and the number of nights.
amount = per_unit × chargeable_guests × nights
e.g. €4.50 × 2 guests × 3 nights = €27.00Adults vs. number_of_guests — the minors lever
Many per-person taxes exempt children. By default the engine charges every occupant: it multiplies by number_of_guests. To exclude minors, pass adults — the chargeable count becomes adults when set, falling back to number_of_guests when it isn't.
| Field | Type | Description |
|---|---|---|
| number_of_guests | number | Total occupants. Used as the chargeable count when adults is absent (legacy behaviour — everyone charged). |
| adults | number | The chargeable count for per-person taxes when set. A 4-occupant booking with adults: 2 is charged for 2 — the surgical lever for the common minors-exempt case. |
So a family of four (two adults, two children under the local exemption age) booking a per-person tourist tax should send number_of_guests: 4 and adults: 2 — the tax then lands on two people, not four.
A 5★ Barcelona stay: the tiered per-person tourist tax lands on the top band and charges 2 adults, not 4 occupants.
{
"jurisdiction_code": "ES-CT-BCN",
"stay_date": "2026-07-01",
"nights": 3,
"nightly_rate": 200,
"currency": "EUR",
"property_type": "hotel",
"star_rating": 5,
"number_of_guests": 4,
"adults": 2
}Sign in to run this against the live API. Read-only — nothing is saved.
Per-guest evaluation — the precise path
When you know each occupant, send the guests[] array instead of (or alongside) the counts. Each guest is evaluated in its own sub-context and charged at its own resulting rate — by age band, residency, disability percentage, or guest type — and the per-person amounts are summed across the party. An individually-exempt guest (a child under the exemption age, a certified-disabled guest, a resident) simply contributes zero and drops out of the total, rather than being approximated by a count.
| Field | Type | Description |
|---|---|---|
| guests[].age | number | The guest's age, for age-band exemptions and reductions (e.g. children under a local exemption age, senior rates). |
| guests[].type | string | The guest's type from the canonical vocabulary — resident, disabled, diplomat, student, senior, and so on. Caller-attested; the property verifies eligibility at check-in. |
| guests[].disability_percentage | number | Certified disability percentage, for threshold exemptions and reductions (e.g. exempt above a stated percentage). |
adults when you only know how many occupants are chargeable — it changes the chargeable count for the common minors-exempt case. Use guests[] when you know each occupant and need them charged at their own rate (different age bands, residency, or disability thresholds within one party). Sending guests[] overrides the scalar guest fields and the guest count.What isn't modeled
Where to go next
The category vocabulary (which codes are per-person, per-night, tiered) is in Tax categories. When a per-person tourist tax folds into the VAT base, see VAT base composition. And exemptions or caps on a tiered tax are Rules.