Skip to content

Powered by Grav CMS + Helios Theme

Rentals (add-on)

The properties let by the night, their stay rules, the rate card, and the quote for a stay.

Provided by the KahunaCart Rentals plugin. Rentals declares no permissions of its own: a property is a Bookings bookable and a stay is a Bookings booking, so reading takes kahunacart.bookings.view and changing anything takes kahunacart.bookings.manage. Everything a guest does goes through the storefront booking routes under their mode key. See Rentals for developers.

List the properties

GET /api/v1/kahunacart/rentals/properties Permission kahunacart.bookings.view

Every property in this store that books by the night: its Bookings service id, what the product and option are called, how many it sleeps, the zone its dates are in, what a night costs in the store's own currency before any rate band, and how many bands its rate card has.

Response

Answers {properties: [...]}: every service whose mode is nightly.

Read a propertys stay rules

GET /api/v1/kahunacart/rentals/rules/{serviceId} Permission kahunacart.bookings.view

One property's stay rules: what is stored, the same thing with the defaults filled in, how many it sleeps, its timezone and what it is called. Includes the note that goes out before somebody arrives, which often carries a door code and is never sent anywhere else. On a store that sells in more than one currency it also carries currency_amounts: what the cleaning fee, the extra-guest rate, the damage deposit and the monthly rate are in each other currency.

Parameters

Name Type Description
serviceId required integer The Bookings service id of the property.

Response

Answers {rule, effective, service_id, product_id, variant_id, product_title, variant_title, sleeps, timezone, currency}.

Save a propertys stay rules

PUT /api/v1/kahunacart/rentals/rules/{serviceId} Permission kahunacart.bookings.manage

Change a property's stay rules — check-in and check-out times, the shortest and longest stay, which weekdays a stay may start and end on, how many guests the nightly rate covers, the fees, the deposit terms, the cancellation policy and the pre-arrival note. Only the fields sent are changed. Refused in a sentence when a rule would contradict another. The _minor fees are in the store's own currency; currency_amounts gives the same four in each other currency, and a fee left empty in a currency is not charged there.

Parameters

Name Type Description
serviceId required integer The Bookings service id of the property.
check_in_time optional string Wall time in the property's own zone, as `16:00`.
check_out_time optional string Wall time in the property's own zone, as `10:00`.
min_nights optional integer The shortest stay, in nights.
max_nights optional integer The longest stay, in nights. Zero is no limit.
arrival_days optional array of integer Which weekdays a stay may start on, `0` Sunday to `6` Saturday. An empty list is any day.
departure_days optional array of integer Which weekdays a stay may end on. An empty list is any day.
guests_included optional integer How many guests the nightly rate covers before the extra-guest rate starts.
cleaning_fee_minor optional integer Charged once per stay, in minor units.
extra_guest_minor optional integer Per guest per night over `guests_included`, in minor units.
damage_deposit_minor optional integer A stated amount the owner collects themselves. Never charged by the store.
monthly_minor optional integer What one whole month costs, in minor units. A stay of a month or more is priced a month at a time from the arrival date, and the nights after the last whole month by the rate card. 0 is no monthly rate. Raise max_nights (or set it to 0) so a stay can run past a month.
avoid_gaps optional boolean The orphan-night rule — refuse a stay that would leave nights nobody could book.
deposit_percent optional integer or null How much of the stay is taken today. Null takes the whole amount at once.
balance_days_before optional integer or null How many days before arrival the rest falls due.
pre_arrival_text optional string The note sent a few days before somebody arrives — directions, the check-in time, the door code. It is never put on a receipt, in an earlier message, in a feed or in any public payload.
currency_amounts optional object Only on a store that sells in more than one currency. The fees in each other currency, as decimals in that currency's own places: `{"EUR": {"cleaning_fee": "130.00", "extra_guest": "22.00", "damage_deposit": "450.00", "monthly": "1100.00"}}`. An empty string takes an amount away, a key left out leaves it alone, and one wrong figure refuses the whole save. An amount nobody gave in a currency is a charge that is not made there, never the store currency's figure.

Response

Answers the same body as the read, after the save. Only the fields sent are changed.

Read a rate card

GET /api/v1/kahunacart/rentals/rates Permission kahunacart.bookings.view

One property's rate card: every dated band in position order, lowest first, with the property's own nightly price and currency beside them. The band furthest down the list wins a night that two bands both cover. On a store that sells in more than one currency every band carries currency_amounts and the card carries base_in, what the property's own price is in each other currency, which is null where nobody priced it there.

Parameters

Name Type Description
service_id required integer The Bookings service id of the property.

Response

Answers {service_id, currency, base_minor, timezone, rates: [...]}, lowest position first. The band furthest down the list wins a night two bands both cover, and base_minor is what a percentage band is a percentage of.

Add a rate band

POST /api/v1/kahunacart/rentals/rates Permission kahunacart.bookings.manage

