> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gridbeds.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Prices and fees

> A price for every party: prices by occupancy, children by age band and infants, the fees, the tourist tax, and the exact rule for the price of a stay.

<Warning>
  **Not served yet.** This page describes the final contract, version `1.0.0`. Until the sandbox opens with the first test key, try it against a mock of the contract ([Testing](/en/distribution-api/testing)).
</Warning>

Prices follow the party. Each night of a rate carries the price for every number of adults the property takes, what each child adds by age band and what an infant adds, all as the guest pays them, so the price of any stay is a sum and you compute no rule. Every amount is VAT included, with your markup applied to the nightly prices and never to fees.

## Rate plans

A property has one or more `rate_plans`, each a way to sell it with its own nightly prices and rules:

* `meal_plan`: `none`, `breakfast`, `half_board`, `full_board` or `all_inclusive`. Open enum: accept a value you do not know.
* `cancellation`: `refundable`, `free_until_days_before`, `penalty`, `penalty_percent`, and a `text` Gridbeds generates from those fields. The fields are what binds.
* `child_age_bands`: the age bands the plan prices children by.
* `lower_price_reasons`: why a guest may pay less than the price you add up.

Gridbeds applies no reduction for the length of a stay or for booking early or late. A cheaper rate for a longer or an earlier stay is a rate plan of its own, with its own nightly prices and rules (`min_stay`, `closed_to_arrival`): offer every plan whose rules admit the stay, as the property's own site does, and the cheapest of them is the lowest price Gridbeds offers for it.

## A night's prices

Each rate of a night, in `rates` of an availability response, prices the whole party:

| Field | |
| - | - |
| `prices_by_occupancy` | A price for each number of adults from 1 to `capacity.max_adults`, in ascending order, with no child. Empty when the rate is `closed`. |
| `child_prices` | What one child of each of the plan's `child_age_bands` adds, as `{age_from, age_to, price}`; `0` is free. Empty when the plan names no bands, or when closed. |
| `child_price` | What one child of any age adds when the plan names no bands; `0` when free. `null` when the plan prices children by age band, or when closed. |
| `infant_price` | What one infant adds; `0` when free, `null` when closed. |
| `price`, `base_occupancy`, `extra_guest_price` | Defined from the list, with the meaning they always had. `price` is the `prices_by_occupancy` entry for `base_occupancy` adults. `extra_guest_price` is the entry for `base_occupancy + 1` minus that one: `0` when free, `null` when `base_occupancy` is `capacity.max_adults` (the price covers everyone) or when closed. |

* **Children by age.** `child_age_bands` lists the plan's bands in ascending order, never overlapping, each `{age_from, age_to}` in whole years from 0 to 17, both inclusive. When it is not empty, ask the guest for each child's age: a child whose age falls in no band cannot be booked. When it is empty, the plan prices children without their age, by `child_price`.
* **Infants.** `capacity.max_infants` is how many infants the property takes beside `max_guests`, in a cot and using no bed. An infant is a guest the booking declares as one, conventionally under 2; the property sets no age limit for it in version 1.

## The price of a stay

For a party on one rate plan, the price of a stay is:

<Steps>
  <Step title="Every night of the stay">
    For each night from arrival up to departure (exclusive): the night's `prices_by_occupancy` entry for the number of adults, plus for each child the `child_prices` entry of its age band (or `child_price` when the plan names no bands), plus `infant_price` for each infant.
  </Step>

  <Step title="The fees paid with the booking">
    Then each fee with `included_in_price: false` and `payable_at: booking`: once for `per: stay`, once per night for `per: night` and once per guest and night for `per: guest_night`. In version 1 that is the cleaning fee, once per stay.
  </Step>
</Steps>

That sum is the price of the stay the guest books on the property's own site, VAT included, however much of it the rate plan takes as a deposit. Nothing else is added and nothing is taken off.

**What is paid at the property is shown beside it.** A fee with `payable_at: property` (in version 1 the tourist tax, `city_tax`) is paid to the property during the stay and is not part of that price: the property's own site shows it beside the price, and so should you. A fee with `included_in_price: true` is already in the nightly prices: show it, and add nothing. Charges a property posts to a stay on its own account during it (parking, a resort fee, breakfast billed by the night) are not published in version 1; they are not part of the price on the property's own site either, and are settled at the property.

### When the property's own quote differs

The property's own quote can differ from your sum in four ways, and in no other:

| Difference | |
| - | - |
| A promo code | It lowers the price for a guest who types one on the property's site. The rate plan's `lower_price_reasons` says when that can happen; a code is never published, and none can be applied through this API. |
| Rounding | Gridbeds rounds VAT once over the whole stay, so the sum can differ by up to one minor unit for each amount you added (each component of each night, and each fee), until `/quotes` (stage 2) answers the exact figure. |
| A change of VAT rate during the stay | Gridbeds then charges every night at the rate in force on the departure date, while each published night carries the rate in force on the morning after it. |
| Your markup | It applies to the nightly prices you receive and never to fees, and the property's site shows its prices without it. |

