Calculate tax

POST /v1/tax/calculate is the core of TaxLens. Give it where the stay is and what the stay is; get back an itemized, stacked tax breakdown.

What it does

The engine resolves the jurisdiction, walks its ancestor chain (country → region → city), collects every active rate that matches your booking and stay date, evaluates the rules bound to those rates (exemptions, overrides, caps, surcharges, reductions), and returns one component per surviving tax plus a total. The calculation is read-only and saves nothing — to persist it, see Bookings API. For the conceptual walk-through, read How a calculation works and Additive stacking.

Locating the stay

Provide either a jurisdiction_code or a lat/lng pair. With coordinates, the geocoder resolves the matching jurisdiction for you. If you only have a street address, run it through address validation first and feed the resulting code back in.

FieldTypeDescription
jurisdiction_codestringTaxLens jurisdiction code (e.g. US-NY-NYC, ES-CT-BCN, HR-19-DBV). Optional when lat+lng are supplied.
lat / lngfloatLatitude and longitude. Provide the pair instead of jurisdiction_code to auto-resolve via the geocoder.

Describing the stay

These fields define what is being taxed. stay_date, nightly_rate, currency, and nights are required; everything else refines which rules fire.

FieldTypeDescription
stay_daterequireddateCheck-in date (YYYY-MM-DD). Rates and rules are time-aware — the engine uses what's in force on this date.
nightsrequiredintegerNumber of nights (≥ 1). Drives per-night taxes and night caps.
nightly_raterequireddecimalRoom rate per night, > 0. Overridden when nightly_rates[] (a per-night schedule) is provided.
currencyrequiredstringISO 4217 code (USD, EUR, JPY …).
checkout_datedateOptional; when supplied it must equal stay_date + nights, else 422.
number_of_guestsintegerGuest count (default 1). Multiplies per-person taxes. Use adults to exclude minors from per-person levies.
property_typestringLodging product type — hotel, vacation_rental, str, apartment_hotel, hostel, etc. (default hotel). Inputs are normalized before rule matching.
star_ratinginteger1–5. Used by star-tiered rates (e.g. Florence, Milan, Dubai).
guests[]listPer-guest detail ({ nationality, age, residency_status, exempt_entity_type }). Overrides the scalar guest_age / guest_nationality / number_of_guests for mixed-guest exemptions.
line_items[]listItemized extras (resort_fee, cleaning_fee, commission …) taxed by their own category. Room line items are ignored — nightly_rate × nights is the canonical room base.
Detail
The full multi-actor field set — merchant_of_record, customer_type / business_tax_id for B2B reverse charge, price_includes_tax, settlement_currency, geofencing and para-hôtelier flags — is documented field-by-field in Scenario fields. They are all backward compatible: a legacy request without them returns identical output.

The request in code

curl -X POST https://api.taxlens.getdynamiq.ai/v1/tax/calculate \
  -H "X-API-Key: $TAXLENS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jurisdiction_code": "ES-CT-BCN",
    "stay_date": "2026-06-15",
    "checkout_date": "2026-06-17",
    "nightly_rate": 180,
    "currency": "EUR",
    "nights": 2,
    "number_of_guests": 2,
    "property_type": "hotel",
    "star_rating": 4
  }'

Reading the response

The response is an itemized breakdown. The fields you'll use most:

FieldTypeDescription
tax_breakdown.components[]listOne entry per tax that fired: name, category_code, jurisdiction_code, jurisdiction_level, rate, rate_type, taxable_amount, and tax_amount. An exempted component carries is_exempt and exemption_reason.
tax_breakdown.total_taxdecimalSum of all component tax amounts, in the booking currency.
tax_breakdown.effective_ratedecimaltotal_tax over the room subtotal (nightly rate × nights) — a single headline rate.
total_with_taxdecimalSubtotal plus total_tax — what the guest pays.
rules_applied[]listA trace of every rule evaluated, each with its result: applied, exempted, skipped. Your audit of why the number is what it is.
collection_infoobjectWho remits each component (property vs platform), the taxable base, and per-component MoR splits. Driven by merchant_of_record / is_marketplace. See Channels & MoR.
{
  "calculation_id": "calc_c484953024e7b4e04f7e9b05ba1ca866",
  "jurisdiction": { "code": "ES-CT-BCN", "name": "Barcelona", "path": "ES.CT.BCN" },
  "tax_breakdown": {
    "components": [
      {
        "name": "Occupancy Tax (flat per person per night)",
        "category_code": "occ_flat_person_night",
        "jurisdiction_code": "ES-CT-BCN",
        "jurisdiction_level": "city",
        "rate_type": "flat",
        "taxable_amount": "360",
        "tax_amount": "20.00"
      },
      {
        "name": "Tourism Tax (flat per person per night)",
        "category_code": "tourism_flat_person_night",
        "jurisdiction_code": "ES-CT-BCN",
        "jurisdiction_level": "city",
        "rate_type": "tiered",
        "taxable_amount": "360",
        "tax_amount": "13.60"
      },
      {
        "name": "VAT / Sales Tax (reduced rate)",
        "category_code": "vat_reduced",
        "jurisdiction_code": "ES",
        "jurisdiction_level": "country",
        "rate": 0.1,
        "rate_type": "percentage",
        "taxable_amount": "393.60",
        "tax_amount": "39.36"
      }
    ],
    "total_tax": "72.96",
    "effective_rate": "0.2026666666666666666666666667",
    "currency": "EUR",
    "subtotal_excluding_tax": "360",
    "subtotal_including_tax": "432.96"
  },
  "total_with_tax": "432.96",
  "rules_applied": [
    { "rule_id": 1361, "name": "Barcelona IEET — 7-night cap per continuous stay",
      "rule_type": "cap", "result": "applied" }
  ],
  "collection_info": {
    "who_collects": "property",
    "taxable_base": "room_rate",
    "platform_must_collect": false,
    "property_collected_components": ["vat_reduced", "occ_flat_person_night", "tourism_flat_person_night"]
  }
}
Detail
The VAT line's taxable_amount (393.60) is larger than the room subtotal (360) on purpose: Spain folds the operator-levied occupancy and tourism taxes into the VAT base, so 10% VAT is charged on room + those taxes (360 + 20.00 + 13.60). Whether a tourist tax sits inside or outside the VAT base is per-jurisdiction — VAT base composition has the full picture.

Try it live

This runs the real engine against your session and active organization. Read-only — nothing is saved. Edit the body and run it again.

POST/v1/tax/calculate
Sign in to run

A 2-night, 4-star Barcelona hotel stay for two guests.

Request body
{
  "jurisdiction_code": "ES-CT-BCN",
  "stay_date": "2026-06-15",
  "checkout_date": "2026-06-17",
  "nightly_rate": 180,
  "currency": "EUR",
  "nights": 2,
  "number_of_guests": 2,
  "property_type": "hotel",
  "star_rating": 4
}

Sign in to run this against the live API. Read-only — nothing is saved.

Tip
Comparing or bulk-processing many stays? Use the batch endpoint to send an array of these requests in one call — see Batch & address validation.