API v2 / schema 2.0.0
Tourist tax policies and quotes
POST /v2/resolve ·
defaults:resolve · schema 2.0.0
Start with the property's saved address.
Your server supplies countryCode, mode and
address: {countryCode, street, city, state, postalCode}.
State and postal code may be empty strings. Matching uses published
official address records, Unicode NFC and outer-whitespace trimming only.
Case, accents, punctuation and house-number suffixes remain significant.
There is no fuzzy, postcode-only or coordinate fallback.
curl 'https://api.touristtaxtools.com/v2/resolve' \
-H "Authorization: Bearer $TOURISTTAXTOOLS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{
"countryCode": "DE",
"mode": "policy",
"address": {
"countryCode": "DE",
"street": "Example Street 1",
"city": "Example Town",
"state": "",
"postalCode": ""
},
"property": {
"accommodationType": "hotel"
}
}'
mode: "policy" reviews the exact location and its complete
local tax scope. policy_ready identifies qualified policies;
its quote is null. Inspect requiredInputs,
missingInputs, evidence and effective dates before recording
an explicit property-level approval. Missing qualified coverage remains
unavailable even when the country has published reference rules.
Provide actual stay inputs.
For mode: "quote", supply the accommodation type, required
facts and stay. Check-in and exclusive checkout use local
YYYY-MM-DD calendar dates. nights must cover every night
exactly once, with its actual EUR net accommodation amount as a decimal
string. Do not divide an arbitrary booking total across nights or include
services and taxes excluded by the policy.
curl 'https://api.touristtaxtools.com/v2/resolve' \
-H "Authorization: Bearer $TOURISTTAXTOOLS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{
"countryCode": "DE",
"mode": "quote",
"address": {
"countryCode": "DE",
"street": "Example Street 1",
"city": "Example Town",
"state": "",
"postalCode": ""
},
"property": {
"accommodationType": "hotel"
},
"facts": {
"paidAccommodation": true,
"platformCollected": false,
"passThroughChosen": true
},
"stay": {
"checkIn": "2026-11-02",
"checkOut": "2026-11-04",
"agreementOn": "2026-10-26",
"nights": [
{
"date": "2026-11-02",
"netAmount": "100.00"
},
{
"date": "2026-11-03",
"netAmount": "120.00"
}
]
},
"inputEvidence": {
"source": "operator_confirmation",
"reference": "illustrative-confirmation-reference",
"recordedAt": "2026-10-26T12:00:00Z"
}
}'
Facts are true, false or null for
unknown. Charging requires confirmed paid accommodation, no prior platform
collection and the operator's choice to pass the levy through to the
guest. A policy can require further facts, such as a source-defined
exemption assessment. When required,
originalContractUnderSixMonths concerns the original legally
binding availability agreement; actual checkout or early departure cannot
establish it. The example does not supply every possible policy input.
inputEvidence identifies your actual recorded confirmation,
booking record or property record and its timestamp. Obtain this from an
authorized server workflow. The API preserves your attestation; it does
not independently verify the underlying guest record.
Use the response state.
| State | Meaning |
|---|---|
unknown |
No published artifact or exact official address match. |
ambiguous |
Conflicting exact official address identities. |
stale |
Source, publication or location validity needs refreshing. |
unsupported |
Incomplete tax scope, a condition mismatch or an unsupported calculation. |
needs_input |
Required stay facts or financial inputs are missing. |
policy_ready |
A qualified policy is available for review; no quote is returned. |
resolved |
Complete supported inputs produce a quote for all applicable policies in the qualified scope. |
Only resolved contains a quote. Keep snapshotId,
countrySnapshotSha256, artifactSha256, location
proof, policy revisions and the quote with the approved transaction.
Recheck current evidence when committing a new charge. Never use a failed
or unavailable result to overwrite manual taxes or recalculate historical
reservations.
Keep levy and VAT treatment distinct.
Existing half-up policies use net-percentage.v1 in EUR, with
source-qualified rounding per night or per stay. Their requests and
arithmetic are unchanged. Fixed, gross, stepped, age-band, seasonal,
refund and alternative calculations are unsupported. Minor-unit amounts
are integer strings. netMinor is the net accommodation base;
taxMinor is the tourist levy; totalMinor is
their sum, excluding VAT.
Exact cents require an explicit transaction.
A separately qualified policy may select
calculation.rounding: "exact_integral_minor_unit". This is
not a statutory rounding convention. It produces
net-percentage.exact-integral-minor-unit.v1 only when each
applicable levy is an integral number of minor units using exact decimal
arithmetic. One fractional levy refuses the entire quote; no levy is
dropped, rounded or replaced with zero. An illustrative 80.00 EUR base at
7.5% has 600 cents principal and 8600 cents net plus levy, before VAT. A
0.01 or 0.20 EUR base refuses. An integral 0.40 EUR aggregate of two
people or two supplies is also unsupported.
Supply transaction with supplyId,
night, accommodatedPersonCount,
accommodationSupplyCount and nightCount. Exactly
one accommodated person, one directly contracted, separately priced
accommodation supply and one complete night are supported. Explicitly
assess completeNight, directlyContracted,
separatelyPriced, considerationComplete and
depositReconciled. All must be true. A payer, room name,
invoice row, one-night checkout or arithmetic sum cannot establish these
facts or the original-contract duration.
The complete components list has at most twelve records, each
with a unique bounded id, kind, decimal string
amount, matching supplyId/night and
allocation. Exactly one accommodation_net and
all taxable_direct_ancillary_net amounts must reconcile
exactly to the supplied nightly net base. A 0.40 EUR room plus a taxable
0.01 EUR cleaning price cannot omit that cent to obtain a 3-cent quote.
vat, own_tourist_levy,
excluded_service and deposit_payment are
retained but do not increase the base. Reconcile deposits as payments
against the price, without counting them again as consideration. Only
direct allocation is supported; shared,
one_off, indirect, negative prices, conflicting
identities and unexplained differences refuse.
Missing or null answers and an unknown classification yield
needs_input with precise field names; known incomplete or
unsupported cases yield unsupported. Both have
quote: null. Malformed or unexpected fields fail validation.
Keep every typed input, component and actual inputEvidence
provenance in the transaction fingerprint and frozen review. These are
caller attestations, not independent proof of source taxability or legal
scope. Exact address, epoch, currentness, full ordinary and special
authority scope, all cumulative policies and required purpose/agreement
facts remain mandatory.
curl 'https://api.touristtaxtools.com/v2/resolve' \
-H "Authorization: Bearer $TOURISTTAXTOOLS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{
"countryCode": "ZZ",
"mode": "quote",
"address": {
"countryCode": "ZZ",
"street": "1 Synthetic Street",
"city": "Synthetic city",
"state": "",
"postalCode": ""
},
"property": {
"accommodationType": "hotel"
},
"facts": {
"paidAccommodation": true,
"platformCollected": false,
"passThroughChosen": true,
"originalContractUnderSixMonths": true
},
"stay": {
"checkIn": "2026-11-02",
"checkOut": "2026-11-03",
"agreementOn": "2026-10-26",
"nights": [
{
"date": "2026-11-02",
"netAmount": "80.00"
}
]
},
"transaction": {
"supplyId": "synthetic-direct-supply-1",
"night": "2026-11-02",
"accommodatedPersonCount": 1,
"accommodationSupplyCount": 1,
"nightCount": 1,
"completeNight": true,
"directlyContracted": true,
"separatelyPriced": true,
"considerationComplete": true,
"depositReconciled": true,
"components": [
{
"id": "synthetic-price-record-1",
"kind": "accommodation_net",
"amount": "80.00",
"supplyId": "synthetic-direct-supply-1",
"night": "2026-11-02",
"allocation": "direct"
}
]
},
"inputEvidence": {
"source": "operator_confirmation",
"reference": "synthetic-confirmation-only",
"recordedAt": "2026-10-26T12:00:00Z"
}
}'
Each policy's taxTreatment.passedThroughVatBase is
accommodation or unknown. The former establishes
that the passed-through levy enters the accommodation VAT base; it does
not select a VAT rate or establish the business's registration, exemption
or price mode. Unknown treatment cannot authorize a financial charge.
Apply a separately reviewed tenant treatment through your tax engine and
calculate VAT once. A levy quote is not the final booking total.
The endpoint uses the same developer-key country restrictions and quotas as v1. Requests are limited to 32 KiB and responses to 2 MiB. The anonymous website proxy does not expose v2.
Download the request schema, response schema, policy schema and location-proof schema, or use the OpenAPI contract.