Scenario → request fields
The calculation request is backward-compatible: a legacy hotel caller needs none of these. Each optional field unlocks a specific real-world scenario. This maps the field to the situation it's for.
Start from the legacy shape
A direct hotel booking needs only location, dates, nightly rate, currency, and (optionally) property type. Everything on this page is additive — omit a field and the calculation behaves exactly as it did before the field existed. Add a field and you opt into a more specific tax treatment. For the request and response anatomy, see Calculate tax (API).
Channel & merchant of record
| Field | Type | Description |
|---|---|---|
| merchant_of_record | "property" | "platform" | "none" | Who is the seller of record. property (agency model, e.g. an OTA that passes the booking to the hotel) surfaces who collects what via collection_info; platform (the OTA / marketplace is the merchant of record) routes all categories to the platform. Drives the booking's channel. See Channels & MoR. |
| is_marketplace | boolean | Marks the booking as marketplace-facilitated. Treated as platform-equivalent when resolving channel-scoped rates. |
| platform_type | string | An identifier for the booking platform / channel. Feeds channel resolution alongside merchant_of_record and is_marketplace. |
applies_to_channels, so the Mexico City split is illustrative of the mechanism, not the current data config.B2B, reverse charge & tax identity
| Field | Type | Description |
|---|---|---|
| customer_type | "consumer" | "business" | "government" | "diplomat" | "ngo" | "exempt_entity" | Who the guest is. business unlocks B2B treatment; government / diplomat / ngo / exempt_entity can trigger exemption rules where a jurisdiction provides them. |
| business_tax_id | string | The guest's VAT / tax ID (e.g. DE…). Combined with customer_type="business" the engine derives has_valid_vat_id and the cross-border flag is_cross_border_b2b. The room is never reverse-charged (it's taxed where the property is); reverse charge applies to the OTA commission line. See Reverse charge. |
| commission_supplier_country | string (ISO country) | The OTA / intermediary's own country. Gates commission-line reverse charge on the intermediary's cross-border status independent of the guest — so a US OTA acting as MoR for a German hotel reverse-charges its commission even for a non-EU consumer guest. Omitted → falls back to the guest-derived cross-border flag. |
| commission_withholding_country | string (ISO country) | The country whose income-tax withholding regime applies to the platform→property payout (e.g. India's TDS on e-commerce). Computed on the gross room subtotal and disclosed as total_withholding, but deliberately excluded from the guest bill, the e-invoice, the refund tax delta, and the liability report — it is a payout-side income-tax deduction, not a consumption tax. Pair with commission_withholding_treaty_rate to apply a treaty-reduced rate. Omitted → no withholding (legacy). |
| payment_method | "card" | "cash" | "bank_transfer" | "foreign_card" | "mobile_money" | "unknown" | How the booking was paid. Gates payment-conditioned exemptions where a jurisdiction provides them — e.g. the Argentina IVA refund, the Azerbaijan cashless-POS exemption, and the Uruguay foreign-card IVA-cero. Rules test it with in [list]. Defaults to unknown (no payment-gated rule fires). |
Pricing, inclusivity & currency
| Field | Type | Description |
|---|---|---|
| price_includes_tax | boolean | Set true when the nightly rate is tax-inclusive (EU consumer-law display, an inclusive OTA tax policy). The engine reverse-derives the base from the gross; the response always populates both subtotal_excluding_tax and subtotal_including_tax. See Inclusive pricing & currency. |
| settlement_currency | string (ISO 4217) | When the booking is priced in one currency but settled in another, the response adds amount_in_settlement_currency and settlement_fx_rate. The tax calculation itself stays in the booking currency. |
Tour operator margin scheme (TOMS)
| Field | Type | Description |
|---|---|---|
| margin_scheme | boolean | Opt into the EU Tour Operators' Margin Scheme (Article 306-310). When true, the destination room VAT is replaced by a single EN 16931 category-E line (VATEX-EU-306, with no VAT shown separately); the VAT on the margin is the operator's own liability, surfaced as total_margin_vat and not added to the guest bill. Supply bought_in_cost and operator_country alongside it (and optionally out_of_eu_cost_fraction for the part of the supply enjoyed outside the EU). Absent → standard destination room VAT (legacy). |
Property shape & supply type
| Field | Type | Description |
|---|---|---|
| para_hotelier | boolean | France only: a bare furnished rental is VAT-exempt; the 10% rate applies only to a para-hôtelier supply (≥3 of 4 services: breakfast, cleaning, linen, reception). For STR-class types, true → 10%, false → exempt, absent → legacy 10%. Hotel-class types always get 10% regardless. |
| property_postal_code | string (ZIP / postal) | Gates geofenced rules that apply only inside a postal boundary (e.g. the Chicago Tourism Improvement District). String match only — normalize ZIP+4 to the 5-digit prefix. Absent → the rule fails open to its pre-geofence behavior. |
| adults | integer | The number of chargeable adults for per-person taxes (FR taxe de séjour, etc.), so you can exclude minors with a coarse count: adults=2 on a 4-occupant booking charges per-person taxes for 2. Absent → every occupant is charged (legacy). For per-occupant precision, send guests[] instead. |
| guests[] | array of { age, type, nationality, disability_percentage } | Per-occupant details. When provided, each guest is evaluated in its own sub-context and charged at its own resulting rate (age band, residency, disability percentage, guest type), and the per-person amounts are summed — so an individually-exempt guest drops out of the total. age drives age-band rules; type is a canonical guest type (resident, disabled, diplomat, student, senior, …); nationality (ISO 3166-1 alpha-2) drives nationality-based rules; disability_percentage drives threshold exemptions. Sending guests[] overrides the scalar guest fields and the guest count. See Tiered & per-person rates. |
| property_zone_code | string | The property's sub-city tax-overlay zone, for cities whose lodging tax varies by a zone that is neither an admin boundary nor a clean postal set. Zone-specific rates gate on it by string match; when absent, those rules fall back to the city baseline (backward-compatible). Admin-boundary zones (e.g. the Venice islands) resolve from the address instead. |
| supplier_tax_regime | string | The host's / supplier's own tax regime, for statutes conditioned on the supplier's standing rather than the booking or guest — small-business and franchise schemes such as the French franchise en base, the German Kleinunternehmer rule, the Italian regime forfettario, the Peruvian MYPE regime, and the UK below-threshold rule. A VAT-exempt regime yields an EN 16931 category-E line with a stated exemption reason. Resolved from an explicit request value, then the supplier legal issuer, then the property default. Absent → standard treatment (backward-compatible). |
Rate & rule configuration (not request fields)
A few scenarios are driven by how a rate or rule is configured in the data rather than by a field on your request. You don't send these; they shape how the matching rate behaves. They're listed here so the full picture is in one place.
| Field | Type | Description |
|---|---|---|
| collection_model | rate config | On a rate, marks it platform-collected vs property-collected. Used by marketplace-facilitator scenarios (e.g. a city-level rate is platform-collected while the state-level rate stays property-collected). |
| applies_to_channels | rate config (array) | Scopes a rate to ['direct'] / ['platform'] / ['marketplace']. The engine fires the rate only for the booking's resolved channel; NULL means all channels. This is the channel-mutex primitive. |
| target_jurisdiction_codes | rule config (array) | On a jurisdiction-wide rule (no bound rate), fans the rule out to descendant jurisdictions by code — so a statewide long-stay exemption reaches every city under it without per-city replication. |
collection_model and applies_to_channels then decide which configured rate that channel selects. See Channels & merchant of record for the end-to-end picture and the OTA guide for worked multi-channel examples.