One more difference holds until the property's site asks for each child's age and for infants: the redirect carries only the number of adults and of children (`booking.url_template`), so a party with children on a plan that prices them by age band is priced there without their ages, and a party's infants are not priced there at all.

`lower_price_reasons` is always present, and empty when no guest pays less. Its one value today is `promo_code`: the property has a promo code a guest can still redeem on its own site. It is listed only when `booking.method` is `redirect`, because only a guest sent to the property's site can type one. Say that the final price may be lower, and read a reason you do not know the same way. A change to it is a `property.updated` with a higher version.

## Fees

`fees` lists the charges beside the nightly prices. Version 1 publishes `cleaning` and `city_tax`, each at most once, and neither carries your markup. Every member of a fee is always present; one that does not apply is `null`.

| Member | |
| - | - |
| `type` | `cleaning` or `city_tax` in version 1. Open enum. |
| `basis` | `fixed`: an `amount` per `per`. `percent`: `percent_bp` of the price named by `percent_of`, for `city_tax` only. `null`: for `city_tax` only, when a tourist tax applies and how it is charged is not known. |
| `amount` | For `basis: fixed`, the amount per `per`. `null` for any other basis, and for a `city_tax` whose amount is not known. A cleaning fee always has one. |
| `percent_bp` | For `basis: percent`, the rate in basis points, hundredths of a percent. An integer, never a fraction, so a rate is never rounded on the way. `null` for any other basis, and when the rate is not known. |
| `percent_of` | For `basis: percent`, the price the percentage is of: `accommodation_excluding_vat` or `accommodation_including_vat`. `null` for any other basis, and when the base is not known. |
| `per` | `stay`, `night` or `guest_night`; `null` only when `basis` is `null`. |
| `included_in_price` | `true` when the fee is already in the nightly prices. |
| `payable_at` | `booking`: part of the price of a stay, paid however the booking is paid. `property`: paid to the property during the stay, shown beside the price. |
| `max_nights` | For `city_tax` only: the nights are counted up to this many; `null` when every night is. |
| `exempts_children` | For a `city_tax` of `basis: fixed` only: `true` when only adults are taxed, `false` when children are taxed too. Infants are never taxed. |

A cleaning fee always has `basis: fixed`, an `amount`, `per: stay` and `payable_at: booking`:

```json theme={null}
{ "type": "cleaning", "basis": "fixed", "amount": { "amount": 15000, "currency": "RON" }, "percent_bp": null, "percent_of": null, "per": "stay", "included_in_price": false, "payable_at": "booking", "max_nights": null, "exempts_children": null }
```

Read `basis` first. A fee whose basis you do not know is shown as payable at the property when `payable_at` is `property`, and is never added to the price of a stay.

## The tourist tax

The tourist tax is never left out. Some municipalities levy it as a fixed amount per guest and night, others as a percentage of the accommodation price, and the amounts change by local decision. Every property says which of three things is true in `city_tax_status`:

| `city_tax_status` | Meaning | In `fees` |
| - | - | - |
| `levied` | A tourist tax applies. | Exactly one `city_tax`, whose value may still be unknown. |
| `none` | The property declares that no tourist tax applies. | No `city_tax`. |
| `undeclared` | The property has not said whether one applies; one may. | No `city_tax`: say that a local tax may be payable at the property. |

A property without a `city_tax` fee is therefore never a statement that there is no tax, unless its `city_tax_status` is `none`. Read a status you do not know as `undeclared`. A change is a `property.updated` with a higher version.

A `city_tax` is paid at the property (`payable_at: property`) and is never added to the price of a stay. It states what is known and no more:

* **`basis: fixed`**, with an `amount` per taxable guest and night (`per: guest_night`). The tax of a stay is `amount` × taxable guests × nights, the nights capped at `max_nights`, rounded once to the currency's minor unit. The taxable guests are the adults and the children, or the adults alone when `exempts_children` is `true`, and never the infants. That is the most the property charges: any further exemption it applies only lowers it. `amount` is the rate in force on the property's today; a stay that begins after a new rate takes effect is charged the new one.
* **`basis: percent`**, with `percent_bp`: a percentage of the accommodation price named by `percent_of`, for the whole stay (`per: stay`), or for its first `max_nights` nights when that is set. The base is the accommodation price at the property's own rates, without your markup and without fees, excluding or including VAT; the prices you receive include VAT and your markup, so the base cannot be derived from them exactly. Gridbeds does not compute the amount and neither should you: show the percentage as a local tax paid at the property. Exemptions from a percentage are not modelled: `exempts_children` is `null`, and the property applies its own. Read a `percent_of` you do not know as "the accommodation price".
* **A value that is not known is `null`, and the fee is still there.** `basis: fixed` with `amount: null`, or `basis: percent` with `percent_bp: null`, says that the tax exists and how it is charged, but not how much. `basis: null`, with `per`, `amount` and `percent_bp` `null`, says only that a tourist tax applies. Show such a fee as a local tax payable at the property, never as zero.

The least a `city_tax` can say:

```json theme={null}
{ "type": "city_tax", "basis": null, "amount": null, "percent_bp": null, "percent_of": null, "per": null, "included_in_price": false, "payable_at": "property", "max_nights": null, "exempts_children": null }
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.