hotel and roomType.
- The amenity dictionary lists every category and amenity with localized labels.
- Hotel and room type responses list the amenities assigned to them, by code.
Amenity dictionary
GET /api/v2/amenity-categories
Fetch the amenity dictionary.
data contains a
category and its
amenities. The whole dictionary is returned in one
response, without pagination. Accept-Language selects
the label languages.
A category is identified by
scope and code; a code is unique only within
its scope. Each amenity has a code that identifies it, a localized label, and
detailKinds, the details that can be specified for it. Amenities with the
options detail kind list their choices in options.
Dictionary excerpt (scope=hotel)
Hotel categories
Room type categories
Assigned amenities
Hotel and room type responses group the assigned amenities by category inamenityCategories. Categories without assigned amenities are omitted.
Categories, amenities, and options follow the dictionary order. An amenity that
is not listed is not offered or not specified.
Each amenity value contains the amenity code
and the fields of its detail kinds.
Labels
Responses identify categories, amenities, and options bycode. To display
them, either:
- Match the codes to the dictionary. Use scope
hotelfor hotel amenities androomTypefor room type amenities, including room types embedded in a hotel. Then matchcategory.code, the amenitycode, and each optioncode. - Request
expand=amenityLabels. The response then includes a localizedlabelon each category, amenity, and option.
Included with this room
Room benefits belong to theinclusions category in scope roomType.
Fetch them as part of the amenity dictionary:
Dictionary category excerpt
expand=roomTypes return
only the benefits assigned to each room type. Find them in amenityCategories:
Room with all three benefits
expand=amenityLabels.
Parking for a room
Room parking is returned in the room type’sinclusions category.
pricing.type: "included" means parking is included in that room’s price.
Hotel parking is returned separately in the hotel’s parking category,
including its localized note. Room type responses do not inherit hotel
parking details.
Detail kinds
An amenity’sdetailKinds lists the details that can be specified for it. Each
detail kind adds fixed fields to the amenity value:
A value contains the fields of all declared detail kinds, even when a detail is
not specified, and no other detail fields. The order of
detailKinds has no
meaning.
Proximity
proximity says where the amenity is located: in-hotel (inside the hotel
building), connecting (in an adjacent building linked by an internal
passage), or nearby (a short distance from the hotel). proximityMeters is
the approximate distance in metres, from 0 to 1,000,000. It is set only when
proximity is nearby.
Pricing
pricing is null when the price conditions are unknown. Otherwise it is
an object with type and schedule, for hotel and room type amenities alike.
A pricing block uses
days, from, and to, like opening hours.
Both times can be null: entry is then included throughout the opening hours
on those days. Otherwise both times are specified. A schedule does not imply
that entry outside its windows is paid.
Price conditions and opening hours are independent. A free-entry window can
be specified when opening hours are unknown. When both are known, windows lie
within opening hours, including any breaks. The response uses days without
times for windows that cover the whole opening day. If a window covers the
entire known opening week, the response uses included instead.
Monetary amounts are not structured fields. Any price description remains
text in note; these values do not change the calculated booking price.
Coverage
coverage describes whether an amenity is available in all physical rooms of
a room type or only some:
all means every room; some means only some rooms. An assigned amenity that
declares this detail kind always returns one of these values, never null.
An unspecified value defaults to all.
The room type dictionary declares coverage on these amenities:
Room type bathroom excerpt
some does not guarantee that a booked room has the amenity. The response
does not identify individual rooms or describe which amenities occur together.
Other amenities omit coverage, including hotel amenities and the room type
inclusions category. Room parking uses the pricing detail kind.
Options
options lists the selected choices by code, for example the types of sauna.
The amenity’s dictionary entry lists every choice, in the same order. With
expand=amenityLabels, each option also has a localized label.
Opening hours
openingHours is null when unknown. Otherwise, its non-empty schedule
lists the opening intervals for the week:
dayscontains weekdays frommondaytosunday, each at most once, in week order.fromandtoare hotel local times inHH:mmformat. Both are required.24:00is allowed only intoand means the end of that day.tois later thanfrom. Intervals across midnight use two blocks.- Blocks that share a day do not overlap. Adjacent intervals are combined; identical intervals on different days share a block.
- A day absent from a known schedule is closed. An unknown schedule does not indicate closure.
from: "00:00",
and to: "24:00". Blocks are ordered by their first weekday, then start and
end time. Opening hours do not specify whether entry is included.
Opening hours of a cafe
Includes
Theaquapark amenity’s includes array lists its facilities. The dictionary
entry declares includedAmenityCodes: indoor_pool, outdoor_pool,
children_pool, whirlpool, and sauna, in that order. Each code references
an amenity definition in the hotel scope. The array contains each selected
code once and does not nest further.
Each item already contains its resolved location, price conditions, opening
hours, and note. Sauna also contains options. Read these values directly;
you do not need to compute inheritance. Labels and option labels are included
with expand=amenityLabels.
Location and distance come from the aquapark. Other values use the facility’s
own conditions when specified, otherwise the aquapark’s. An inherited
free-entry window is limited to the facility’s known opening hours. No
overlap yields pricing: null, which does not mean paid entry. When parent
hours are unknown, inherited days without times remain days without times;
they do not establish unrestricted free entry.
A facility’s own note replaces the whole aquapark note, including translations.
A missing translation remains null. Note and price conditions are resolved
independently.
The hotel’s own pool or sauna remains a separate top-level amenity. An
included facility is not automatically duplicated there. An empty includes
means the aquapark’s contents are unspecified.
Aquapark with a sauna (Accept-Language: en)
Note
note is additional information for guests, up to 200 characters per
language. It follows Accept-Language; a missing
translation is null.
Presence-only amenities
An amenity with an emptydetailKinds array has no details. Its value contains
only code, plus label with expand=amenityLabels. Examples include
hairdryer, kettle, welcome_drink, and fruit_bowl. The dictionary lists
the detail kinds for each amenity.
Filtering
GET /api/v2/hotels and
GET /api/v2/room-types accept
two amenity filters. Each endpoint filters by its own scope.
When you combine both filters, both must match. Unknown codes return
400.
The filters match assigned amenity codes, regardless of details such as
proximity, pricing, or coverage. For example, amenities=balcony matches
room types with either coverage: "all" or coverage: "some".
For hotels, a facility can match as an own amenity or through an aquapark’s
includes, regardless of price conditions. For example, amenities=indoor_pool,sauna
can match an own pool and an aquapark sauna. A nearby facility also matches;
use the returned proximity to narrow the results. Filtering happens before
pagination, so pagination.total counts all matching hotels.
pricing
to determine whether parking is included.
To find hotels by room type amenities, filter room types and use their
hotelId.
Caching
The dictionary changes only with SpaPortal releases. To keep a cached copy current:- Store the dictionary with its
ETagandX-SpaPortal-Amenities-Versionresponse headers. To cache all label languages, omitAccept-Languageor sendAccept-Language: *. - Compare the
X-SpaPortal-Amenities-Versionheader of hotel and room type responses with your stored version. When it differs, fetch the dictionary again. - To revalidate, repeat the same request with
If-None-Match: <stored ETag>. The API returns304without a body while your copy is current.