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.

Policy request · fictional address, no coverage claim
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.

Quote request · illustrative inputs, not a tax result
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.

Synthetic ZZ exact-cent request · no real policy, address or default qualification
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.