Add a dated band to a property's rate card. A band names either a price a night or a percentage of the property's own price, never both. With no position it goes on the end of the card, where it wins any night it overlaps. On a store that sells in more than one currency a band that charges a price a night needs one in each other currency, in currency_amounts, or the nights it covers are not for sale in that currency: a band with no amount there cannot price a night, and is never read as free.

Parameters

Name Type Description
service_id required integer The Bookings service id of the property.
starts_on required string The first date the band covers, as `2026-08-01`.
ends_on required string The last date the band covers, inclusive.
label optional string What the merchant calls it, such as `High summer`.
nightly_minor optional integer or null A price a night in minor units — or `percent`, never both.
percent optional integer or null A share of the property's own price. 130 is thirty per cent more than usual, 80 is a fifth off.
weekend_minor optional integer or null What a weekend night costs inside this band, in minor units.
weekend_days optional array of integer Which nights count as the weekend. Empty is Friday and Saturday.
min_nights optional integer or null Overrides the property's shortest stay for a stay starting inside this band.
arrival_days optional array of integer Overrides the property's arrival days for a stay starting inside this band.
position optional integer Higher wins where two bands cover one night.
currency_amounts optional object Only on a store that sells in more than one currency. What the band charges in each other currency, as decimals in that currency's own places: `{"EUR": {"nightly": "230.00", "weekend": "265.00"}}`. `weekend` is only for a band that has a weekend price. A share of the property's own price takes none. An empty string takes an amount away, and one wrong figure refuses the whole save.

Response

Answers 201 with {rate}. The body carries service_id.

Update a rate band

PATCH /api/v1/kahunacart/rentals/rates/{id} Permission kahunacart.bookings.manage

Change one band on a rate card. Only the fields sent are changed. A band cannot be moved to another property. currency_amounts changes what it charges in the store's other currencies, with an empty string taking one away and a key left out leaving it alone.

Parameters

Name Type Description
id required integer The rate band's own id.
starts_on optional string The first date the band covers.
ends_on optional string The last date the band covers, inclusive.
label optional string 190 characters or fewer.
nightly_minor optional integer or null A price a night in minor units — or `percent`, never both.
percent optional integer or null A share of the property's own price, between 1 and 1000.
weekend_minor optional integer or null At least 0.
weekend_days optional array of integer
min_nights optional integer or null At least 1.
arrival_days optional array of integer
position optional integer
currency_amounts optional object Only on a store that sells in more than one currency, as on `create_rental_rate`.

Response

Answers {rate}.

Remove a rate band

DELETE /api/v1/kahunacart/rentals/rates/{id} Permission kahunacart.bookings.manage

Take one band off a rate card. The nights it covered fall back to whatever band is under it, or to the property's own price.

Parameters

Name Type Description
id required integer The rate band's own id.

Response

Answers {deleted: true, id}.

Reorder the rate bands

POST /api/v1/kahunacart/rentals/rates/reorder Permission kahunacart.bookings.manage

Renumber one property's rate bands in the order the ids are given, which is what decides who wins a night two bands both cover. Answers the whole rate card back. An id belonging to another property is refused and nothing is written.

Parameters

Name Type Description
service_id required integer The Bookings service id of the property.
ids required array of integer The band ids, lowest priority first. Bands of this property the list does not name keep their order and follow the named ones.

Response

Takes {service_id, ids: [...]}, renumbers position in that order and answers the whole card.

Quote a stay

GET /api/v1/kahunacart/rentals/quote Permission kahunacart.bookings.view

What a stay at a property would come to — every night with the band it fell in, the extra guests, the cleaning, the total, what is due today and when the balance falls due. A stay that cannot be had answers the reason a guest would have been given rather than an error. With currency it is priced in another currency the store sells in, from that currency's own amounts, and a stay with a night nobody priced there answers "Not available in EUR." rather than a price.

Parameters

Name Type Description
product_id required integer The product the property is.
variant_id optional integer or null Which option the guest would have picked, where the product has options.
arrival required string The day they arrive, as `2026-08-09`.
departure required string The day they leave, as `2026-08-16`. They do not sleep this night.
guests optional integer How many people. One where nobody said.
exclude_booking_id optional integer A booking to leave out of the calendar, for quoting a move of an existing stay.
currency optional string A currency the store sells in, such as `EUR`. Left out it is the store's own. A currency the store does not sell in is refused.

Response

Answers {quote}, refusal and all. A refused quote is a 200 with ok: false and the sentence a guest would have read, because nothing went wrong with the request. exclude_booking_id leaves one booking out of the reckoning, which is how a move is priced. A product with no nightly rule is a 404.

Money is minor units, named *_minor. Every route that names a service checks that it exists and that its mode is nightly, so a rule written against a haircut is a 404. A refusal from the rule or rate repository is its own sentence, as a 422.