{"openapi":"3.0.0","info":{"title":"Hostex API","description":"API for integration with Hostex\n\n# Changelog\n\n## [3.9.0] - 2026-06-25\n\n### Added\n\n- `GET \/reservations` now returns a `payment` object for each reservation, exposing the same Received \/ Unreceived collection status shown in the Hostex web app: `total_amount` (expected amount), `received_amount` (already received), `balance_amount` (still outstanding, never negative) and `status` (`unreceived` \/ `partial` \/ `received` \/ `over_received`). Settlement is computed at the order level, so stays sharing the same `reservation_code` carry identical `payment` values. Most meaningful for Hostex Direct (manually created) reservations whose income is recorded via `POST \/transactions`.\n\n## [3.8.0] - 2026-06-17\n\n### Added\n\n- `GET \/listings\/airbnb\/price_and_rules` and `POST \/listings\/airbnb\/price_and_rules` now support `high_rated_guest_discount` and `mobile_only_discount` boolean fields to read and toggle Airbnb's highly-rated guest discount and mobile-only discount promotions.\n\n## [3.7.0] - 2026-06-12\n\n### Added\n\n- New `Messages` endpoints to manage special offers and pre-approvals in a conversation (previously only available in the Hostex Inbox UI):\n  - `GET \/conversations\/{conversation_id}\/special_offers` lists the special offers and pre-approvals sent in a conversation, with their current status (`active` \/ `accepted` \/ `declined` \/ `expired` \/ `withdrawn`). The returned `id` is used to withdraw an offer. Exposed as MCP tool `search_special_offers`.\n  - `POST \/conversations\/{conversation_id}\/special_offers` sends a special offer to the guest, inviting them to book the given listing (`listing_id`) for the given dates at a custom total `price`, with a guest breakdown (`number_of_adults` \/ `number_of_children` \/ `number_of_infants` \/ `number_of_pets`). Supported on Airbnb and booking-site (direct booking) conversations; booking-site conversations also require `rate_plan_id` and `currency`. Offers typically expire 24 hours after being sent. Exposed as MCP tool `send_special_offer`.\n  - `POST \/conversations\/{conversation_id}\/preapprovals` pre-approves the guest's inquiry (Airbnb conversations only), inviting them to book the listing and dates they asked about at the standard price. Exposed as MCP tool `send_preapproval`.\n  - `DELETE \/conversations\/{conversation_id}\/special_offers\/{special_offer_id}` withdraws a previously sent offer that is still active. Exposed as MCP tool `withdraw_special_offer`.\n- New read endpoints for listing-level pricing and rules, complementing the existing write endpoints:\n  - `GET \/listings\/airbnb\/price_and_rules` returns an Airbnb listing's current prices, fees, discounts, booking settings and availability rules, read in real time from Airbnb. The response mirrors the `settings` object accepted by `POST \/listings\/airbnb\/price_and_rules` (values can be written back as-is), plus `eligible_cancellation_policies` listing the valid `cancellation_policy` values for the listing. Rate limited to 120 requests per minute, same as write operations.\n  - `GET \/listings\/vrbo\/price_and_rules` returns a Vrbo listing's prices, fees and booking rules as currently recorded by Hostex (the synced snapshot, not a real-time read from Vrbo). The response mirrors the `settings` object accepted by `POST \/listings\/vrbo\/price_and_rules`.\n\n## [3.6.0] - 2026-06-01\n\n### Added\n\n- `POST \/reviews\/{reservation_code}` now accepts an optional `category_ratings` object to submit per-category sub-ratings (`overall_rating`, `cleanliness`, `communication`, `respect_of_house_rules`, `recommend`) together with the host review. Only effective on channels that support category ratings (currently Airbnb and Zhenguo). When `host_review_score` is omitted, the `overall_rating` value is used as the review score.\n- New write endpoints to update listing-level pricing, fees and booking rules (the listing's default settings, not a specific date range; only the fields you provide are updated):\n  - `POST \/listings\/airbnb\/price_and_rules` updates an Airbnb listing's prices, fees, discounts, booking settings and availability rules (`base_price`, `weekend_price`, `cleaning_fee`, `security_deposit`, `pet_fee`, `early_bird_discount` \/ `last_minute_discount` \/ `long_term_discount`, `check_in_start_time` \/ `check_in_end_time` \/ `check_out_before`, `instant_booking`, `minimum_stay` \/ `maximum_stay`, `advance_notice`, `availability_window`, `cancellation_policy`, `new_listing_promotion`, etc.). Processed synchronously against Airbnb.\n  - `POST \/listings\/vrbo\/price_and_rules` updates a Vrbo listing's prices, fees and booking rules (`base_price` or per-weekday `nightly_rate`, `cleaning_fee`, `security_deposit`, `extra_guest_fee`, `weekly_discount` \/ `monthly_discount`, `check_in_start_time` \/ `check_out_before`, `instant_booking`, `minimum_stay`, `advance_notice`, `availability_window`). Processed synchronously against Vrbo.\n\n## [3.5.0] - 2026-05-25\n\n### Added\n\n- New `Messages` write endpoint to manage the host-side note attached to a conversation thread (the same `note` already exposed read-only on `GET \/conversations\/{conversation_id}`):\n  - `PATCH \/conversations\/{conversation_id}\/note` sets or clears the note. Notes are stored only in Hostex (visible in the Hostex Inbox), are **never** sent to the guest or pushed to any channel, and are shared across operators inside the same account so the team can leave context for each other. Pass an empty string or `null` in `note` to clear the existing note (max 5000 chars). Exposed as MCP tool `update_conversation_note`.\n- New write operations on the `Property` group dictionary, complementing the existing `GET \/groups`:\n  - `POST \/groups` creates a new property group (`name` required; optional `property_ids` to pre-attach properties). Group names must be unique within the operator's account. Exposed as MCP tool `create_property_group`.\n  - `PATCH \/groups\/{id}` updates a group. `name` renames it; `property_ids` **replaces** the full property assignment (empty array detaches all). Exposed as MCP tool `update_property_group`.\n  - `DELETE \/groups\/{id}` deletes a group and its pivot rows; the underlying properties are unaffected. Exposed as MCP tool `delete_property_group`.\n- New write operations on the `Property` tag dictionary, complementing the existing `GET \/tags`:\n  - `POST \/tags` creates a new property tag (`name` required; optional `color` from the Hostex palette, `property_ids`, `room_type_ids`). Operators are capped at 500 property tags; soft-deleted same-name tags are transparently restored. Exposed as MCP tool `create_property_tag`.\n  - `PATCH \/tags\/{id}` updates a tag. `name` \/ `color` change the tag itself; `property_ids` \/ `room_type_ids` each **replace** the full attached list (empty arrays detach all). Exposed as MCP tool `update_property_tag`.\n  - `DELETE \/tags\/{id}` deletes a tag and its property \/ room-type pivot rows. Exposed as MCP tool `delete_property_tag`.\n- New `Reservation Tags` section with read\/write coverage of the operator's reservation tag dictionary (the tags that `POST \/reservations\/{stay_code}\/tags` can attach to a reservation):\n  - `GET \/reservation_tags` lists the operator's reservation tag dictionary, including both system default tags (`is_default = true`, shared across operators) and the operator's own custom tags. Supports `offset` \/ `limit` pagination, `id` lookup and `keyword` substring search. Exposed as MCP tool `search_reservation_tags`.\n  - `POST \/reservation_tags` creates a new custom tag (`tag_name` only, max 15 chars). Color is auto-assigned from the Hostex palette. Name collisions against the system defaults or the operator's existing tags return 409; a soft-deleted tag with the same name is transparently restored. Operators are capped at 500 custom tags. Exposed as MCP tool `create_reservation_tag`.\n  - `DELETE \/reservation_tags\/{id}` deletes one of the operator's custom tags. System default tags cannot be deleted via this API. Deletion also detaches the tag from every reservation it had been applied to. Exposed as MCP tool `delete_reservation_tag`.\n- New `Calendar Share Links` section with read\/write coverage of public, read-only calendar share links (the same artefacts the Hostex Host Portal exposes under \"Share calendar\"):\n  - `GET \/calendar_share_links` lists the operator's share links. Each entry returns `id`, `scope` (`entire` \/ `partial`), the share `url` and the `property_ids` the link exposes (empty when `scope = entire`). Exposed as MCP tool `search_calendar_share_links`.\n  - `POST \/calendar_share_links` creates a new share link. `scope = entire` covers every property (idempotent: returns the existing link if any). `scope = partial` requires a non-empty `property_ids` list; each id must belong to the operator. Exposed as MCP tool `create_calendar_share_link`.\n  - `DELETE \/calendar_share_links\/{id}` invalidates a share link; anyone holding the previous URL will get a `share link invalid` error. Exposed as MCP tool `delete_calendar_share_link`.\n\n### Changed\n\n- `GET \/tags` x-mcp metadata: `description` and `intent_examples` clarified \u2014 this endpoint returns **property tags** (the tags attached to properties \/ room types), not reservation tags. The new MCP tool `search_reservation_tags` covers the reservation tag dictionary. The response shape itself is unchanged.\n- `GET \/reservations`: each reservation now includes `checkin_guide_images`, an array of ID document images uploaded by guests through the online check-in guide. The list covers every image submitted under the reservation \u2014 including images not yet linked to a guest record (`client_id` is `null` for those). Each entry has `id`, `client_id` and `url` (extra-large CDN variant). Existing per-guest `guests[].id_images` is unchanged.\n- `GET \/reservations`: each reservation now exposes `rates.tax`, the reservation `TAXES` amount as a standalone `{ currency, amount }` object (`null` when the reservation has no taxes). The aggregated `rates.rate` and `rates.details` are unchanged.\n\n---\n\n## [3.4.1] - 2026-05-21\n\n### Changed\n\n- **BREAKING** `GET \/knowledge_bases`: `property_ids` query parameter is now a comma-separated integer string (e.g. `1,2,3`) instead of a repeated array, matching `GET \/automation\/actions` and the rest of the v3 list endpoints.\n- **BREAKING** `POST \/knowledge_bases` and `PATCH \/knowledge_bases\/{id}`: `scope_property.scope_ids` renamed to `scope_property.ids` so the field name matches the value returned by `GET \/knowledge_bases` and `GET \/knowledge_bases\/{id}`.\n\n### Added\n\n- `GET \/knowledge_bases\/{id}`: response now includes `process_status` (string enum `waiting`\/`processing`\/`done`\/`failed`), matching the list endpoint.\n- `GET \/automation\/actions`: each item in `actions[]` now includes `type` (`message`\/`review`) and `stay_code` (linked reservation code, may be `null`).\n- `POST \/automation\/actions\/{plan_id}\/execute`: documented `400` response for unsupported plan types or `review` plans whose reservation has not checked out yet.\n\n### Fixed\n\n- `GET \/knowledge_bases`: filtering by `channel_types` no longer crashes with a `TypeError`; `scope_property` in each row now correctly reflects the entry's actual property scope (`all` \/ `by_property` \/ `by_group` \/ `by_room_type`) instead of always falling back to an empty `by_property` set.\n- `GET \/knowledge_bases\/{id}`: same `scope_property` correctness fix as above.\n- `POST \/knowledge_bases` and `PATCH \/knowledge_bases\/{id}`: when `scope_channel.type` is `all`, the upstream channel list is no longer populated with an `unknown` sentinel; permission failures on `PATCH \/knowledge_bases\/{id}` and `DELETE \/knowledge_bases\/{id}` now consistently return `404`.\n- `GET \/knowledge_bases`: pagination now respects arbitrary `offset` values instead of always advancing by a full page (previous `ceil(offset \/ limit) + 1` made `offset=5, limit=10` return rows 11\u201320 instead of 6\u201315).\n- `GET \/automation\/actions`: results are now correctly scoped to the operator's master account, so sub-account access tokens no longer return an empty list. The `total` count also matches the number of returned `actions[]` rows (plans missing their rule or detail row are filtered in SQL instead of skipped in PHP).\n- `POST \/automation\/actions\/{plan_id}\/execute`: same-day reviews are no longer rejected as \"not yet checked out\" \u2014 the check-out date comparison now uses the date portion of the reservation's check-out timestamp instead of a lexicographic string compare.\n\n---\n\n\n## [3.4.0] - 2026-05-20\n\n### Added\n\n- New `Knowledge Base` section with full read\/write coverage of the HostGPT knowledge base entries used by the automation assistant. Each entry carries a content body and a scope (properties \/ channels) where it applies:\n  - `GET \/knowledge_bases` to list entries, with pagination and optional filtering by property or channel.\n  - `GET \/knowledge_bases\/{id}` to fetch the full detail of a single entry.\n  - `POST \/knowledge_bases` to create a new entry.\n  - `PATCH \/knowledge_bases\/{id}` to update an existing entry.\n  - `DELETE \/knowledge_bases\/{id}` to delete an entry.\n- New `Channels` section with read-only access to the operator's connected channel accounts and the listings synced from them:\n  - `GET \/channel_accounts` returns the third-party platform accounts the operator has connected (Airbnb, Booking.com, etc.) with `channel_type`, `username`, `origin_account_id` and a readable `auth_status` enum (`active` \/ `connecting` \/ `disconnected` \/ `exception`). Supports filtering by `id` and `channel_type`. Accounts with `channel_type=booking_site` are excluded. Exposed as MCP tool `search_channel_accounts`.\n  - `GET \/listings` returns the listings (channel-side properties) synced under those accounts with `listing_id`, `channel_type`, `channel_account_id`, `title`, `cover`, `url`, `inventory`, a readable `shelf_status` enum and a `metadata` passthrough object exposing the normalized channel-side data Hostex caches internally (geo, pictures, price list, etc.; shape varies by channel). Supports filtering by `channel_account_id`, `listing_id` and `channel_type`. Exposed as MCP tool `search_listings`.\n- `GET \/tasks`: new optional `id` query parameter for fetching a single task by its internal id (still scoped to the current operator). Other filters remain unchanged.\n- `GET \/transactions`: new optional `id` query parameter for fetching a single transaction entry by its internal id. When `id` is supplied, `start_date` and `end_date` may be omitted; otherwise the existing date-range requirement (and 366-day cap) still applies.\n- `GET \/reservations`: each entry in `guests` now includes an `id_images` array exposing the ID document images uploaded for that guest. Each item carries the image `id` and a `url` pointing to the extra-large variant served by the image CDN. Returns an empty array when no image has been uploaded.\n- `GET \/conversations\/{id}`: each entry in `messages` now includes:\n  - `sender_name`: display name of the sender when known (operator account name for host-side messages, `HostGPT` for HostGPT-generated messages, localized HostGPT label for shadow preview messages). `null` for guest messages and other cases where the sender cannot be resolved.\n  - `sources`: knowledge sources cited by HostGPT to generate the message, grouped by `type` (e.g. `checkin_guide`, `automation_reply`, `host_knowledge`, `thread`, `host_assistant`). Each group exposes `docs[].title` \/ `docs[].fragment` \/ `docs[].source_type` \/ `docs[].link_id`. Empty array for human-sent messages and HostGPT messages without resolved citations.\n- `PATCH \/reservations\/{stay_code}\/check_in_details`: new optional `id_required` field controls whether the guest must register \/ upload ID documents before check-in. String enum: `not_required` (no ID needed), `required` (collect ID, no manual review), `required_with_review` (collect ID and the host must manually review and approve). Internally maps to the `need_credential` field of the per-stay check-in guide and triggers the same downstream check-in unlocking logic as the Hostex Host Portal.\n- `GET \/reservations`: each entry in `check_in_details` now exposes the matching `id_required` string enum (defaults to `not_required` when no setting has been applied to the stay).\n- `GET \/reservations`: `order_by` now accepts `created_at` (sort by the row creation timestamp, i.e. when the reservation was first synced into Hostex). Existing values (`booked_at`, `check_in_date`, `check_out_date`, `cancelled_at`) are unchanged; default remains `booked_at`.\n- `POST \/tasks`: new optional `stay_code` field links the task to a specific reservation by writing into the `schedule_task__reservation` pivot. When `stay_code` is supplied without `property_id`, the property is inherited from the stay; when both are supplied they must point to the same property. Used by the LLM workflow for \"create a cleaning \/ maintenance task on this reservation\".\n- `GET \/tasks`: each task entry now includes a `stay_code` field (string, nullable) \u2014 the reservation the task is linked to, or `null` for unlinked tasks.\n- New `Property` write endpoint:\n  - `POST \/properties` creates a new property (room) under the current operator. Only `title` is required; everything else (address, channels, pictures, prices, default check-in\/out times) is configured afterwards via the Hostex Host Portal. Subject to the property quantity limit of the operator's subscription.\n- New `Room Type` write endpoint:\n  - `POST \/room_types` creates a new room type under the current operator. Optionally accepts `property_ids` to link existing properties at creation time (each property must not already belong to another room type). Subject to the room type quantity limit (capped by the property quantity limit of the subscription) and not available on Basic editions.\n- New `GET \/pricing_ratios` endpoint (under `Listing Calendar`) returns the per-channel pricing ratio of each OTA listing linked to a property (`property_id`) or room type (`room_type_id`). Each entry exposes `channel_type`, `listing_id`, `listing_title`, `ratio` (percent) and `readonly`. This enables a \"change price by property \/ room type\" workflow at the skill \/ client layer without a dedicated server endpoint: read the ratios, compute `target_price = round(base_price * ratio \/ 100)` for every non-readonly listing, then call `POST \/listings\/prices` once per listing (`readonly: true` listings \u2014 e.g. Airbnb child rate plans \u2014 must be skipped).\n\n\n---\n\n## [3.3.1] - 2026-05-11\n\n### Fixed\n\n- `GET \/transactions`: `start_date` and `end_date` are now consistently interpreted in the operator's configured timezone, matching how entries are stored and how `action_at` is returned. Previously the boundaries could be evaluated in the database session's default timezone, causing up to a one-day shift for operators not in UTC+8.\n- `POST \/transactions` and `PATCH \/transactions\/{id}`: `action_at` values supplied as UTC ISO 8601 are now correctly converted to the operator's timezone before being persisted, so the round-trip with `GET \/transactions` returns the same instant.\n\n---\n\n## [3.3.0] - 2026-05-08\n\n### Added\n\n- `GET \/reservations`: new optional `channel_id` query parameter to filter reservations by the channel-side reservation ID (the same value returned as `channel_id` in the response).\n\n---\n\n## [3.2.0] - 2026-04-29\n\n### Added\n\n- New `Incomes & Expenses` section, with full read\/write coverage of income and expense entries (transactions):\n  - `GET \/transactions` for querying entries. Supports filtering by date range (`start_date` \/ `end_date`), `property_id`, `stay_code`, `direction`, `item_id`, `payment_method_id`, `currency` and `keyword`. Each entry exposes `direction` (`income` \/ `expense`), `link_type` (`property` \/ `reservation` \/ `operator`) and `status` (`paid` \/ `outstanding`) as readable string enums, and resolves `item_name` \/ `payment_method_name` from the dictionaries below.\n  - `POST \/transactions` to record a new entry. The link target is inferred from the request: provide `stay_code` to record against a specific stay, `property_id` to record against a property, or neither for an operator-level entry (master operator only). `amount` is always positive \u2014 sign is derived from `direction`. `currency` is required unless `stay_code` is provided, in which case it is inherited from the reservation order.\n  - `PATCH \/transactions\/{id}` to update an entry's `amount`, `item_id`, `payment_method_id`, `action_at` or `note`. Direction, link target and currency are immutable.\n  - `DELETE \/transactions\/{id}` to permanently delete an entry.\n  - New dictionary endpoints `GET \/income_items`, `GET \/expense_items`, `GET \/income_methods` and `GET \/expense_methods` decode the `item_id` \/ `payment_method_id` returned by `GET \/transactions`.\n- New `Task` write endpoints:\n  - `POST \/tasks` to create a schedule task. Optional `property_id` and `staff_id` link the task to a property and assign a staff; `level` is only meaningful for cleaning tasks. `expected_date` \/ `expected_time` are interpreted in the operator's configured timezone. Returns the new `task_id`.\n  - `PATCH \/tasks\/{id}` to update an existing task. All fields are optional; pass `property_id=0` or `staff_id=0` to detach. The full `status` lifecycle (`pending` \/ `in_progress` \/ `completed` \/ `cancelled`) can be set here. `expected_date` \/ `expected_time` are interpreted in the operator's configured timezone.\n  - `DELETE \/tasks\/{id}` to delete a task.\n- New `Staff` write endpoints:\n  - `POST \/staffs` to create a schedule staff (created as active). Use `property_ids` to scope the staff to specific properties. International operators must provide `mobile` in `+<country code> <number>` format.\n  - `PATCH \/staffs\/{id}` to update an existing staff. Passing `property_ids` replaces the full assignment list; pass an empty array to clear. `is_active` toggles enable\/disable.\n  - `DELETE \/staffs\/{id}` to delete a staff (and remove their property assignments).\n\n### Changed\n\n- `PATCH \/reservations\/{stay_code}` (Update Reservation Basic Info): the path parameter is now `stay_code` instead of `reservation_code`, since the endpoint updates a specific stay's attributes rather than the order. The URL pattern itself is unchanged. `DELETE \/reservations\/{reservation_code}` (Cancel) and the channel-facing `POST \/reservations\/{reservation_code}\/approve|decline` keep `reservation_code` since they operate at the order level.\n\n### Fixed\n\n- `GET \/reservations`: the `custom_channel.id` field now returns the same id used by `GET \/custom_channels` (previously returned an internal table primary key that could not be matched against the dictionary).\n\n---\n\n## [3.1.2] - 2026-04-28\n\n### Added\n\n- New `Task` endpoints `GET \/tasks` and `GET \/staffs` for querying schedule tasks and staffs.\n- `GET \/tasks` supports filtering by date range (`start_date` \/ `end_date`), `staff_id`, `property_id`, `type` and `status`.\n- Task `type`, `status` and `level` are returned as readable string enums (e.g. `cleaning`, `pending`, `standard`).\n\n---\n\n## [3.1.1] - 2026-03-10\n\n### Added\n\n- New `Property` endpoint `GET \/tags` returning all tags with their associated property and room type ids.\n- `GET \/properties` supports `tag_id` filter and now returns a `tags` array on each property.\n- `GET \/room_types` supports `id` and `tag_id` filters and now returns a `tags` array on each room type.\n\n---\n\n## [3.1.0] - 2026-01-21\n\n### Added\n\n- New `Property` endpoint `GET \/groups` returning all property groups with their associated property ids.\n- `GET \/properties` supports `group_id` filter and now returns a `groups` array on each property.\n\n---\n\n## [3.0.0]\n\n### Added\n\n- Initial release of the Hostex OpenAPI v3, with endpoints covering Properties, Room Types, Reservations, Availabilities, Listing Calendar, Messaging, Reviews, Automation and Webhooks.","version":"3.9.0"},"servers":[{"url":"https:\/\/api.hostex.io\/v3","description":"Hostex API Server"}],"tags":[{"name":"Property","description":""},{"name":"Room Type","description":""},{"name":"Reservations","description":""},{"name":"Availability","description":""},{"name":"Listing Calendar","description":""},{"name":"Messages","description":""},{"name":"Reviews","description":""},{"name":"Automation","description":"Scheduled automation actions (e.g. automated guest messages and scheduled host reviews)."},{"name":"Task","description":"Schedule tasks such as cleaning, maintenance, reception, housekeeping and others."},{"name":"Incomes & Expenses","description":"Income and expense entries (transactions) plus the dictionaries used to categorize them."},{"name":"Manage Webhooks","description":""},{"name":"Oauth","description":""},{"name":"Knowledge Base","description":"AI knowledge base entries for the HostGPT automation assistant. Each entry defines content and the scope (properties\/channels) where it applies."},{"name":"Channels","description":"Channel accounts (third-party platform accounts the operator has connected) and the listings synced from those accounts."},{"name":"Reservation Tags","description":"Manage the operator's reservation tag dictionary (the tags that can be applied to reservations)."},{"name":"Calendar Share Links","description":"Public share links that expose a read-only calendar (and reservation list) of all or selected properties to anyone holding the link."}],"paths":{"\/properties":{"get":{"summary":"Query Properties","description":"You can query properties by making a request to this endpoint.","operationId":"query-properties","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_properties","description":"Search \/ paginate the operator's properties. Returns each property's id, name, address, status, and connected channels. Common use cases: list all properties to pick from, look up a property name by id, browse the asset list during onboarding.","intent_examples":["List all my properties","How many properties do I have","What is the id of Coastal Villa #1"],"category":"property","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"offset","in":"query","description":"The starting point from which to begin returning results.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100.","required":false,"schema":{"type":"integer","default":20}},{"name":"id","in":"query","description":"The id of the property.","required":false,"schema":{"type":"integer"}},{"name":"group_id","in":"query","description":"Filter properties by the group id. Only properties belonging to this group are returned.","required":false,"schema":{"type":"integer"}},{"name":"tag_id","in":"query","description":"Filter properties by the tag id. Only properties tagged with this tag are returned.","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"A list of properties with their details","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["properties","total"],"properties":{"properties":{"description":"List of the properties","type":"array","items":{"required":["id","title","channels"],"properties":{"id":{"description":"Unique identifier for the property","type":"integer","format":"int64"},"title":{"description":"Title of the property","type":"string"},"channels":{"description":"List of channels associated with the property","type":"array","items":{"required":["channel_type","listing_id"],"properties":{"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."}},"type":"object"}},"groups":{"description":"List of groups the property belongs to","type":"array","items":{"required":["id","name"],"properties":{"id":{"description":"Unique identifier for the group","type":"integer","format":"int64"},"name":{"description":"Name of the group","type":"string"}},"type":"object"}},"tags":{"description":"List of tags attached to the property","type":"array","items":{"required":["id","name"],"properties":{"id":{"description":"Unique identifier for the tag","type":"integer","format":"int64"},"name":{"description":"Name of the tag","type":"string"},"color":{"description":"Color of the tag, in hex format (e.g. #FD587B).","type":"string"}},"type":"object"}},"address":{"description":"address of the property","type":"string"},"longitude":{"description":"longitude of the property","type":"string"},"latitude":{"description":"latitude of the property","type":"string"}},"type":"object"}},"total":{"description":"Total number of properties.","type":"integer"}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Property","description":"Create a new property (room) under the current operator. Hostex properties are physical room units; OTA listings can be attached to a property afterwards via the Hostex Host Portal. The newly created property has no address, channels or pictures and starts with the operator's default check-in \/ check-out time settings. Subject to the property quantity limit of the operator's subscription.","operationId":"create-property","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_property","description":"Create a new property. Only accepts `title`; all other details (address, channels, photos, pricing, etc.) are configured later in the admin portal. \u26a0\ufe0f Consumes one slot from the subscription's property quota; will fail when the quota is exhausted.","intent_examples":["Create a new property named 'Coastal Villa #5'","Add another room called Studio A"],"category":"property","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","maxLength":100,"description":"Title of the new property. Must be unique within the operator."}}}}}},"responses":{"200":{"description":"The property has been successfully created.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["property_id"],"properties":{"property_id":{"type":"integer","format":"int64","description":"Unique identifier of the newly created property."}},"type":"object"}},"type":"object"}]}}}}}}},"\/pricing_ratios":{"get":{"summary":"Query Pricing Ratios","description":"Return the per-channel pricing ratio of each OTA listing linked to a property (`property_id`) or a room type (`room_type_id`). Pricing ratio is the **percentage** Hostex multiplies a base (property\/room-type level) price by to derive the actual price pushed to each listing. Use this endpoint at the skill layer to compose a 'change price by property \/ room type' workflow: read the ratios, compute `target_price = round(base_price * ratio \/ 100)` for every non-readonly listing, then call `POST \/listings\/prices` once per listing. Listings marked `readonly: true` are silently controlled by the channel (e.g. Airbnb child rate plans) and cannot be repriced via `POST \/listings\/prices`; skip them.","operationId":"query-pricing-ratios","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"get_pricing_ratios","description":"Get the per-channel listing price ratios (in %) for a given property or room type. Use the ratios client-side to compute each listing's target price (`target = round(base * ratio \/ 100)`), then loop `update_listing_prices` to push the new prices. Listings with `readonly=true` cannot be updated via `update_listing_prices` and must be skipped. Exactly one of `property_id` \/ `room_type_id` is required.","intent_examples":["What are the price ratios on each OTA for Coastal Villa #1","I want to reprice this room type \u2014 show me the ratio per channel"],"category":"calendar","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"property_id","in":"query","description":"Id of the property to read ratios for. Mutually exclusive with `room_type_id`; exactly one of the two must be supplied.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"room_type_id","in":"query","description":"Id of the room type to read ratios for. Mutually exclusive with `property_id`; exactly one of the two must be supplied.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Pricing ratios for the listings under the given property or room type.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["link_type","link_id","channels"],"properties":{"link_type":{"type":"string","enum":["property","room_type"],"description":"Echoes which of `property_id` \/ `room_type_id` was supplied."},"link_id":{"type":"integer","format":"int64","description":"Echoes the supplied id."},"channels":{"type":"array","description":"One entry per OTA listing currently linked to the property \/ room type.","items":{"type":"object","required":["channel_type","listing_id","ratio","readonly"],"properties":{"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"listing_title":{"type":"string","description":"Display title of the listing on the channel."},"ratio":{"type":"integer","description":"Pricing ratio in percent. `100` = same as base price; `>100` = markup; `<100` = discount. When `readonly=true`, this is `-1` and should not be used to compute target prices."},"readonly":{"type":"boolean","description":"When `true`, the listing's price is controlled by the channel (e.g. Airbnb child rate plans synced from a parent) and cannot be updated via `POST \/listings\/prices`; skip these in the workflow."}}}}},"type":"object"}},"type":"object"}]}}}}}}},"\/groups":{"get":{"summary":"Query Groups","description":"You can query property groups by making a request to this endpoint.","operationId":"query-groups","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_property_groups","description":"List property groups. A group is an operator-defined collection of properties (e.g. 'Sea-view suites', 'Downtown apartments', 'Handled by cleaner A'). Returns each group's id, name, and associated property ids. Common use cases: batch-operate or filter by group.","intent_examples":["What property groups do I have","Which properties are in the Sea-view Suites group"],"category":"property","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"offset","in":"query","description":"The starting point from which to begin returning results.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100.","required":false,"schema":{"type":"integer","default":20}},{"name":"id","in":"query","description":"The id of the group.","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"A list of groups with their details","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["groups","total"],"properties":{"groups":{"description":"List of the groups","type":"array","items":{"required":["id","name","property_ids"],"properties":{"id":{"description":"Unique identifier for the group","type":"integer","format":"int64"},"name":{"description":"Name of the group","type":"string"},"property_ids":{"description":"Property ids that belong to this group","type":"array","items":{"type":"integer","format":"int64"}}},"type":"object"}},"total":{"description":"Total number of groups.","type":"integer"}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Group","description":"Create a new property group. Optionally pre-attach properties at creation time via `property_ids`. The group name must be unique within the operator's account.","operationId":"create-group","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_property_group","description":"Create a new property group (an operator-defined collection of properties such as 'Sea-view suites', 'Downtown apartments'). Optionally pass `property_ids` to pre-assign properties. Returns the new group's id, name and the property_ids it now contains. Use search_properties first to look up property ids.","intent_examples":["Create a property group called 'Sea-view suites'","Create a group 'Downtown apartments' with properties 101, 102, 103"],"category":"property","read_only":false,"since_version":"3.6.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":50,"description":"Group display name. Max 50 characters. Must be unique within the operator's account."},"property_ids":{"type":"array","items":{"type":"integer"},"description":"Optional list of property ids to attach to the new group. Each id must belong to the operator."}}}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["group"],"properties":{"group":{"type":"object","required":["id","name","property_ids"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"property_ids":{"type":"array","items":{"type":"integer"}}}}},"type":"object"}},"type":"object"}]}}}}}}},"\/groups\/{id}":{"patch":{"summary":"Update Group","description":"Update a property group. Pass `name` to rename it; pass `property_ids` to **replace** the group's full property assignment with the supplied list (pass an empty array to detach all properties). Omitted fields are left unchanged.","operationId":"update-group","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_property_group","description":"Rename a property group and\/or replace its property assignment. `property_ids` REPLACES the full list (not additive): to add a property, fetch the current ids via search_property_groups(id=...) first, then PATCH with the combined list. Pass an empty array to detach all properties from the group.","intent_examples":["Rename group 5 to 'Coastline villas'","Add property 110 to the 'Sea-view suites' group","Remove all properties from group 7"],"category":"property","read_only":false,"since_version":"3.6.0"},"parameters":[{"name":"id","in":"path","description":"Internal group id (from `search_property_groups`).","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"description":"New display name. Must remain unique within the operator's account."},"property_ids":{"type":"array","items":{"type":"integer"},"description":"Replaces the group's property list with the given ids (each must belong to the operator). Empty array detaches all."}}}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"delete":{"summary":"Delete Group","description":"Delete a property group. All property-group pivot rows are removed automatically; the underlying properties themselves are unaffected.","operationId":"delete-group","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_property_group","description":"Permanently delete a property group. Properties previously attached to the group are NOT deleted, only detached. Look up the group id via search_property_groups first.","intent_examples":["Delete the 'Old downtown apartments' group","Remove property group 7"],"category":"property","read_only":false,"since_version":"3.6.0"},"parameters":[{"name":"id","in":"path","description":"Internal group id (from `search_property_groups`).","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/room_types":{"summary":"RoomType","description":"RoomType","get":{"summary":"Query RoomTypes","description":"You can query room types by making a request to this endpoint.","operationId":"query-room-types","tags":["Room Type"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_room_types","description":"List room types. A room type groups interchangeable properties of the same kind and is used to sell by room-type inventory (vs. selling a specific property). Returns each room type's id, name, and associated properties.","intent_examples":["List my room types","What room types do I have"],"category":"property","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"offset","in":"query","description":"The starting point from which to begin returning results.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100.","required":false,"schema":{"type":"integer","default":20}},{"name":"id","in":"query","description":"The id of the room type.","required":false,"schema":{"type":"integer"}},{"name":"tag_id","in":"query","description":"Filter room types by the tag id. Only room types tagged with this tag are returned.","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"A list of room types with their details","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["room_types","total"],"properties":{"room_types":{"description":"List of the room types","type":"array","items":{"required":["id","title","properties","channels"],"properties":{"id":{"description":"Unique identifier for the property","type":"integer","format":"int64"},"title":{"description":"Title of the property","type":"string"},"properties":{"description":"A list of properties associated with the room type. The number of properties represents the maximum inventory quantity for the room type.","type":"array","items":{"required":["id","title"],"properties":{"id":{"description":"Unique identifier for the property","type":"integer","format":"int64"},"title":{"description":"The title of the property","type":"string"}},"type":"object"}},"channels":{"description":"List of channels associated with the room type","type":"array","items":{"required":["channel_type","listing_id"],"properties":{"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."}},"type":"object"}},"tags":{"description":"List of tags attached to the room type","type":"array","items":{"required":["id","name"],"properties":{"id":{"description":"Unique identifier for the tag","type":"integer","format":"int64"},"name":{"description":"Name of the tag","type":"string"},"color":{"description":"Color of the tag, in hex format (e.g. #FD587B).","type":"string"}},"type":"object"}}},"type":"object"}},"total":{"description":"Total number of room types.","type":"integer"}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create RoomType","description":"Create a new room type under the current operator. A room type is a group of interchangeable properties (rooms) sold as a single inventory pool. Optionally link existing properties at creation time via `property_ids` \u2014 each linked property must not already belong to another room type. Subject to the room type quantity limit of the operator's subscription (capped by the property quantity limit) and not available on Basic editions.","operationId":"create-room-type","tags":["Room Type"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_room_type","description":"Create a new room type. Optionally pass `property_ids` to attach several properties at once (each property must not already belong to another room type). \u26a0\ufe0f Not supported on the Basic subscription; the room type count cannot exceed the property quota.","intent_examples":["Create a room type called 'City-view King Room'","Create a new room type and attach rooms 101, 102, 103"],"category":"property","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","maxLength":100,"description":"Title of the new room type. Must be unique within the operator."},"property_ids":{"type":"array","description":"Optional list of property ids to link to the new room type. Each property must belong to the operator and must not already be linked to another room type.","items":{"type":"integer","format":"int64"}}}}}}},"responses":{"200":{"description":"The room type has been successfully created.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["room_type_id"],"properties":{"room_type_id":{"type":"integer","format":"int64","description":"Unique identifier of the newly created room type."}},"type":"object"}},"type":"object"}]}}}}}}},"\/tags":{"get":{"summary":"Query Tags","description":"You can query tags by making a request to this endpoint.","operationId":"query-tags","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_tags","description":"List the operator's property tags (the tags attached to properties \/ room types, not reservation tags). Each entry returns id, name, color and the property_ids \/ room_type_ids the tag is applied to. Use search_reservation_tags for the reservation tag dictionary.","intent_examples":["What property tags are available","Which properties carry the 'Beachfront' tag"],"category":"meta","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"offset","in":"query","description":"The starting point from which to begin returning results.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100.","required":false,"schema":{"type":"integer","default":20}},{"name":"id","in":"query","description":"The id of the tag.","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"A list of tags with their details","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["tags","total"],"properties":{"tags":{"description":"List of the tags","type":"array","items":{"required":["id","name","color","property_ids","room_type_ids"],"properties":{"id":{"description":"Unique identifier for the tag","type":"integer","format":"int64"},"name":{"description":"Name of the tag","type":"string"},"color":{"description":"Color of the tag, in hex format (e.g. #FD587B).","type":"string"},"property_ids":{"description":"Property ids attached with this tag","type":"array","items":{"type":"integer","format":"int64"}},"room_type_ids":{"description":"Room type ids attached with this tag","type":"array","items":{"type":"integer","format":"int64"}}},"type":"object"}},"total":{"description":"Total number of tags.","type":"integer"}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Tag","description":"Create a new property tag. Optionally pre-attach properties via `property_ids` and \/ or room types via `room_type_ids`. The name must be unique within the operator's account (soft-deleted same-name tags are restored). Color is auto-assigned from the Hostex palette unless one of the allowed hex strings is supplied. Operators are capped at 500 property tags.","operationId":"create-tag","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_property_tag","description":"Create a new property tag (the tag dictionary used to label properties \/ room types, e.g. 'Beachfront', 'Pet-friendly'). Optionally attach properties (`property_ids`) and \/ or room types (`room_type_ids`) at creation time. For tagging existing properties \/ room types under a tag that already exists, use update_property_tag instead. Returns the new tag's id, name, color, property_ids and room_type_ids.","intent_examples":["Create a property tag called 'Beachfront'","Add a 'Pet-friendly' tag and attach properties 101, 102"],"category":"property","read_only":false,"since_version":"3.6.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":15,"description":"Tag display name. Max 15 characters. Must be unique within the operator's account."},"color":{"type":"string","enum":["#FD587B","#1BBFA4","#FFA410","#F3D432","#2CBCFD","#7175FA","#EF7EDE"],"description":"Hex color string. Auto-assigned from the palette when omitted."},"property_ids":{"type":"array","items":{"type":"integer"},"description":"Optional list of property ids to attach to the new tag."},"room_type_ids":{"type":"array","items":{"type":"integer"},"description":"Optional list of room type ids to attach to the new tag."}}}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["tag"],"properties":{"tag":{"$ref":"#\/components\/schemas\/PropertyTag"}},"type":"object"}},"type":"object"}]}}}}}}},"\/tags\/{id}":{"patch":{"summary":"Update Tag","description":"Update a property tag. Pass `name` and \/ or `color` to change the tag itself; pass `property_ids` and \/ or `room_type_ids` to **replace** the tag's full assignment list. Pass an empty array to detach all properties \/ all room types. Omitted fields are left unchanged.","operationId":"update-tag","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_property_tag","description":"Rename a property tag, change its color, or replace the properties \/ room types it is attached to. Both `property_ids` and `room_type_ids` REPLACE the full list (not additive): to add a property to a tag without dropping the existing ones, fetch the current ids via search_tags(id=...) first, then PATCH with the combined list. Pass an empty array to detach all properties \/ room types from the tag.","intent_examples":["Rename property tag 3 to 'Oceanfront'","Attach properties 110, 111 to the 'Pet-friendly' tag","Detach all room types from the 'Family suite' tag"],"category":"property","read_only":false,"since_version":"3.6.0"},"parameters":[{"name":"id","in":"path","description":"Internal tag id (from `search_tags`).","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":15,"description":"New display name. Must remain unique within the operator's account."},"color":{"type":"string","enum":["#FD587B","#1BBFA4","#FFA410","#F3D432","#2CBCFD","#7175FA","#EF7EDE"],"description":"Hex color string from the allowed palette."},"property_ids":{"type":"array","items":{"type":"integer"},"description":"Replaces the tag's property list with the given ids (each must belong to the operator). Empty array detaches all."},"room_type_ids":{"type":"array","items":{"type":"integer"},"description":"Replaces the tag's room type list with the given ids (each must belong to the operator). Empty array detaches all."}}}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"delete":{"summary":"Delete Tag","description":"Delete a property tag. All property-tag and room-type-tag pivot rows are removed automatically; the underlying properties \/ room types themselves are unaffected.","operationId":"delete-tag","tags":["Property"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_property_tag","description":"Permanently delete a property tag. The properties and room types previously labelled with the tag are NOT deleted, only detached. Look up the tag id via search_tags first.","intent_examples":["Delete the 'Old discount' property tag","Remove property tag 12"],"category":"property","read_only":false,"since_version":"3.6.0"},"parameters":[{"name":"id","in":"path","description":"Internal tag id (from `search_tags`).","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/tasks":{"get":{"summary":"Query Tasks","description":"You can query schedule tasks (cleaning \/ maintain \/ reception \/ housekeeping \/ others) by making a request to this endpoint.","operationId":"query-tasks","tags":["Task"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_tasks","description":"Search tasks (cleaning \/ maintenance \/ reception \/ room service \/ other). Filter by `id` (to fetch one task), status, type, property, staff, date range, etc. Returns each task's id, type, property, assigned staff, status, expected execution time, and more. Pass `id` to fetch a single task's details.","intent_examples":["What cleaning tasks do I have today","All tasks for Coastal Villa #1 next week","Open maintenance tasks","Show me the details of task 123"],"category":"task","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"query","description":"Internal id of a specific task. When supplied, returns at most one entry (the matching task under the current operator).","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"The starting point from which to begin returning results.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100.","required":false,"schema":{"type":"integer","default":20}},{"name":"start_date","in":"query","description":"The start of the expected date range to filter tasks by. The date format is YYYY-MM-DD. `start_date` and `end_date` must be supplied together.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_date","in":"query","description":"The end of the expected date range to filter tasks by. The date format is YYYY-MM-DD. `start_date` and `end_date` must be supplied together.","required":false,"schema":{"type":"string","format":"date"}},{"name":"staff_id","in":"query","description":"Filter tasks assigned to the given staff id.","required":false,"schema":{"type":"integer"}},{"name":"property_id","in":"query","description":"Filter tasks under the given property id.","required":false,"schema":{"type":"integer"}},{"name":"type","in":"query","description":"Filter tasks by type.","required":false,"schema":{"type":"string","enum":["cleaning","maintenance","reception","room_service","other"]}},{"name":"status","in":"query","description":"Filter tasks by status.","required":false,"schema":{"type":"string","enum":["pending","in_progress","completed","cancelled"]}}],"responses":{"200":{"description":"A list of tasks with their details","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["tasks","total"],"properties":{"tasks":{"description":"List of the tasks","type":"array","items":{"required":["id","type","status"],"properties":{"id":{"description":"Unique identifier for the task","type":"integer","format":"int64"},"type":{"description":"Task type.","type":"string","enum":["cleaning","maintenance","reception","room_service","other"]},"status":{"description":"Task status.","type":"string","enum":["pending","in_progress","completed","cancelled"]},"property_id":{"description":"Property id this task belongs to. Null if the task is not bound to a property.","type":"integer","format":"int64","nullable":true},"property_title":{"description":"Title of the property this task belongs to.","type":"string","nullable":true},"stay_code":{"description":"Stay code this task is linked to. Null when the task is not linked to a reservation.","type":"string","nullable":true},"staff_id":{"description":"Id of the staff this task is assigned to. Null if the task is not assigned.","type":"integer","format":"int64","nullable":true},"staff_name":{"description":"Name of the staff this task is assigned to.","type":"string","nullable":true},"expected_date":{"description":"Expected execution date in YYYY-MM-DD.","type":"string","format":"date"},"expected_time":{"description":"Expected execution time in HH:mm:ss. May be null when only date is set.","type":"string","nullable":true},"expected":{"description":"Expected execution datetime in YYYY-MM-DD HH:mm:ss.","type":"string"},"level":{"description":"Cleaning level.","type":"string","enum":["standard","simple","advanced"],"nullable":true},"currency":{"description":"The currency code for the fee.","type":"string","nullable":true},"fee":{"description":"Task fee.","type":"number","format":"float"},"note":{"description":"Note attached to the task.","type":"string"},"create_time":{"description":"Time when the task was created (YYYY-MM-DD HH:mm:ss).","type":"string","nullable":true},"update_time":{"description":"Time when the task was last updated (YYYY-MM-DD HH:mm:ss).","type":"string","nullable":true}},"type":"object"}},"total":{"description":"Total number of tasks.","type":"integer"}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Task","description":"Create a schedule task. The task may be linked to a property (`property_id`), to a specific stay (`stay_code`), and\/or assigned to a staff (`staff_id`); all are optional. When `stay_code` is provided the task is linked to the reservation; `property_id` is inferred from the stay when omitted (and must match the stay's property when both are supplied). The `type` selects the task category and `level` is only meaningful for cleaning tasks.","operationId":"create-task","tags":["Task"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_task","description":"Create a task (cleaning \/ maintenance \/ reception \/ room service \/ other). Can optionally be linked to a property (`property_id`), a reservation (`stay_code`), or assigned to a staff member (`staff_id`). When `stay_code` is supplied the task is bound to that reservation and `property_id` defaults to the reservation's property if omitted. `type` selects the task category; `level` is only meaningful for cleaning tasks.","intent_examples":["Create a cleaning task for Coastal Villa #1 tomorrow morning","Create a cleaning task for reservation ABC123","Assign a maintenance task to John"],"category":"task","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["type","expected_date","currency"],"properties":{"type":{"description":"Task category.","type":"string","enum":["cleaning","maintenance","reception","room_service","other"]},"stay_code":{"description":"Stay code to link the task to a specific reservation. When provided, the task is linked to the reservation and `property_id` defaults to the stay's property (an explicit `property_id` must match).","type":"string"},"property_id":{"description":"Id of the property the task belongs to. Omit to record an unassigned task (or to inherit from `stay_code` when supplied).","type":"integer"},"staff_id":{"description":"Id of the staff to assign. Omit to leave the task unassigned.","type":"integer"},"expected_date":{"description":"Expected execution date in `YYYY-MM-DD`. Interpreted in the operator's configured timezone (see [Account Settings](https:\/\/hostex.io\/app\/account\/setting)).","type":"string","format":"date"},"expected_time":{"description":"Expected execution time in `HH:mm:ss`. Optional. Interpreted in the operator's configured timezone.","type":"string"},"level":{"description":"Cleaning level. Only meaningful when `type=cleaning`.","type":"string","enum":["standard","simple","advanced"]},"currency":{"description":"Currency code for `fee`. See [Supported Currencies](\/reference\/supported-currencies) for more information.","type":"string"},"fee":{"description":"Task fee. Defaults to 0 (or to the property's configured cleaning fee for cleaning tasks linked to a property when omitted).","type":"number"},"note":{"description":"Free-form note attached to the task (max 500 characters).","type":"string"}}}}}},"responses":{"200":{"description":"The task has been successfully created.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["task_id"],"properties":{"task_id":{"description":"Unique identifier of the newly created task.","type":"integer","format":"int64"}},"type":"object"}},"type":"object"}]}}}}}}},"\/tasks\/{id}":{"patch":{"summary":"Update Task","description":"Update an existing task. All fields are optional; only the supplied fields are changed. Pass `property_id=0` or `staff_id=0` to detach the task from the related property or staff.","operationId":"update-task","tags":["Task"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_task","description":"Update an existing task. All fields are optional; only the supplied fields are changed. Pass `property_id=0` or `staff_id=0` to detach the task from its property \/ staff. Common use cases: change task status (e.g. mark as completed), reassign staff, change the expected time, add a note.","intent_examples":["Mark this task as completed","Reassign this task to Lily","Reschedule this cleaning task to 3 PM"],"category":"task","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"path","description":"Id of the task to update.","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["cleaning","maintenance","reception","room_service","other"]},"property_id":{"description":"Pass `0` to detach the task from any property.","type":"integer"},"staff_id":{"description":"Pass `0` to unassign the task.","type":"integer"},"expected_date":{"description":"Expected execution date in `YYYY-MM-DD`. Interpreted in the operator's configured timezone.","type":"string","format":"date"},"expected_time":{"description":"Expected execution time in `HH:mm:ss`. Interpreted in the operator's configured timezone.","type":"string"},"level":{"type":"string","enum":["standard","simple","advanced"]},"status":{"type":"string","enum":["pending","in_progress","completed","cancelled"]},"currency":{"type":"string"},"fee":{"type":"number"},"note":{"type":"string"}}}}}},"responses":{"200":{"description":"The task has been successfully updated.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"delete":{"summary":"Delete Task","description":"Delete a task permanently. Returns 404 if the task does not exist or is not accessible to the current operator.","operationId":"delete-task","tags":["Task"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_task","description":"Permanently delete a task. \u26a0\ufe0f Irreversible \u2014 the task history and associated staff assignment records are wiped. If you only want to mark it done or cancelled, use `update_task` to change `status` instead.","intent_examples":["Delete task 123","Remove this cleaning task \u2014 I created it by mistake"],"category":"task","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"path","description":"Id of the task to delete.","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"The task has been successfully deleted.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/staffs":{"get":{"summary":"Query Staffs","description":"You can query schedule staffs (cleaners \/ operators \/ receptionists, etc.) by making a request to this endpoint.","operationId":"query-staffs","tags":["Task"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_staffs","description":"List the staff \/ contractors (cleaners, maintenance technicians, receptionists, housekeepers, etc.). Returns each staff member's id, name, type, and contact details. Common use case: look up `staff_id` by name before calling `create_task` \/ `update_task`.","intent_examples":["Which cleaners do I have","What is the maintenance technician's phone number","What is John's staff id"],"category":"task","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"offset","in":"query","description":"The starting point from which to begin returning results.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100.","required":false,"schema":{"type":"integer","default":20}},{"name":"id","in":"query","description":"The id of the staff.","required":false,"schema":{"type":"integer"}},{"name":"is_active","in":"query","description":"Filter staffs by active state. 1: active only, 0: inactive only.","required":false,"schema":{"type":"integer","enum":[0,1]}}],"responses":{"200":{"description":"A list of staffs with their details","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["staffs","total"],"properties":{"staffs":{"description":"List of the staffs","type":"array","items":{"required":["id","name","is_active"],"properties":{"id":{"description":"Unique identifier for the staff","type":"integer","format":"int64"},"name":{"description":"Name of the staff","type":"string"},"mobile":{"description":"Mobile number of the staff","type":"string"},"email":{"description":"Email address of the staff","type":"string"},"note":{"description":"Note attached to the staff","type":"string"},"is_active":{"description":"Whether the staff is active.","type":"boolean"}},"type":"object"}},"total":{"description":"Total number of staffs.","type":"integer"}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Staff","description":"Create a schedule staff. The staff is created as active by default. Use `property_ids` to limit the staff to specific properties; the staff will be created with access to all properties when omitted.\n\nFor international operators, `mobile` must be in `+<country code> <number>` format (e.g. `+86 13800138000`).","operationId":"create-staff","tags":["Task"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_staff","description":"Create a staff member \/ contractor (cleaner, maintenance technician, receptionist, housekeeper, etc.). Defaults to `active`. Use `property_ids` to restrict the staff to specific properties (omit to authorize all properties). For international operators, `mobile` must use the `+<country code> <number>` format, e.g. `+1 4155550100`.","intent_examples":["Add a new cleaner named Mary, phone +1 4155550100","Add a maintenance technician who only services Coastal Villa #1"],"category":"task","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["name","mobile"],"properties":{"name":{"description":"Display name of the staff (max 128 characters).","type":"string"},"mobile":{"description":"Mobile number. International operators must use `+<country code> <number>` format.","type":"string"},"email":{"description":"Email address.","type":"string"},"note":{"description":"Free-form note (max 500 characters).","type":"string"},"property_ids":{"description":"Properties this staff can access. Omit to grant access to all properties available to the operator.","type":"array","items":{"type":"integer"}}}}}}},"responses":{"200":{"description":"The staff has been successfully created.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["staff_id"],"properties":{"staff_id":{"description":"Unique identifier of the newly created staff.","type":"integer","format":"int64"}},"type":"object"}},"type":"object"}]}}}}}}},"\/staffs\/{id}":{"patch":{"summary":"Update Staff","description":"Update an existing staff. All fields are optional; only the supplied fields are changed. Passing `property_ids` replaces the staff's full property assignment list (use an empty array to clear). Use `is_active` to enable or disable the staff.","operationId":"update-staff","tags":["Task"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_staff","description":"Update a staff member's info. All fields are optional; only the supplied fields are changed. \u26a0\ufe0f Note: passing `property_ids` **fully replaces** the staff's authorized property list (it is not appended); passing an empty array clears all authorizations. Use `is_active` to enable \/ disable the staff.","intent_examples":["Change Mary's phone number to +1 4155550199","Deactivate John","Let Lily service both Villa #1 and Villa #2"],"category":"task","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"path","description":"Id of the staff to update.","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"mobile":{"type":"string"},"email":{"type":"string"},"note":{"type":"string"},"is_active":{"description":"Enable (`true`) or disable (`false`) the staff.","type":"boolean"},"property_ids":{"description":"Replaces the staff's property assignment list. Use an empty array to remove all assignments.","type":"array","items":{"type":"integer"}}}}}}},"responses":{"200":{"description":"The staff has been successfully updated.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"delete":{"summary":"Delete Staff","description":"Delete a staff permanently along with their property assignments. Returns 404 if the staff does not exist or is not accessible to the current operator.","operationId":"delete-staff","tags":["Task"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_staff","description":"Permanently delete a staff member \/ contractor along with all their property authorizations. \u26a0\ufe0f Irreversible. If you only want to temporarily disable the staff, use `update_staff` to set `is_active=false` instead.","intent_examples":["Delete John from staff","Remove Lily \u2014 she has left the company"],"category":"task","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"path","description":"Id of the staff to delete.","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"The staff has been successfully deleted.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/availabilities":{"get":{"summary":"Query Property Availabilities","description":"By sending a request to this endpoint, you can retrieve the availabilities of the properties.","operationId":"query-availabilities","tags":["Availability"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_availabilities","description":"Query the property-level availability calendar. Returns each property's daily availability status (`available=true\/false`) within the requested date range. Note the distinction: this is the property master calendar (which decides whether bookings are open) \u2014 it differs from per-channel listing inventory \/ prices (use `search_listing_calendars` for those). Common use cases: check which days a property is free, find which days are booked or blocked.","intent_examples":["Which days is Coastal Villa #1 open next month","Which properties are still bookable this weekend"],"category":"calendar","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"property_ids","in":"query","description":"Enter property IDs to search, separating them with commas (,). A maximum of 100 properties can be queried at once.","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"The start date for records. The date format is YYYY-MM-DD, and must be within 1 years from now.","required":true,"schema":{"type":"string","format":"date"}},{"name":"end_date","in":"query","description":"The end date for records. The date format is YYYY-MM-DD, and must be within 3 years from now.","required":true,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"A list of availabilities with their details","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["properties"],"properties":{"properties":{"description":"","type":"array","items":{"required":["id","availabilities"],"properties":{"id":{"description":"The unique identifier for the property","type":"integer"},"availabilities":{"description":"A list of availability objects. Each object contains the date, available, and remarks for that date.","type":"array","items":{"required":["date","available","remarks"],"properties":{"date":{"description":"The date of the availability","type":"string","format":"date"},"available":{"description":"Set the date's availability: `true` for available or `false` for unavailable.","type":"boolean"},"remarks":{"description":"Remarks for the date","type":"string"}},"type":"object"}}},"type":"object"}}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Update Property Availabilities","description":"Use this endpoint to update property availabilities. <br><br>Please be aware that a successful response indicates only that we have initiated an asynchronous task to handle your submission; it <b>DOES NOT<\/b> ensure that the channel inventories have been modified successfully. If you wish to view detailed results of the task execution, please visit the [Host Portal](https:\/\/hostex.io\/app\/calendar).","operationId":"update-availabilities","tags":["Availability"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_availabilities","description":"Open \/ block a property's availability over a date range (`available=true` opens, `false` blocks). Asynchronous: a successful response only means the task was submitted; the change takes a short while to propagate to channels. Will cascade to all connected channels' inventory for that property. Note: this controls the property master calendar \u2014 distinct from per-channel listing inventory (`update_listing_inventories`). Blocking the wrong dates can make the property unbookable or impact existing reservations, so double-check the date range.","intent_examples":["Block Coastal Villa #1 next Monday through Wednesday","Reopen Coastal Villa for May 20-25"],"category":"calendar","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"description":"","required":true,"content":{"application\/json":{"schema":{"required":["property_ids","available"],"properties":{"property_ids":{"description":"Specify the property IDs to update.","type":"array","items":{"type":"integer"}},"start_date":{"description":"Specify the update's start date using the YYYY-MM-DD format. This must be either the current date or a future date. <br>If omitted, the `dates` becomes mandatory.","type":"string","format":"date"},"end_date":{"description":"Specify the update's end date using the YYYY-MM-DD format. This must be a future date within 3 years from now. <br>If omitted, the `dates` becomes mandatory.","type":"string","format":"date"},"dates":{"description":"Provide a list of dates for the update in YYYY-MM-DD format. Dates must be today's date or later. <br>If `start_date` and `end_date` are specified, the list of dates will not be considered.","type":"array","items":{"type":"string","format":"date"}},"available":{"description":"Set the availability status: `true` for available or `false` for unavailable.","type":"boolean"}},"type":"object"}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/listings\/calendar":{"post":{"summary":"Query Listing Calendars","description":"By sending a request to this endpoint, you can retrieve calendar information for multiple listings. This endpoint will return daily details on price, inventory, and restrictions for each listing.","operationId":"query-listing-calendars","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_listing_calendars","description":"Query the per-channel listing calendar (daily price, inventory, minimum-stay and other restrictions per `channel_type` + `listing_id` within a date range). Note: a listing is the OTA-side entry (Airbnb, Booking, etc.) for one property and carries channel-specific price \/ inventory. To query the property master calendar use `search_availabilities`.","intent_examples":["Prices on Airbnb for Coastal Villa May 20-30","Booking inventory and minimum-stay for this property next week"],"category":"calendar","read_only":true,"since_version":"3.4.0"},"requestBody":{"description":"","required":true,"content":{"application\/json":{"schema":{"required":["start_date","end_date","listings"],"properties":{"start_date":{"description":"The start date for records. The date format is YYYY-MM-DD, and must be within 1 years from now.","type":"string","format":"date"},"end_date":{"description":"The end date for the calendar. The date format is YYYY-MM-DD, and must be within 3 years from now.","type":"string","format":"date"},"listings":{"description":"A list of listing object. The listing object contains the listing id and channel type.","type":"array","items":{"required":["channel_type","listing_id"],"properties":{"channel_type":{"$ref":"#\/components\/schemas\/ChannelTypeParam"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"}},"type":"object"}}},"type":"object"}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["listings"],"properties":{"listings":{"description":"A list of listing objects. Each listing object contains the listing id, channel type, and calendar.","type":"array","items":{"required":["listing_id","channel_type","calendar"],"properties":{"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"calendar":{"description":"A list of calendar objects. Each calendar object contains the date, price, and inventory for that date.","type":"array","items":{"required":["date","price","inventory"],"properties":{"date":{"description":"The date of the calendar","type":"string","format":"date"},"price":{"description":"The price for the date","type":"number"},"inventory":{"description":"The inventory for the date","type":"integer"},"restrictions":{"description":"Restrictions for the date. Please notice that the range of fields for restrictions may vary across different channels. The fields listed below may not apply to all channels.","properties":{"closed_on_arrival":{"description":"Reservations for the check-in date on this date are not allowed. Available for `airbnb` `booking.com` `agoda` `expedia` `booking_site` `trip.com`.","type":"boolean"},"closed_on_departure":{"description":"Reservations for the check-out date on this date are not allowed. Available for `airbnb` `booking.com` `agoda` `expedia` `booking_site` `trip.com`.","type":"boolean"},"min_stay_on_arrival":{"description":"Reservations including this date must not be shorter than the specified number of days. Available for `airbnb` `booking.com` `agoda` `expedia` `booking_site` `trip.com`.","type":"integer"},"max_stay_on_arrival":{"description":"Reservations including this date must not be longer than the specified number of days. Available for `airbnb` `booking.com` `agoda` `expedia` `booking_site` `trip.com`.","type":"integer"},"min_stay_through":{"description":"Reservations including this date must not be shorter than the specified number of days. Available for `booking.com` `agoda` `trip.com`.","type":"integer"},"max_stay_through":{"description":"Reservations including this date must not be longer than the specified number of days. Available for `booking.com` `trip.com`.","type":"integer"},"min_advance_reservation":{"description":"The minimum number of days and\/or hours that guests must book in advance (before the planned check-in or check-out date). The search date is counted as one of the days in the restriction length. This field requires the format like 'xDxH'. Examples: 4D = four days; 4D4H = four days and four hours. Available for `booking.com` `trip.com`.","type":"string"},"max_advance_reservation":{"description":"The maximum number of days and\/or hours that guests may book in advance (before the planned check-in or check-out date). The search date is counted as one of the days in the restriction length. This field requires the format like 'xDxH'. Examples: 4D = four days; 4D4H = four days and four hours. Available for `booking.com` `trip.com`.","type":"string"},"exact_stay_on_arrival":{"description":"Reservations with the check-in date on this date must be equal to the specified number of days. Available for `booking.com`.","type":"integer"}},"type":"object"}},"type":"object"}}},"type":"object"}}},"type":"object"}},"type":"object"}]}}}}}}},"\/listings\/inventories":{"post":{"summary":"Update Listing Inventories","description":"Update the inventories of channel listings. <br><br>Please be aware that a successful response indicates only that we have initiated an asynchronous task to handle your submission; it <b>DOES NOT<\/b> ensure that the channel inventories have been modified successfully. If you wish to view detailed results of the task execution, please visit the [Host Portal](https:\/\/hostex.io\/app\/price). <br><br>Furthermore, you should be aware that this endpoint only modifies the listing's inventory and <b>DOES NOT<\/b> affect the property availability. If the property availability is modified, it may still result in the channel inventory being overwritten again.","operationId":"update-listing-inventories","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_listing_inventories","description":"Update the inventory of a channel listing for specific dates. Asynchronous \u2014 channel-side propagation takes a short while. Note: this only updates per-channel inventory and does NOT touch the property master calendar (`property availability`); subsequent master-calendar changes can overwrite this. To open \/ block the property master calendar use `update_availabilities`. Wrong values can cause oversells or sellouts.","intent_examples":["Set Airbnb inventory to 0 for this property next week","Set Booking inventory to 1 for May 20-25"],"category":"calendar","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"description":"","required":true,"content":{"application\/json":{"schema":{"type":"object","required":["channel_type","listing_id","inventories"],"properties":{"channel_type":{"$ref":"#\/components\/schemas\/ChannelTypeParam"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"inventories":{"type":"array","items":{"type":"object","required":["start_date","end_date","inventory"],"properties":{"start_date":{"description":"The start date from which the inventory update will apply.","type":"string","format":"date"},"end_date":{"description":"The end date until which the inventory update will apply, must be within 3 years from now.","type":"string","format":"date"},"inventory":{"description":"The number of available units for the specified date range.","type":"integer"}}}}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/listings\/prices":{"post":{"summary":"Update Listing Prices","description":"Update the prices of channel listings. <br><br>Please be aware that a successful response indicates only that we have initiated an asynchronous task to handle your submission; it <b>DOES NOT<\/b> ensure that the channel prices have been modified successfully. If you wish to view detailed results of the task execution, please visit the [Host Portal](https:\/\/hostex.io\/app\/price).","operationId":"update-listing-prices","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_listing_prices","description":"Update the selling price of a channel listing for specific dates. Asynchronous \u2014 channel-side propagation takes a short while. Pricing changes directly affect what guests see and pay, so double-check channel \/ listing \/ dates \/ currency \/ amount. For long-term dynamic pricing, prefer integrating a service such as PriceLabs rather than calling this endpoint manually.","intent_examples":["Raise Airbnb price to 800 for this property on May 20-25","Add a 20% markup on Booking for next weekend"],"category":"calendar","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"description":"","required":true,"content":{"application\/json":{"schema":{"type":"object","required":["channel_type","listing_id","prices"],"properties":{"channel_type":{"$ref":"#\/components\/schemas\/ChannelTypeParam"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"prices":{"type":"array","items":{"type":"object","required":["start_date","end_date","price"],"properties":{"start_date":{"description":"The start date from which the price update will apply.","type":"string","format":"date"},"end_date":{"description":"The end date until which the price update will apply, must be within 3 years from now.","type":"string","format":"date"},"price":{"description":"The price of the listing for the specified date range. <br><br>For example, if the currency is USD, price=100 represents 100 US dollars, not 100 cents.","type":"integer"}}}}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/listings\/restrictions":{"post":{"summary":"Update Listing Restrictions","description":"Update the restrictions of channel listings. <br><br>Please be aware that a successful response indicates only that we have initiated an asynchronous task to handle your submission; it <b>DOES NOT<\/b> ensure that the channel restrictions have been modified successfully. If you wish to view detailed results of the task execution, please visit the [Host Portal](https:\/\/hostex.io\/app\/price).","operationId":"update-listing-restrictions","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_listing_restrictions","description":"Update the booking restrictions of a channel listing for specific dates (minimum nights, maximum nights, whether check-in \/ check-out is allowed on the date, etc.). Asynchronous. Common use cases: require at least 3 nights during peak season, close check-in on a specific date.","intent_examples":["Require a 2-night minimum on Airbnb for next weekend","Close check-in on Booking for May 1"],"category":"calendar","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"description":"","required":true,"content":{"application\/json":{"schema":{"type":"object","required":["channel_type","listing_id","restrictions"],"properties":{"channel_type":{"$ref":"#\/components\/schemas\/ChannelTypeParam"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"restrictions":{"type":"array","items":{"type":"object","required":["start_date","end_date"],"properties":{"start_date":{"description":"The start date from which restrictions update will apply.","type":"string","format":"date"},"end_date":{"description":"The end date until which restrictions update will apply, must be within 3 years from now.","type":"string","format":"date"},"closed_on_arrival":{"description":"Reservations for the check-in date on this date are not allowed. Available for `airbnb` `booking.com` `agoda` `expedia` `booking_site` `trip.com`.","type":"boolean"},"closed_on_departure":{"description":"Reservations for the check-out date on this date are not allowed. Available for `airbnb` `booking.com` `agoda` `expedia` `booking_site` `trip.com`.","type":"boolean"},"min_stay_on_arrival":{"description":"Reservations including this date must not be shorter than the specified number of days. Available for `airbnb` `booking.com` `agoda` `expedia` `booking_site` `trip.com`.","type":"integer"},"max_stay_on_arrival":{"description":"Reservations including this date must not be longer than the specified number of days. Available for `airbnb` `booking.com` `agoda` `expedia` `booking_site` `trip.com`.","type":"integer"},"min_stay_through":{"description":"Reservations including this date must not be shorter than the specified number of days. Available for `booking.com` `agoda` `trip.com`.","type":"integer"},"max_stay_through":{"description":"Reservations including this date must not be longer than the specified number of days. Available for `booking.com` `trip.com`.","type":"integer"},"min_advance_reservation":{"description":"The minimum number of days and\/or hours that guests must book in advance (before the planned check-in or check-out date). The search date is counted as one of the days in the restriction length. This field requires the format like 'xDxH'. Examples: 4D = four days; 4D4H = four days and four hours. Available for `booking.com` `trip.com`.","type":"string"},"max_advance_reservation":{"description":"The maximum number of days and\/or hours that guests may book in advance (before the planned check-in or check-out date). The search date is counted as one of the days in the restriction length. This field requires the format like 'xDxH'. Examples: 4D = four days; 4D4H = four days and four hours. Available for `booking.com` `trip.com`.","type":"string"},"exact_stay_on_arrival":{"description":"Reservations with the check-in date on this date must be equal to the specified number of days. Available for `booking.com`.","type":"integer"}}}}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/listings\/airbnb\/price_and_rules":{"get":{"summary":"Get Airbnb Listing Price and Rules","description":"Fetch the current pricing, availability rules and booking settings of an Airbnb listing in real time from Airbnb. The response fields mirror the `settings` object accepted by `POST \/listings\/airbnb\/price_and_rules`, so values read here can be written back as-is.\n\nThis endpoint calls multiple Airbnb APIs per request and therefore shares the stricter rate limit of write operations (120 requests per minute).","operationId":"get-airbnb-listing-price-and-rules","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"parameters":[{"name":"listing_id","in":"query","description":"The Airbnb listing id.","required":true,"schema":{"$ref":"#\/components\/schemas\/ListingId"}}],"responses":{"200":{"description":"The current price and rules of the Airbnb listing.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"type":"object","properties":{"listing_currency":{"description":"The listing currency code, e.g. `USD`.","type":"string"},"base_price":{"description":"The default nightly price.","type":"number"},"weekend_price":{"description":"The Friday and Saturday nightly price. `null` when not set.","type":"number","nullable":true},"security_deposit":{"description":"The security deposit amount.","type":"number"},"cleaning_fee":{"description":"The cleaning fee amount.","type":"number"},"short_term_cleaning_fee":{"description":"The short-term cleaning fee amount. `null` when not set.","type":"number","nullable":true},"pet_fee":{"description":"The pet fee amount. `null` when not set.","type":"number","nullable":true},"pet_fee_obj":{"description":"The detailed pet fee. `null` when not set.","type":"object","nullable":true,"properties":{"amount":{"type":"number"},"charge_type":{"type":"string"},"charge_period":{"type":"string"}}},"extra_guest_fee":{"description":"The fee charged per extra guest.","type":"number","nullable":true},"early_bird_discount":{"description":"Early bird discounts: `discount` percent off when booked at least `days` days ahead.","type":"array","items":{"type":"object","properties":{"discount":{"type":"integer","description":"Discount percentage (0-100)."},"days":{"type":"integer"}}}},"last_minute_discount":{"description":"Last minute discounts: `discount` percent off when booked within `days` days of check-in.","type":"array","items":{"type":"object","properties":{"discount":{"type":"integer","description":"Discount percentage (0-100)."},"days":{"type":"integer"}}}},"long_term_discount":{"description":"Long term discounts: `discount` percent off for stays of at least `days` nights.","type":"array","items":{"type":"object","properties":{"discount":{"type":"integer","description":"Discount percentage (0-100)."},"days":{"type":"integer"}}}},"check_in_start_time":{"description":"Check-in start time. An integer hour 8-24, `25`\/`26` for 1am\/2am next day, or `FLEXIBLE`."},"check_in_end_time":{"description":"Check-in end time. An integer hour 9-26 (`25`\/`26` for 1am\/2am next day) or `FLEXIBLE`."},"check_out_before":{"description":"Check-out latest time, an integer hour 0-23.","type":"integer"},"instant_booking":{"description":"Whether instant booking is allowed.","type":"boolean"},"max_guests":{"description":"The number of guests included in the base price.","type":"integer"},"minimum_stay":{"description":"The default minimum number of nights.","type":"integer"},"maximum_stay":{"description":"The default maximum number of nights.","type":"integer"},"advance_notice":{"description":"Booking lead time in hours.","type":"integer","nullable":true},"availability_window":{"description":"How far in advance (in days) the calendar is bookable.","type":"integer"},"preparation_time":{"description":"Turnover\/preparation days between reservations.","type":"integer"},"days_of_week_check_in":{"description":"Days of week (0=Sunday ... 6=Saturday) on which check-in IS allowed.","type":"array","items":{"type":"integer"}},"days_of_week_check_out":{"description":"Days of week (0=Sunday ... 6=Saturday) on which check-out IS allowed.","type":"array","items":{"type":"integer"}},"allow_rtb_above_max_nights":{"description":"Whether request-to-book is allowed for stays exceeding the maximum nights.","type":"boolean"},"cancellation_policy":{"description":"The cancellation policy category."},"long_term_cancellation_policy":{"description":"The long-term-stay cancellation policy id.","nullable":true},"non_refundable_price_factor":{"description":"The non-refundable discount percentage (0-100). `null` when the non-refundable option is off.","type":"number","nullable":true},"day_of_week_min_nights":{"description":"Per-day-of-week minimum nights rules; only days with a minimum-nights override are returned.","type":"array","items":{"type":"object"}},"seasonal_min_stay":{"description":"Seasonal minimum nights rules.","type":"array","items":{"type":"object"}},"new_listing_promotion":{"description":"Whether the Airbnb new listing promotion is currently ongoing.","type":"boolean"},"high_rated_guest_discount":{"description":"Whether the Airbnb highly-rated guest discount (15% off for guests rated 4.8+ with at least 3 reviews) is currently enabled.","type":"boolean"},"mobile_only_discount":{"description":"Whether the Airbnb mobile-only discount (10% off for guests booking via the Airbnb mobile app) is currently enabled.","type":"boolean"},"eligible_cancellation_policies":{"description":"Cancellation policy categories this listing is eligible for; these are the valid values for `cancellation_policy` when updating.","type":"array","items":{"type":"string"}}}}}}]}}}}}},"post":{"summary":"Update Airbnb Listing Price and Rules","description":"Update the listing-level pricing, fees, booking settings and availability rules of an Airbnb listing. <br><br>Unlike the calendar endpoints, this updates the listing's default settings (not a specific date range). Only the fields you provide are updated; omit a field to leave it unchanged. <br><br>This request is processed synchronously against Airbnb: a successful response means the changes were accepted by Airbnb.","operationId":"update-airbnb-listing-price-and-rules","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"requestBody":{"description":"","required":true,"content":{"application\/json":{"schema":{"type":"object","required":["listing_id","settings"],"properties":{"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"settings":{"type":"object","description":"The settings to update. All fields are optional; only the provided fields are updated.","properties":{"listing_currency":{"description":"The listing currency code, e.g. `USD`.","type":"string"},"base_price":{"description":"The default nightly price.","type":"number"},"weekend_price":{"description":"The Friday and Saturday nightly price.","type":"number"},"security_deposit":{"description":"The security deposit amount.","type":"number"},"cleaning_fee":{"description":"The cleaning fee amount.","type":"number"},"short_term_cleaning_fee":{"description":"The short-term cleaning fee amount.","type":"number"},"pet_fee":{"description":"The pet fee amount. Mutually exclusive with `pet_fee_obj`.","type":"number","nullable":true},"pet_fee_obj":{"description":"The detailed pet fee. Mutually exclusive with `pet_fee`.","type":"object","nullable":true,"properties":{"amount":{"type":"number"},"charge_type":{"type":"string"},"charge_period":{"type":"string"}}},"extra_guest_fee":{"description":"The fee charged per extra guest.","type":"number"},"early_bird_discount":{"description":"Early bird discount. An object `{discount, days}` (or an array of such objects) where `discount` is a percentage (0-100) applied when booked at least `days` days ahead.","type":"object","properties":{"discount":{"type":"integer"},"days":{"type":"integer"}}},"last_minute_discount":{"description":"Last minute discount. An object `{discount, days}` (or an array of such objects) where `discount` is a percentage (0-100) applied when booked within `days` days of check-in.","type":"object","properties":{"discount":{"type":"integer"},"days":{"type":"integer"}}},"long_term_discount":{"description":"Long term discount. An object `{discount, days}` (or an array of such objects) where `discount` is a percentage (0-100) applied for stays of at least `days` nights.","type":"object","properties":{"discount":{"type":"integer"},"days":{"type":"integer"}}},"check_in_start_time":{"description":"Check-in start time. An integer hour 8-24, `25`\/`26` for 1am\/2am next day, or `FLEXIBLE`."},"check_in_end_time":{"description":"Check-in end time. An integer hour 9-26 (`25`\/`26` for 1am\/2am next day) or `FLEXIBLE`."},"check_out_before":{"description":"Check-out latest time, an integer hour 0-23.","type":"integer"},"instant_booking":{"description":"Whether instant booking is allowed.","type":"boolean"},"max_guests":{"description":"The number of guests included in the base price.","type":"integer"},"minimum_stay":{"description":"The default minimum number of nights.","type":"integer"},"maximum_stay":{"description":"The default maximum number of nights.","type":"integer"},"advance_notice":{"description":"Booking lead time in hours.","type":"integer"},"availability_window":{"description":"How far in advance (in days) the calendar is bookable.","type":"integer"},"preparation_time":{"description":"Turnover\/preparation days between reservations.","type":"integer"},"days_of_week_check_in":{"description":"Days of week (0=Sunday ... 6=Saturday) on which check-in IS allowed; the remaining days are blocked.","type":"array","items":{"type":"integer"}},"days_of_week_check_out":{"description":"Days of week (0=Sunday ... 6=Saturday) on which check-out IS allowed; the remaining days are blocked.","type":"array","items":{"type":"integer"}},"allow_rtb_above_max_nights":{"description":"Whether to allow request-to-book for stays exceeding the maximum nights.","type":"boolean"},"cancellation_policy":{"description":"The cancellation policy category."},"long_term_cancellation_policy":{"description":"The long-term-stay cancellation policy id."},"non_refundable_price_factor":{"description":"The non-refundable discount percentage (0-100). Stored as a price factor of `(100 - value) \/ 100`.","type":"number"},"day_of_week_min_nights":{"description":"Per-day-of-week minimum nights rule."},"seasonal_min_stay":{"description":"Seasonal minimum nights rules.","type":"array","items":{"type":"object"}},"new_listing_promotion":{"description":"Whether to enable the Airbnb new listing promotion.","type":"boolean"},"high_rated_guest_discount":{"description":"Whether to enable the Airbnb highly-rated guest discount (15% off for guests rated 4.8+ with at least 3 reviews).","type":"boolean"},"mobile_only_discount":{"description":"Whether to enable the Airbnb mobile-only discount (10% off for guests booking via the Airbnb mobile app).","type":"boolean"}}}}}}}},"responses":{"200":{"description":"The request has been successfully processed. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/listings\/vrbo\/price_and_rules":{"get":{"summary":"Get Vrbo Listing Price and Rules","description":"Get the pricing and rules of a Vrbo listing as currently recorded by Hostex. The data is the snapshot Hostex keeps in sync with Vrbo (updated when changes are made through Hostex or the listing is re-synced), not a real-time read from Vrbo. The response fields mirror the `settings` object accepted by `POST \/listings\/vrbo\/price_and_rules`.","operationId":"get-vrbo-listing-price-and-rules","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"parameters":[{"name":"listing_id","in":"query","description":"The Vrbo listing id.","required":true,"schema":{"$ref":"#\/components\/schemas\/ListingId"}}],"responses":{"200":{"description":"The current price and rules of the Vrbo listing.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"type":"object","properties":{"base_price":{"description":"The nightly price when all seven days share the same price; `null` when per-day prices differ (see `nightly_rate`).","type":"number","nullable":true},"nightly_rate":{"description":"Per-day-of-week nightly prices. `null` when all days share the same price (see `base_price`).","type":"object","nullable":true,"properties":{"sunday":{"type":"number"},"monday":{"type":"number"},"tuesday":{"type":"number"},"wednesday":{"type":"number"},"thursday":{"type":"number"},"friday":{"type":"number"},"saturday":{"type":"number"}}},"weekly_discount":{"description":"The weekly stay discount percentage (0-99).","type":"number","nullable":true},"monthly_discount":{"description":"The monthly stay discount percentage (0-99).","type":"number","nullable":true},"cleaning_fee":{"description":"The cleaning fee amount. `null` when no fee is set.","type":"number","nullable":true},"extra_guest_fee":{"description":"The fee charged per extra guest. `null` when no fee is set.","type":"number","nullable":true},"extra_guest_number":{"description":"The number of guests after which the extra guest fee applies.","type":"integer","nullable":true},"security_deposit":{"description":"The security deposit amount. `null` when no deposit is set.","type":"number","nullable":true},"check_in_start_time":{"description":"The earliest check-in time.","nullable":true},"check_out_before":{"description":"The latest check-out time.","nullable":true},"instant_booking":{"description":"Whether instant booking is allowed.","type":"boolean","nullable":true},"max_guests":{"description":"The maximum number of guests.","type":"integer","nullable":true},"minimum_stay":{"description":"The default minimum number of nights.","type":"integer","nullable":true},"advance_notice":{"description":"Booking lead time \/ advance notice.","type":"integer","nullable":true},"availability_window":{"description":"How far in advance the calendar is bookable.","type":"integer","nullable":true}}}}}]}}}}}},"post":{"summary":"Update Vrbo Listing Price and Rules","description":"Update the listing-level pricing, fees and booking rules of a Vrbo listing. <br><br>Unlike the calendar endpoints, this updates the listing's default settings (not a specific date range). Only the fields you provide are updated; omit a field to leave it unchanged. <br><br>This request is processed synchronously against Vrbo: a successful response means the changes were accepted by Vrbo.","operationId":"update-vrbo-listing-price-and-rules","tags":["Listing Calendar"],"security":[{"HostexAccessToken":[]}],"requestBody":{"description":"","required":true,"content":{"application\/json":{"schema":{"type":"object","required":["listing_id","settings"],"properties":{"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"settings":{"type":"object","description":"The settings to update. All fields are optional; only the provided fields are updated.","properties":{"base_price":{"description":"The default nightly price applied to every day of the week. Takes precedence over `nightly_rate` when both are provided.","type":"number"},"nightly_rate":{"description":"Per-day-of-week nightly prices. All seven days are required when provided.","type":"object","properties":{"sunday":{"type":"number"},"monday":{"type":"number"},"tuesday":{"type":"number"},"wednesday":{"type":"number"},"thursday":{"type":"number"},"friday":{"type":"number"},"saturday":{"type":"number"}}},"security_deposit":{"description":"The security deposit amount. `0` clears the deposit.","type":"number"},"cleaning_fee":{"description":"The cleaning fee amount. `0` clears the fee.","type":"number"},"extra_guest_fee":{"description":"The fee charged per extra guest. `0` clears the fee.","type":"number"},"extra_guest_number":{"description":"The number of guests after which the extra guest fee applies.","type":"integer"},"max_guests":{"description":"The maximum number of guests.","type":"integer"},"weekly_discount":{"description":"The weekly stay discount percentage (0-99).","type":"number"},"monthly_discount":{"description":"The monthly stay discount percentage (0-99).","type":"number"},"check_in_start_time":{"description":"The earliest check-in time."},"check_out_before":{"description":"The latest check-out time."},"instant_booking":{"description":"Whether instant booking is allowed.","type":"boolean"},"minimum_stay":{"description":"The default minimum number of nights.","type":"integer"},"advance_notice":{"description":"Booking lead time \/ advance notice.","type":"integer"},"availability_window":{"description":"How far in advance the calendar is bookable.","type":"integer"}}}}}}}},"responses":{"200":{"description":"The request has been successfully processed. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/calendar_share_links":{"get":{"summary":"Query Calendar Share Links","description":"List the operator's public calendar share links. Each link exposes a read-only calendar (and reservation list) of either every property (`scope = entire`) or a selected subset (`scope = partial`) and is reachable by anyone who has the URL.","operationId":"query-calendar-share-links","tags":["Calendar Share Links"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_calendar_share_links","description":"Search \/ paginate the operator's public calendar share links. Returns each link's id, scope (entire \/ partial), the property_ids it exposes (empty for entire-scope links) and the share URL. Use this to enumerate existing links before creating or deleting one.","intent_examples":["List my calendar share links","What calendar share links have I created","Show the share link for property 123"],"category":"calendar","read_only":true,"since_version":"3.5.0"},"parameters":[{"name":"offset","in":"query","description":"Pagination offset. Defaults to 0.","required":false,"schema":{"type":"integer","minimum":0}},{"name":"limit","in":"query","description":"Page size. Defaults to 20. Max 100.","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"id","in":"query","description":"Fetch a single share link by its internal id.","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["calendar_share_links","total"],"properties":{"total":{"type":"integer","description":"Total number of share links matching the filter."},"calendar_share_links":{"type":"array","items":{"$ref":"#\/components\/schemas\/CalendarShareLink"}}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Calendar Share Link","description":"Create a new public calendar share link. `scope = entire` exposes every property in the operator's account; `scope = partial` exposes only the properties listed in `property_ids`. Each operator can have at most one entire-scope link: requesting one when it already exists simply returns the existing link.","operationId":"create-calendar-share-link","tags":["Calendar Share Links"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_calendar_share_link","description":"Create a new public calendar share link. Pick `scope=entire` to expose all properties (idempotent: returns the existing link if any), or `scope=partial` plus `property_ids` to expose only specific properties. The returned `url` is a public, read-only calendar that the operator can hand off to cleaners, owners, or external collaborators.","intent_examples":["Create a shared calendar link for all my properties","Generate a share link for properties 101 and 102","Give me a public calendar link I can send to my cleaner"],"category":"calendar","read_only":false,"since_version":"3.5.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["scope"],"properties":{"scope":{"type":"string","enum":["entire","partial"],"description":"`entire` exposes every property of the operator; `partial` exposes only the ids listed in `property_ids`."},"property_ids":{"type":"array","items":{"type":"integer"},"description":"Required (non-empty) when `scope = partial`. Each id must reference a property owned by the operator."}}}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["calendar_share_link"],"properties":{"calendar_share_link":{"$ref":"#\/components\/schemas\/CalendarShareLink"}},"type":"object"}},"type":"object"}]}}}}}}},"\/calendar_share_links\/{id}":{"delete":{"summary":"Delete Calendar Share Link","description":"Permanently invalidate a calendar share link. The public URL will start returning a `share link invalid` error to anyone who tries to open it.","operationId":"delete-calendar-share-link","tags":["Calendar Share Links"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_calendar_share_link","description":"Permanently invalidate a public calendar share link. Anyone holding the previous URL will get a `share link invalid` error. Look up the link id via search_calendar_share_links first.","intent_examples":["Revoke calendar share link 42","Delete the calendar share link I sent to my cleaner"],"category":"calendar","read_only":false,"since_version":"3.5.0"},"parameters":[{"name":"id","in":"path","description":"Internal share link id (from `search_calendar_share_links`).","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reservations":{"get":{"summary":"Query Reservations","description":"You can query reservations by making a request to this endpoint.","operationId":"query-reservations","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_reservations","description":"Search reservations. Filter by reservation code, channel reservation id, property, status, check-in \/ check-out date range, etc. Returns a list of reservations including guest info, stay status, pricing, and channel. Common use cases: find reservations by date \/ property \/ status, or check whether a given reservation exists. By default returns reservations with `check_out` within the next 180 days.","intent_examples":["Reservations checking in next week","Which guests are checking out tomorrow","Unconfirmed reservations on Airbnb","All reservations for Coastal Villa this month"],"category":"reservation","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"reservation_code","in":"query","description":"Filters the results by the specified reservation code.","required":false,"schema":{"type":"string"}},{"name":"channel_id","in":"query","description":"Filters the results by the reservation ID in the channel (matches the `channel_id` field returned in the response).","required":false,"schema":{"type":"string"}},{"name":"property_id","in":"query","description":"Filters the results by the specified property ID.","required":false,"schema":{"type":"integer"}},{"name":"status","in":"query","description":"Filters the results by the specified reservation status.","required":false,"schema":{"type":"string","enum":["wait_accept","wait_pay","accepted","cancelled","denied","timeout"]}},{"name":"start_check_in_date","in":"query","description":"Filters the results to include reservations with check-in dates starting from this date (inclusive).","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_check_in_date","in":"query","description":"Filters the results to include reservations with check-in dates up to this date (inclusive).","required":false,"schema":{"type":"string","format":"date"}},{"name":"start_check_out_date","in":"query","description":"Filters the results to include reservations with check-out dates starting from this date (inclusive). By default, reservations within 180 days are returned.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_check_out_date","in":"query","description":"Filters the results to include reservations with check-out dates up to this date (inclusive).","required":false,"schema":{"type":"string","format":"date"}},{"name":"order_by","in":"query","description":"Sorts the results by the specified field (always descending). Default is `booked_at`. `created_at` sorts by the row creation timestamp (i.e. when the reservation was first synced into Hostex).","required":false,"schema":{"type":"string","enum":["booked_at","check_in_date","check_out_date","cancelled_at","created_at"],"default":"booked_at"}},{"name":"channel_type","in":"query","description":"Filters the results by the specified channel type.","required":false,"schema":{"$ref":"#\/components\/schemas\/ChannelType"}},{"name":"offset","in":"query","description":"Specifies the starting index from which the results should be returned. Default: 0","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"Determines the maximum number of results to be returned, up to a maximum of 100. Default: 20.","required":false,"schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["reservations"],"properties":{"reservations":{"description":"List of the properties","type":"array","items":{"type":"object","required":["reservation_code","stay_code","property_id","channel_id","channel_type","listing_id","check_in_date","check_out_date","number_of_guests","status","booked_at","created_at"],"properties":{"reservation_code":{"type":"string","description":"The reservation code. Multiple stays are allowed for the same reservation. In the case of multiple stays, all stays will share the same reservation code. For example: `0-1234567-abcdef`"},"stay_code":{"type":"string","description":"The stay code of the reservation. For example: `0-1234567-abcdef` or `0-1234567_1-abcdef`(if there are multiple stays for the same reservation)"},"channel_id":{"type":"string","description":"The reservation ID in the channel."},"property_id":{"type":"integer","description":"The property ID. If an reservation fails to be allocated to a property, `0` will be returned."},"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"check_in_date":{"type":"string","format":"date","description":"The check-in date of the reservation in YYYY-MM-DD format. Example: `2019-01-01`"},"check_out_date":{"type":"string","format":"date","description":"The check-out date of the reservation in YYYY-MM-DD format. Example: `2019-01-01`"},"number_of_guests":{"type":"integer","description":"The total number of guests for the reservation"},"number_of_adults":{"type":"integer","description":"The number of adults for the reservation"},"number_of_children":{"type":"integer","description":"The number of children for the reservation"},"number_of_infants":{"type":"integer","description":"The number of infants for the reservation"},"number_of_pets":{"type":"integer","description":"The number of pets for the reservation"},"status":{"type":"string","enum":["wait_accept","wait_pay","accepted","cancelled","denied","timeout"]},"guest_name":{"type":"string","nullable":true,"description":"The default name of the guest. If it has been modified, it may differ from the name in the `guests`."},"guest_phone":{"type":"string","nullable":true,"description":"The default phone of the guest. If it has been modified, it may differ from the name in the `guests`."},"guest_email":{"type":"string","nullable":true,"description":"The default email of the guest. If it has been modified, it may differ from the name in the `guests`."},"cancelled_at":{"type":"string","format":"date-time","nullable":true,"description":"The datetime when the reservation was cancelled, `null` will be returned if the reservation is not cancelled in ISO 8601 format. Example: `2019-01-01T00:00:00+00:00`"},"booked_at":{"type":"string","format":"date-time","description":"The datetime when the reservation was booked in ISO 8601 format. Example: `2019-01-01T00:00:00+00:00`"},"created_at":{"type":"string","format":"date-time","description":"The datetime when the reservation was created in Hostex in ISO 8601 format. Example: `2019-01-01T00:00:00+00:00`"},"creator":{"type":"string","description":"The creator name of the reservation"},"rates":{"type":"object","properties":{"total_rate":{"type":"object","description":"The order rate includes commission.","properties":{"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"amount":{"type":"number"}}},"total_commission":{"type":"object","description":"The total commission of the order.","properties":{"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"amount":{"type":"number"}}},"rate":{"type":"object","description":"The reservation rate includes commission.","properties":{"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"amount":{"type":"number"}}},"commission":{"type":"object","description":"The commission of the reservation (if it is a multi-reservation order, the amount is allocated from the order commission).","properties":{"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"amount":{"type":"number"}}},"tax":{"type":"object","nullable":true,"description":"The taxes of the reservation. `null` will be returned if the reservation has no taxes.","properties":{"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"amount":{"type":"number"}}},"details":{"type":"array","description":"The rate details of the reservation","items":{"type":"object","properties":{"type":{"type":"string","description":"The type of the rate detail"},"description":{"type":"string","description":"The description of the rate detail"},"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"amount":{"type":"number"}}}}}},"payment":{"type":"object","description":"The payment collection status of the reservation, computed the same way as the Received \/ Unreceived status shown in the Hostex web app. Settlement is calculated at the order level, so all stays sharing the same `reservation_code` carry identical `payment` values \u2014 do not sum them across stays. Most meaningful for Hostex Direct (manually created) reservations where income is recorded against the order via `POST \/transactions`; channel-collected reservations may report `unreceived` if no income has been recorded in Hostex.","properties":{"currency":{"type":"string","description":"The currency code for the payment amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"total_amount":{"type":"number","description":"The amount expected to be received for the order (the settlement basis used for the Received \/ Unreceived status)."},"received_amount":{"type":"number","description":"The amount already received, i.e. the sum of recorded house-fee income for the order."},"balance_amount":{"type":"number","description":"The amount still outstanding (`total_amount - received_amount`, never negative). `0` when fully or over collected."},"status":{"type":"string","enum":["unreceived","partial","received","over_received"],"description":"The collection status: `unreceived` (nothing received), `partial` (received less than expected), `received` (fully settled), `over_received` (received more than expected)."}}},"check_in_details":{"type":"object","description":"The check-in details of the reservation","properties":{"arrival_at":{"type":"object","nullable":true,"description":"The arrival time of the reservation. If not specified, `null` will be returned.","properties":{"hour":{"type":"integer"},"minute":{"type":"integer"}}},"departure_at":{"type":"object","nullable":true,"description":"The departure time of the reservation. If not specified, `null` will be returned.","properties":{"hour":{"type":"integer"},"minute":{"type":"integer"}}},"lock_code":{"type":"string","nullable":true,"description":"The lock code of the reservation. If not specified, `null` will be returned."},"lock_code_visible_after":{"type":"string","description":"The lock code will be visible after this time, formatted as `HH:mm`."},"deposit":{"type":"number","description":"The deposit amount in the host's currency. For example, if the currency is USD, 100 means 100 US Dollars."},"id_required":{"type":"string","description":"Whether the guest must register \/ upload identity documents (ID) for this stay before check-in. Defaults to `not_required` when no setting has been applied.","enum":["not_required","required","required_with_review"]},"check_in_guide_url":{"type":"string","description":"The check-in guide URL."}}},"remarks":{"type":"string","description":"Remarks from the [Hostex Host Portal](https:\/\/hostex.io\/app\/reservations)"},"channel_remarks":{"type":"string","description":"Remarks from the channel"},"conversation_id":{"type":"string","description":"The conversation ID of the reservation. If not specified, `null` will be returned."},"tags":{"type":"array","description":"Tags from the [Hostex Host Portal](https:\/\/hostex.io\/app\/reservations)","items":{"type":"string"}},"custom_channel":{"type":"object","description":"Custom channels created from the [Custom Options Page](https:\/\/hostex.io\/app\/settings\/custom-options). See [Query Custom Channel](\/reference\/query-custom-channels) for retrieving custom channels.","required":["id","name"],"properties":{"id":{"type":"integer"},"name":{"type":"string"}}},"guests":{"type":"array","description":"In some special cases (e.g., the host manually deleted the guest information), the guests field may return an empty array, so you need to handle the empty case.","items":{"type":"object","properties":{"id":{"type":"integer","description":""},"name":{"type":"string","nullable":true,"description":""},"phone":{"type":"string","nullable":true,"description":""},"email":{"type":"string","nullable":true,"description":""},"id_type":{"type":"string","nullable":true,"description":"","enum":["passport","id_card","others"]},"id_number":{"type":"string","nullable":true,"description":""},"gender":{"type":"string","nullable":true,"description":"","enum":["male","female"]},"country":{"type":"string","nullable":true,"description":"ISO 3166-1 Alpha-2"},"is_booker":{"type":"boolean","description":"Used to determine whether it is the booker of the reservation."},"id_images":{"type":"array","description":"ID document images uploaded for this guest. Returns an empty array when no image has been uploaded.","items":{"type":"object","properties":{"id":{"type":"integer","description":"Internal ID of the image record."},"url":{"type":"string","nullable":true,"description":"Extra-large variant URL of the uploaded image, served by the image CDN."}}}}}}},"custom_fields":{"description":"Custom fields.","nullable":true,"type":"object"},"in_reservation_box":{"description":"Whether the reservation is in the reservation box.","type":"boolean"},"additional_fees":{"type":"array","description":"Additional fees parsed from `channel_remarks` (e.g., city tax, tourist tax). Currently only available for some channels (e.g., Booking.com) that include an `Additional Fee:` line in the channel remark. Returns an empty array when no additional fees can be parsed.","items":{"type":"object","properties":{"name":{"type":"string","description":"The name of the additional fee item, as provided by the channel (may be in the channel's locale, e.g., `imposto municipal`)."},"currency":{"type":"string","description":"The currency code of the additional fee, inherited from the reservation rate. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"amount":{"type":"number","description":"The amount of the additional fee in the specified currency."}}}},"checkin_guide_images":{"type":"array","description":"ID document images uploaded by guests through the online check-in guide for this reservation. Includes all images submitted on the reservation, even those not yet linked to a guest record (in which case `client_id` is `null`). Returns an empty array when no images have been uploaded.","items":{"type":"object","properties":{"id":{"type":"integer","description":"Internal ID of the image record."},"client_id":{"type":"integer","nullable":true,"description":"ID of the guest this image is linked to. `null` if the image has not been associated with a guest yet."},"url":{"type":"string","nullable":true,"description":"Extra-large variant URL of the uploaded image, served by the image CDN."}}}}}}}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Reservation","description":"Create a reservation (Direct Booking) in Hostex.","operationId":"create-reservation","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_reservation","description":"Create a Direct Booking reservation, bypassing any OTA channel. Requires property id, check-in \/ check-out dates, guest name & contact, pricing, etc. A direct booking is treated as a full reservation in the system and supports the complete payment \/ receipt flow. Note: this endpoint cannot be used to record Airbnb \/ Booking \/ etc. channel reservations (those are synced in from each channel).","intent_examples":["Create a direct booking at Coastal Villa #1, May 20-22, guest John, 3 pax, $600","Record a direct booking for a returning customer"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["property_id","custom_channel_id","check_in_date","check_out_date","guest_name","currency","rate_amount","commission_amount","received_amount","income_method_id"],"properties":{"property_id":{"type":"integer","description":"The id of the property for the reservation."},"custom_channel_id":{"type":"integer","description":"The id of the custom channel through which the reservation is booked. See [Query Custom Channel](\/reference\/query-custom-channels) for retrieving custom channels."},"check_in_date":{"type":"string","format":"date","description":"The check-in date for the reservation in YYYY-MM-DD format."},"check_out_date":{"type":"string","format":"date","description":"The check-out date for the reservation in YYYY-MM-DD format."},"number_of_guests":{"type":"integer","description":"The total number of guests included in the reservation."},"guest_name":{"type":"string","description":"The name of the primary guest."},"email":{"type":"string","description":"The email address of the primary guest."},"mobile":{"type":"string","description":"The mobile phone number of the primary guest."},"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"rate_amount":{"type":"integer","description":"The total rate amount for the reservation."},"commission_amount":{"type":"integer","description":"The commission amount for the reservation."},"received_amount":{"type":"integer","description":"The total amount received for the reservation."},"income_method_id":{"type":"integer","description":"The identifier for the income method used for the reservation payment. See [Query Income methods](\/reference\/query-income-methods) for retrieving all income methods."},"remarks":{"type":"string","description":"Any additional remarks related to the reservation."}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reservations\/{reservation_code}":{"delete":{"summary":"Cancel Reservation","description":"Cancel a direct booking reservation in Hostex. Note that this endpoint does not support the cancellation of channel bookings.","operationId":"cancel-reservation","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"cancel_reservation","description":"Cancel a Direct Booking reservation. \u26a0\ufe0f Irreversible and will immediately release the property's occupancy. This endpoint only supports cancelling direct bookings \u2014 channel reservations (Airbnb \/ Booking \/ Agoda, etc.) must be cancelled on the channel side. A wrong cancellation may leave the guest without a room and trigger refund disputes.","intent_examples":["Cancel reservation ABC123","The guest isn't coming \u2014 cancel this direct booking"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"reservation_code","in":"path","description":"The code of the reservation.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reservations\/{stay_code}":{"patch":{"summary":"Update Reservation Basic Info","description":"Update basic information of a stay including guest details, dates, pricing, and other attributes.","operationId":"update-reservation-basic-info","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_reservation_basic","description":"Update a reservation's basic info: guest name \/ phone \/ email, check-in \/ check-out dates, party size, pricing, remarks (`remarks` \/ `channel_remarks`), etc. Common use cases: edit remarks, update the guest's contact info, change dates. Note: changing dates can create conflicts with other reservations \u2014 verify before calling.","intent_examples":["Change the remarks on reservation ABC123 to 'Deposit collected'","Change this reservation to check in May 20 through 22","Update the guest's phone number"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"remarks":{"type":"string","description":"Remarks for the reservation.","maxLength":500},"creator":{"type":"string","description":"The account of the creator.","maxLength":50},"custom_channel_id":{"type":"integer","description":"The id of the custom channel."},"check_in_date":{"type":"string","format":"date","description":"The check-in date for the reservation in YYYY-MM-DD format."},"check_out_date":{"type":"string","format":"date","description":"The check-out date for the reservation in YYYY-MM-DD format."},"number_of_guests":{"type":"integer","description":"The total number of guests.","minimum":1,"maximum":99},"guest_name":{"type":"string","description":"The name of the primary guest.","maxLength":100},"mobile":{"type":"string","description":"The mobile phone number of the guest.","maxLength":50},"email":{"type":"string","format":"email","description":"The email address of the guest."},"currency":{"type":"string","description":"The currency code for the reservation amounts. See [Supported Currencies](\/reference\/supported-currencies) for more information."},"rate_amount":{"type":"number","description":"The total rate amount for the reservation.","minimum":0,"maximum":999999},"commission_amount":{"type":"number","description":"The commission amount for the reservation.","minimum":0,"maximum":999999}}}}}},"responses":{"200":{"description":"The request has been successfully submitted.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reservations\/{stay_code}\/check_in_details":{"patch":{"summary":"Update Check-in Details","description":"Update check-in details for a stay including lock code, arrival\/departure times, and deposit information.","operationId":"update-check-in-details","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_reservation_checkin_details","description":"Update a reservation's check-in details: lock code, expected arrival \/ departure time, deposit info, etc. Common use cases: set the door-lock code in the admin before the guest arrives, record the expected arrival time so cleaning can be scheduled. This endpoint does NOT notify the guest \u2014 pair with `send_message` if the guest needs to be informed.","intent_examples":["Set the lock code for reservation ABC123 to 6688","Note that the guest will arrive at 14:00"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"lock_code":{"type":"string","nullable":true,"description":"The lock code for the property, stored only in Hostex and shown in the check-in guide. This field is independent of any smart-lock channel integration and is NOT pushed to external smart-lock providers. Set to null to remove the lock code."},"lock_code_visible_after":{"type":"string","nullable":true,"pattern":"^\\d\\d:\\d\\d$","description":"The time after which the lock code becomes visible, in HH:mm format (24-hour). Example: '14:00'. Set to null to remove the restriction."},"arrival_at":{"type":"object","nullable":true,"description":"The expected arrival time. Set to null to remove the arrival time.","properties":{"hour":{"type":"integer","minimum":0,"maximum":23,"description":"Hour in 24-hour format (0-23)"},"minute":{"type":"integer","minimum":0,"maximum":59,"description":"Minute (0-59)"}},"required":["hour","minute"]},"departure_at":{"type":"object","nullable":true,"description":"The expected departure time. Set to null to remove the departure time.","properties":{"hour":{"type":"integer","minimum":0,"maximum":23,"description":"Hour in 24-hour format (0-23)"},"minute":{"type":"integer","minimum":0,"maximum":59,"description":"Minute (0-59)"}},"required":["hour","minute"]},"deposit":{"type":"integer","minimum":0,"description":"The deposit amount in the host's currency. For example, if the currency is USD, 100 means 100 US Dollars."},"id_required":{"type":"string","description":"Whether the guest must register \/ upload identity documents (ID) for this stay before check-in. `not_required` = no ID required; `required` = guest must upload an ID, no manual review; `required_with_review` = guest must upload an ID and the host needs to manually review and approve it before check-in is unlocked.","enum":["not_required","required","required_with_review"]}}}}}},"responses":{"200":{"description":"The request has been successfully submitted.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/custom_channels":{"get":{"summary":"Query Custom Channels","description":"Query custom channels created from the [Custom Options Page](https:\/\/hostex.io\/app\/settings\/custom-options).","operationId":"query-custom-channels","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_custom_channels","description":"List the operator's custom channels (channels the operator defines themselves \u2014 e.g. WhatsApp, Facebook Messenger, returning-customer direct \u2014 on top of the built-in Airbnb \/ Booking \/ etc.). Returns each channel's id and name. Call this first when you need a `custom_channel_id` for `create_reservation` \/ `update_reservation_basic`.","intent_examples":["What custom channels do I have","What is the id of the WhatsApp channel"],"category":"meta","read_only":true,"since_version":"3.4.0"},"parameters":[],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["custom_channels"],"properties":{"custom_channels":{"description":"List of the custom channels","type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","description":"The id of the custom channel."},"name":{"type":"string","description":"The name of the custom channel."}}}}},"type":"object"}},"type":"object"}]}}}}}}},"\/transactions":{"get":{"summary":"Query Incomes & Expenses","description":"Query income and expense entries (also known as `transactions`) recorded against the operator, properties or reservations.\n\nThe response provides each entry with its categorization (`item_id` \/ `item_name`) and payment method (`payment_method_id` \/ `payment_method_name`). The values of `item_id` and `payment_method_id` reference the dictionaries returned by `GET \/income_items`, `GET \/expense_items`, `GET \/income_methods` and `GET \/expense_methods` (which dictionary applies depends on `direction`).","operationId":"query-transactions","tags":["Incomes & Expenses"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_transactions","description":"Query transaction entries (income \/ expense ledger). Filter by direction (`income` \/ `expense`), linked reservation (`stay_code`), linked property (`property_id`), date range, etc.; or pass `id` directly to fetch a single entry. Returns each entry's amount, currency, item (`item_id` \/ `item_name`), payment method, and linked object. `start_date` \/ `end_date` are optional when filtering by `id`.","intent_examples":["All income this month","Expenses for Coastal Villa #1 this month","All transactions related to reservation ABC123","Show me the details of transaction 12345"],"category":"finance","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"query","description":"Internal id of a specific transaction entry. When supplied, returns at most one matching entry under the current operator; `start_date` and `end_date` may then be omitted.","required":false,"schema":{"type":"integer"}},{"name":"start_date","in":"query","description":"Start of the action time range, inclusive. Format `YYYY-MM-DD`. Interpreted in the operator's configured timezone. Required unless `id` is supplied.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_date","in":"query","description":"End of the action time range, inclusive. Format `YYYY-MM-DD`. Interpreted in the operator's configured timezone. The range from `start_date` to `end_date` cannot exceed 366 days. Required unless `id` is supplied.","required":false,"schema":{"type":"string","format":"date"}},{"name":"offset","in":"query","description":"The starting point from which to begin returning results.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100.","required":false,"schema":{"type":"integer","default":20}},{"name":"property_id","in":"query","description":"Filter entries linked to the given property id (either directly recorded against the property, or indirectly through a reservation on this property).","required":false,"schema":{"type":"integer"}},{"name":"stay_code","in":"query","description":"Filter entries linked to the given stay (the `stay_code` returned by `GET \/reservations`).","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Filter by direction: `income` for money received, `expense` for money spent.","required":false,"schema":{"type":"string","enum":["income","expense"]}},{"name":"item_id","in":"query","description":"Filter by item id (the categorization of the entry). For income entries the id refers to `GET \/income_items`; for expense entries it refers to `GET \/expense_items`.","required":false,"schema":{"type":"integer"}},{"name":"payment_method_id","in":"query","description":"Filter by payment method id. For income entries the id refers to `GET \/income_methods`; for expense entries it refers to `GET \/expense_methods`.","required":false,"schema":{"type":"integer"}},{"name":"currency","in":"query","description":"Filter by currency code. See [Supported Currencies](\/reference\/supported-currencies) for more information.","required":false,"schema":{"type":"string"}},{"name":"keyword","in":"query","description":"Substring match on the entry `note`.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A list of transaction entries with their details.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["transactions","total"],"properties":{"transactions":{"description":"List of transaction entries.","type":"array","items":{"type":"object","required":["id","direction","amount","currency"],"properties":{"id":{"description":"Unique identifier of the transaction entry.","type":"integer","format":"int64"},"direction":{"description":"Whether the entry represents money received (`income`) or spent (`expense`).","type":"string","enum":["income","expense"]},"amount":{"description":"Absolute amount of the entry, always non-negative; use `direction` to distinguish income from expense.","type":"number"},"currency":{"description":"The currency code of the entry. See [Supported Currencies](\/reference\/supported-currencies) for more information.","type":"string"},"status":{"description":"Payment status of the entry.","type":"string","enum":["paid","outstanding"]},"action_at":{"description":"When the action took place, in ISO 8601 (UTC).","type":"string","nullable":true},"item_id":{"description":"The id of the item categorization. References `GET \/income_items` when `direction` is `income`, or `GET \/expense_items` when `direction` is `expense`.","type":"integer","nullable":true},"item_name":{"description":"Human-readable name of the item, resolved against the item dictionary at the time of the request. May be a localized name for system-default items, or the operator's custom name.","type":"string","nullable":true},"payment_method_id":{"description":"The id of the payment method. References `GET \/income_methods` when `direction` is `income`, or `GET \/expense_methods` when `direction` is `expense`.","type":"integer","nullable":true},"payment_method_name":{"description":"Human-readable name of the payment method.","type":"string","nullable":true},"note":{"description":"Free-form note attached to the entry.","type":"string"},"operator_name":{"description":"Display name of the user who created the entry, or `System` for entries created by automated processes.","type":"string"},"link_type":{"description":"What the entry is linked to: `property` (a specific property), `reservation` (a specific stay), or `operator` (the operator account, not tied to any property or reservation).","type":"string","enum":["property","reservation","operator"]},"property_id":{"description":"Id of the related property, if any. For reservation-linked entries this resolves to the stay's property; for property-linked entries this is the property itself; null for operator-linked entries.","type":"integer","nullable":true},"property_title":{"description":"Title of the related property.","type":"string","nullable":true},"stay_code":{"description":"The `stay_code` of the stay the entry is linked to. Null when not linked to a reservation.","type":"string","nullable":true},"created_at":{"description":"When the entry was created, in ISO 8601 (UTC).","type":"string","nullable":true},"updated_at":{"description":"When the entry was last updated, in ISO 8601 (UTC).","type":"string","nullable":true}}}},"total":{"description":"Total number of entries matching the filters.","type":"integer"}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Transaction","description":"Record a new income or expense entry. What the entry is linked to is inferred from the request:\n- provide `stay_code` to record an entry against a specific stay,\n- provide `property_id` to record an entry against a specific property,\n- provide neither to record an operator-level entry (not tied to any specific property or stay; only available to the master operator).\n\n`stay_code` and `property_id` are mutually exclusive.\n\nThe `direction` field decides whether the entry is an `income` or an `expense`, which in turn determines which dictionaries are used for `item_id` (`GET \/income_items` or `GET \/expense_items`) and `payment_method_id` (`GET \/income_methods` or `GET \/expense_methods`). The `amount` is always provided as a positive number; the sign is derived from `direction`. The `currency` accompanies the amount and must be supplied unless `stay_code` is provided, in which case it is inherited from the reservation order and, if you do provide it, it must match the order's currency.","operationId":"create-transaction","tags":["Incomes & Expenses"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_transaction","description":"Record an income or expense entry (bookkeeping). Required: `direction` (`income` \/ `expense`) + `amount` (positive number) + `item_id` + `payment_method_id`. Can be linked to a reservation (`stay_code`) or to a property (`property_id`), but not both; omit both to record an operator-level entry (master account only). When `stay_code` is supplied, `currency` is inherited from the reservation; otherwise `currency` is required. Look up `item_id` \/ `payment_method_id` via `GET \/income_items`, `\/expense_items`, `\/income_methods`, `\/expense_methods`.","intent_examples":["Record a $200 cleaning expense for reservation ABC123","Log that we received a $500 deposit from the guest","Coastal Villa spent $1500 on maintenance this month"],"category":"finance","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["direction","amount","item_id","payment_method_id"],"properties":{"property_id":{"description":"The id of the property to record the entry against. Mutually exclusive with `stay_code`. Omit both to record an operator-level entry.","type":"integer"},"stay_code":{"description":"The `stay_code` (returned by `GET \/reservations`) of the stay to record the entry against. Mutually exclusive with `property_id`. Omit both to record an operator-level entry.","type":"string"},"direction":{"description":"Whether this entry represents money received (`income`) or money spent (`expense`).","type":"string","enum":["income","expense"]},"amount":{"description":"Absolute amount of the entry. Always provide a positive value; the sign is derived from `direction`.","type":"number"},"currency":{"description":"Currency code that accompanies `amount`. Required unless `stay_code` is provided; reservation-linked entries inherit the currency from the order and reject mismatching values. See [Supported Currencies](\/reference\/supported-currencies) for more information.","type":"string"},"item_id":{"description":"The id of the item categorization. Must be a valid id from `GET \/income_items` when `direction=income`, or from `GET \/expense_items` when `direction=expense`.","type":"integer"},"payment_method_id":{"description":"The id of the payment method. Must be a valid id from `GET \/income_methods` when `direction=income`, or from `GET \/expense_methods` when `direction=expense`.","type":"integer"},"action_at":{"description":"When the action took place. Accepts ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). Defaults to the current time. If set to a future time the entry is created with status `outstanding`; otherwise it is `paid`.","type":"string"},"note":{"description":"Free-form note (max 500 characters).","type":"string"}}}}}},"responses":{"200":{"description":"The transaction entry has been successfully created.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["transaction_id"],"properties":{"transaction_id":{"description":"Unique identifier of the newly created transaction entry.","type":"integer","format":"int64"}},"type":"object"}},"type":"object"}]}}}}}}},"\/transactions\/{id}":{"patch":{"summary":"Update Transaction","description":"Update an existing transaction entry. Only the fields listed below can be modified. The entry's `direction`, link target (related property \/ reservation \/ operator) and `currency` are immutable; if you need to change any of these, delete the entry and create a new one.","operationId":"update-transaction","tags":["Incomes & Expenses"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_transaction","description":"Update an existing transaction entry. Only `amount` \/ `item_id` \/ `payment_method_id` \/ `action_at` \/ `note` and similar fields can be changed; `direction` (income \/ expense), the linked object (reservation \/ property \/ operator-level), and `currency` are immutable \u2014 to change those, `delete_transaction` and re-create with `create_transaction`.","intent_examples":["Change this expense amount to 320","Update the note on this transaction"],"category":"finance","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"path","description":"Id of the transaction entry returned by `GET \/transactions` or `POST \/transactions`.","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"amount":{"description":"New absolute amount. Always provide a positive value; the original `direction` (income or expense) is preserved.","type":"number"},"item_id":{"description":"New item categorization id. Must be a valid id from `GET \/income_items` when the entry's direction is `income`, or `GET \/expense_items` when it is `expense`.","type":"integer"},"payment_method_id":{"description":"New payment method id. Must be a valid id from `GET \/income_methods` when the entry's direction is `income`, or `GET \/expense_methods` when it is `expense`.","type":"integer"},"action_at":{"description":"New action time. Accepts ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`).","type":"string"},"note":{"description":"New free-form note (max 500 characters).","type":"string"}}}}}},"responses":{"200":{"description":"The transaction entry has been successfully updated.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"delete":{"summary":"Delete Transaction","description":"Delete a transaction entry. The operation is irreversible. Returns 404 if the entry does not exist or is not accessible to the current operator.","operationId":"delete-transaction","tags":["Incomes & Expenses"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_transaction","description":"Permanently delete a transaction entry. \u26a0\ufe0f Irreversible \u2014 deleting will affect the cumulative income \/ expense totals for the linked property \/ reservation \/ operator. If only the amount is wrong, use `update_transaction` instead of deleting.","intent_examples":["Delete this expense entry \u2014 it was recorded incorrectly"],"category":"finance","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"path","description":"Id of the transaction entry to delete.","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"The transaction entry has been successfully deleted.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/income_items":{"get":{"summary":"Query Income Items","description":"Query the dictionary of income item categorizations available to the operator. The returned `id` matches the `item_id` returned by `GET \/transactions` for entries with `direction=income`.","operationId":"query-income-items","tags":["Incomes & Expenses"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_income_items","description":"List all available income item categories (room fee, deposit, cleaning fee, etc.). Returns each item's id and name. Required: call this before `create_transaction` with `direction=income` to obtain a valid `item_id`.","intent_examples":["What income categories are available","Which `item_id` should I use to log a deposit"],"category":"finance","read_only":true,"since_version":"3.4.0"},"parameters":[],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["income_items"],"properties":{"income_items":{"description":"List of income items.","type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","description":"The id of the income item."},"name":{"type":"string","description":"The name of the income item."}}}}},"type":"object"}},"type":"object"}]}}}}}}},"\/expense_items":{"get":{"summary":"Query Expense Items","description":"Query the dictionary of expense item categorizations available to the operator. The returned `id` matches the `item_id` returned by `GET \/transactions` for entries with `direction=expense`.","operationId":"query-expense-items","tags":["Incomes & Expenses"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_expense_items","description":"List all available expense item categories (cleaning, maintenance, linen, platform commission, etc.). Returns each item's id and name. Required: call this before `create_transaction` with `direction=expense` to obtain a valid `item_id`.","intent_examples":["What expense categories are available","Which `item_id` should I use for maintenance fees"],"category":"finance","read_only":true,"since_version":"3.4.0"},"parameters":[],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["expense_items"],"properties":{"expense_items":{"description":"List of expense items.","type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","description":"The id of the expense item."},"name":{"type":"string","description":"The name of the expense item."}}}}},"type":"object"}},"type":"object"}]}}}}}}},"\/income_methods":{"get":{"summary":"Query Income Methods","description":"Query the dictionary of payment methods available to the operator for income entries. The returned `id` matches the `payment_method_id` returned by `GET \/transactions` for entries with `direction=income`.","operationId":"query-income-methods","tags":["Incomes & Expenses"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_income_methods","description":"List all available income payment methods (cash, bank transfer, Stripe, PayPal, etc.). Returns each method's id and name. Required: call this before `create_transaction` with `direction=income` to obtain a valid `payment_method_id`.","intent_examples":["What income payment methods are available","Which `payment_method_id` should I use to log a cash receipt"],"category":"finance","read_only":true,"since_version":"3.4.0"},"parameters":[],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["income_methods"],"properties":{"income_methods":{"description":"List of income methods.","type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","description":"The id of the income method."},"name":{"type":"string","description":"The name of the income method."}}}}},"type":"object"}},"type":"object"}]}}}}}}},"\/expense_methods":{"get":{"summary":"Query Expense Methods","description":"Query the dictionary of payment methods available to the operator for expense entries. The returned `id` matches the `payment_method_id` returned by `GET \/transactions` for entries with `direction=expense`.","operationId":"query-expense-methods","tags":["Incomes & Expenses"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_expense_methods","description":"List all available expense payment methods (cash, bank transfer, credit card, etc.). Returns each method's id and name. Required: call this before `create_transaction` with `direction=expense` to obtain a valid `payment_method_id`.","intent_examples":["What expense payment methods are available","Which `payment_method_id` should I use to log a cash expense"],"category":"finance","read_only":true,"since_version":"3.4.0"},"parameters":[],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["expense_methods"],"properties":{"expense_methods":{"description":"List of expense methods.","type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","description":"The id of the expense method."},"name":{"type":"string","description":"The name of the expense method."}}}}},"type":"object"}},"type":"object"}]}}}}}}},"\/reservations\/{stay_code}\/custom_fields":{"get":{"summary":"Query Custom Fields","description":"Query custom fields for a stay. For more information, please refer to the [Custom Fields Guide](\/reference\/custom-fields-guide).","operationId":"query-custom-fields","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_reservation_custom_fields","description":"Get the current definitions and values of a reservation's custom fields. Custom fields are defined by the operator in system settings to hold extra business-specific info (license plate, allergies, special requests, etc.). Call this first to obtain field ids and current values before invoking `update_reservation_custom_fields`.","intent_examples":["Show me all custom fields on reservation ABC123","What is the license-plate field on this reservation"],"category":"reservation","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["custom_fields"],"properties":{"custom_fields":{"description":"Custom fields.","nullable":true,"type":"object"}},"type":"object"}},"type":"object"}]}}}}}},"patch":{"summary":"Update Custom Fields","description":"Update custom fields for a stay. For more information, please refer to the [Custom Fields Guide](\/reference\/custom-fields-guide)","operationId":"update-custom-fields","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_reservation_custom_fields","description":"Update the values of a reservation's custom fields. Custom fields are defined by the operator in system settings to hold extra business-specific info (license plate, allergies, special requests, etc.). Recommended to call `search_reservation_custom_fields` first to fetch the field definitions and current values, then call this endpoint to update.","intent_examples":["Set the license-plate field on reservation ABC123 to CA-7XYZ123","Record that this guest is allergic to peanuts"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","description":"","properties":{"custom_fields":{"type":"object","description":"The custom fields to update. You can submit any field for creation, update, or deletion. Field values must be of type string. If the field does not exist, it will be created; if it exists, it will be updated. To delete a field, set its value to null.","properties":{"online_checkin_url":{"type":"string","nullable":true,"description":"This is just an example."}}}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["custom_fields"],"properties":{"custom_fields":{"description":"Custom fields.","nullable":true,"type":"object"}},"type":"object"}},"type":"object"}]}}}}}}},"\/reservations\/{reservation_code}\/approve":{"post":{"summary":"Approve Reservation","description":"Approve a pending reservation request. The reservation must be in `wait_accept` status. This endpoint communicates with the channel to confirm the booking.","operationId":"approve-reservation","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"approve_reservation","description":"Approve a reservation that is pending host confirmation (`status=wait_accept`). The system will call the channel to confirm the reservation and the guest will be notified that the host accepted. \u26a0\ufe0f Irreversible. Only works on reservations in `wait_accept` status (i.e. channel reservations where the guest sent a booking request waiting for host approval \u2014 mainly Airbnb 'Request to Book' and similar). Calls against already-confirmed or cancelled reservations will fail.","intent_examples":["Approve reservation ABC123","Accept this guest's booking request"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"reservation_code","in":"path","description":"The code of the reservation.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The reservation has been successfully approved.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}},"400":{"description":"The reservation is not in pending status, the account authorization has been revoked, or the account is disconnected."},"404":{"description":"The reservation or thirdparty account was not found."}}}},"\/reservations\/{reservation_code}\/decline":{"post":{"summary":"Decline Reservation","description":"Decline a pending reservation request. The reservation must be in `wait_accept` status. This endpoint communicates with the channel to reject the booking.","operationId":"decline-reservation","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"decline_reservation","description":"Decline a reservation that is pending host confirmation (`status=wait_accept`). \u26a0\ufe0f Irreversible; the guest will be notified that the host declined. Frequent declines can hurt the host's Acceptance Rate on Airbnb and similar channels. Only works on reservations in `wait_accept` status.","intent_examples":["Decline reservation ABC123","Reject this guest's booking request"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"reservation_code","in":"path","description":"The code of the reservation.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The reservation has been successfully declined.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}},"400":{"description":"The reservation is not in pending status, the account authorization has been revoked, or the account is disconnected."},"404":{"description":"The reservation or thirdparty account was not found."}}}},"\/reservations\/{stay_code}\/move_to_box":{"post":{"summary":"Move to Box","description":"Move a stay of the reservation to the reservation box. This action is typically used when you want to temporarily remove a reservation from the active calendar view.","operationId":"move-reservation-to-box","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"move_reservation_to_box","description":"Move a reservation's stay into the reservation box. Once in the box, the stay disappears from the master calendar view, but the reservation itself is NOT cancelled and the guest is NOT notified. Common use cases: temporarily set aside conflicting or anomalous reservations until they can be handled; later use `allocate_reservation` to reassign the stay to a specific property.","intent_examples":["Move reservation ABC123 to the reservation box for now","Tuck this conflicting reservation away"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay to move to the box.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The stay of the reservation has been successfully moved to the box.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reservations\/{stay_code}\/allocate":{"post":{"summary":"Allocate to Property","description":"Allocate a reservation to a specific property. This action is used to assign or reassign a reservation to a particular property. If there is already a stay for the target property, it will be marked as a conflicting stay and move to the reservation box.","operationId":"allocate-reservation","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"allocate_reservation","description":"Allocate \/ re-allocate a reservation's stay to a specific property. Typical scenarios: (1) a room-type reservation (sold by room type) needs to be assigned to a concrete property after booking; (2) reassign a conflicting reservation to another vacant property of the same room type. \u26a0\ufe0f If the target property already has a stay in the same date range, that stay will be marked as conflicting and moved to the reservation box.","intent_examples":["Assign reservation ABC123 to Coastal Villa #1","Move this reservation to Villa #2"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay to allocate.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["property_id"],"properties":{"property_id":{"type":"integer","description":"The ID of the property to allocate the reservation to."}}}}}},"responses":{"200":{"description":"The reservation has been successfully allocated to the property.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reservations\/{stay_code}\/stay_status":{"put":{"summary":"Update Stay Status","description":"Update the stay status of a reservation. This endpoint allows you to change the status of a stay between different states such as check-in pending, in-house, and stay completed.","operationId":"update-stay-status","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_reservation_stay_status","description":"Update a reservation's stay status (`stay_status`), e.g. `checkin_pending` (awaiting check-in) \u2192 `in_house` (checked in) \u2192 `stay_completed` (checked out). Common use case: manually process check-in \/ check-out.","intent_examples":["Mark this reservation as checked in","The guest has checked out \u2014 mark it","Check in ABC123"],"category":"reservation","read_only":false,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay to update.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["stay_status"],"properties":{"stay_status":{"type":"string","description":"The new status for the stay.","enum":["checkin_pending","in_house","stay_completed"]}}}}}},"responses":{"200":{"description":"The stay status has been successfully updated.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reservations\/{stay_code}\/tags":{"post":{"summary":"Add Tag","description":"Add a tag to a reservation. If the tag does not exist, it will be created automatically.","operationId":"add-tag","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"add_reservation_tag","description":"Add a tag to a reservation. If the tag does not exist it will be created automatically. Common use cases: flag VIP guests, problem reservations, reservations requiring special attention.","intent_examples":["Tag this reservation as VIP","Mark this reservation as 'pickup confirmed'"],"category":"reservation","read_only":false,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["tag_name"],"properties":{"tag_name":{"type":"string","description":"The name of the tag to add."}}}}}},"responses":{"200":{"description":"The tag has been successfully added to the reservation.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"delete":{"summary":"Remove Tag","description":"Remove a tag from a reservation.","operationId":"remove-tag","tags":["Reservations"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"remove_reservation_tag","description":"Remove a tag from a reservation.","intent_examples":["Remove the VIP tag from this reservation"],"category":"reservation","read_only":false,"since_version":"3.4.0"},"parameters":[{"name":"stay_code","in":"path","description":"The code of the stay.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["tag_name"],"properties":{"tag_name":{"type":"string","description":"The name of the tag to remove."}}}}}},"responses":{"200":{"description":"The tag has been successfully removed from the reservation.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reservation_tags":{"get":{"summary":"Query Reservation Tags","description":"List the operator's reservation tag dictionary. Includes both system default tags (`is_default = true`, shared across all operators) and the operator's own custom tags. These are the tags that `POST \/reservations\/{stay_code}\/tags` can attach to a reservation.","operationId":"query-reservation-tags","tags":["Reservation Tags"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_reservation_tags","description":"Search \/ paginate the operator's reservation tag dictionary. Returns each tag's id, tag_name, color and whether it is a system default tag. Use this to discover existing tag names (and their ids) before calling add_reservation_tag, or to enumerate tags for management UIs.","intent_examples":["List all my reservation tags","Do I already have a 'VIP' reservation tag","Search reservation tags containing 'cleaning'"],"category":"meta","read_only":true,"since_version":"3.5.0"},"parameters":[{"name":"offset","in":"query","description":"Pagination offset. Defaults to 0.","required":false,"schema":{"type":"integer","minimum":0}},{"name":"limit","in":"query","description":"Page size. Defaults to 20. Max 100.","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"id","in":"query","description":"Fetch a single tag by its internal id.","required":false,"schema":{"type":"integer","minimum":1}},{"name":"keyword","in":"query","description":"Case-insensitive substring match on `tag_name`.","required":false,"schema":{"type":"string","maxLength":50}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["reservation_tags","total"],"properties":{"total":{"type":"integer","description":"Total number of tags matching the filter."},"reservation_tags":{"type":"array","items":{"type":"object","required":["id","tag_name","color","is_default"],"properties":{"id":{"type":"integer","description":"Internal tag id."},"tag_name":{"type":"string","description":"Display name of the tag."},"color":{"type":"string","description":"Hex color string (e.g. `#FFA416`)."},"is_default":{"type":"boolean","description":"`true` for system default tags shared across all operators (cannot be deleted via this API)."}}}}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Reservation Tag","description":"Create a new reservation tag in the operator's dictionary. Color is auto-assigned from the Hostex palette. Names must be unique across both system default tags and the operator's own tags (a soft-deleted tag with the same name will be restored). Operators are capped at 500 tags.","operationId":"create-reservation-tag","tags":["Reservation Tags"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_reservation_tag","description":"Create a reservation tag in the operator's dictionary so it can later be attached to reservations via add_reservation_tag. Use this when the user wants to define a brand new tag (e.g. 'Pickup confirmed'). Note that add_reservation_tag will already auto-create a tag if it does not exist; prefer this endpoint only when the user explicitly wants to manage the dictionary itself.","intent_examples":["Create a reservation tag called 'Repeat guest'","Add 'Late check-in' to my reservation tag list"],"category":"reservation","read_only":false,"since_version":"3.5.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["tag_name"],"properties":{"tag_name":{"type":"string","maxLength":15,"description":"Tag display name. Max 15 characters."}}}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["reservation_tag"],"properties":{"reservation_tag":{"type":"object","required":["id","tag_name","color","is_default"],"properties":{"id":{"type":"integer"},"tag_name":{"type":"string"},"color":{"type":"string"},"is_default":{"type":"boolean"}}}},"type":"object"}},"type":"object"}]}}}}}}},"\/reservation_tags\/{id}":{"delete":{"summary":"Delete Reservation Tag","description":"Delete one of the operator's custom reservation tags. System default tags (`is_default = true`) cannot be deleted via this API and will return 404. Deleting a tag also removes it from any reservations it had been applied to.","operationId":"delete-reservation-tag","tags":["Reservation Tags"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_reservation_tag","description":"Permanently remove a reservation tag from the operator's dictionary. Only custom tags can be deleted (`is_default = false` from search_reservation_tags). Deletion also detaches the tag from every reservation it was applied to. Lookup the tag id via search_reservation_tags first.","intent_examples":["Delete the reservation tag 'Repeat guest'","Remove the 'Late check-in' tag from my tag list"],"category":"reservation","read_only":false,"since_version":"3.5.0"},"parameters":[{"name":"id","in":"path","description":"Internal tag id (from `search_reservation_tags`).","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/conversations":{"get":{"summary":"Query Conversations","description":"This endpoint is used to query the list of conversations regarding guest inquiries.","operationId":"query-conversations","tags":["Messages"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_conversations","description":"List conversation threads. A thread carries all messages with a given guest and may be linked to one or more reservations. Returns each thread's id, latest message preview, unread count, linked channel, etc. Common use cases: find a guest's thread to reply to, list recently active threads.","intent_examples":["Any unread messages recently","Where is the thread with John","All conversations on Airbnb"],"category":"messaging","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"offset","in":"query","description":"Specifies the starting index from which the results should be returned.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"Determines the maximum number of results to be returned, up to a maximum of 100.","required":false,"schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["conversations"],"properties":{"conversations":{"description":"List of the conversations","type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The id the conversation."},"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"last_message_at":{"type":"string","format":"date-time","description":"The datetime when the last message was created in ISO 8601 format. Example: `2019-01-01T00:00:00+00:00`"},"guest":{"type":"object","description":"The guest's information.","properties":{"name":{"type":"string","description":"The name of the guest."},"email":{"type":"string","description":"The email of the guest."},"phone":{"type":"string","description":"The phone of the guest."}}},"property_title":{"type":"string","description":"The title of property."},"check_in_date":{"type":"string","description":"The check-in date of the reservation."},"check_out_date":{"type":"string","description":"The check-out date of the reservation."}},"required":["id","channel_type","last_message_at","guest"]}}},"type":"object"}},"type":"object"}]}}}}}}},"\/conversations\/{conversation_id}":{"get":{"summary":"Get Conversation Details","description":"This endpoint is used to retrieve the messages and details of a conversation. <br><br>We are constantly improving our API which could mean that message schema may change. In order to maintain a healthy integration, your Application must parse and ignore unexpected parameters instead of throwing errors.","operationId":"get-conversation-details","tags":["Messages"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"get_conversation","description":"Get a single conversation's details and message list. Call `search_conversations` first to obtain a `conversation_id`. Returns each message's sender, content, timestamp, and attachments.","intent_examples":["Show me what we've discussed with this guest","Full chat history for this thread"],"category":"messaging","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"conversation_id","in":"path","description":"The id of the conversation.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["id","channel_type","guest","activities","messages"],"properties":{"id":{"type":"string","description":"The id of the conversation."},"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"guest":{"type":"object","description":"The guest's information.","properties":{"name":{"type":"string","description":"The name of the guest."},"phone":{"type":"string","description":"The phone of the guest."},"email":{"type":"string","description":"The email of the guest."}}},"activities":{"type":"array","description":"A list of activities associated with the conversation.","items":{"type":"object","properties":{"activity_type":{"type":"string","description":"The type of activity.","enum":["inquiry","reservation"]},"reservation_code":{"type":"string","nullable":true,"description":"The reservation code related to the activity, if applicable."},"check_in_date":{"type":"string","format":"date","nullable":true,"description":"The check-in date related to the activity."},"check_out_date":{"type":"string","format":"date","nullable":true,"description":"The check-out date related to the activity."},"listing_id":{"type":"string","nullable":true,"description":"The listing id related to the activity."},"property":{"type":"object","description":"Details of the property related to the activity.","nullable":true,"properties":{"id":{"type":"integer","description":"The id of the property."},"title":{"type":"string","description":"The title of the property."},"cover_url":{"type":"string","nullable":true,"description":"The URL of the property's cover image."},"room_type":{"type":"object","description":"Details of the room type related to the activity.","nullable":true,"properties":{"id":{"type":"integer","description":"The id of the room type."},"title":{"type":"string","description":"The title of the room type."}}}}}}}},"note":{"type":"string","description":"Any notes related to the conversation."},"messages":{"type":"array","description":"List of messages within the conversation.","items":{"type":"object","properties":{"id":{"type":"string","description":"The id of the message."},"sender_role":{"type":"string","description":"The role of the message sender, either 'host' or 'guest'."},"sender_name":{"type":"string","nullable":true,"description":"Display name of the sender when known. For host-side messages this is the real operator account name; for HostGPT-generated messages this is `HostGPT`; for shadow HostGPT preview messages this is a localized HostGPT label. `null` for guest messages and other cases where the sender cannot be resolved."},"sources":{"type":"array","description":"Knowledge sources cited by HostGPT to generate this message, grouped by `type` (e.g. `checkin_guide`, `automation_reply`, `host_knowledge`, `thread`, `host_assistant`). Empty array for human-sent messages and HostGPT messages without resolved citations.","items":{"type":"object","properties":{"type":{"type":"string","description":"Source group type."},"docs":{"type":"array","description":"Individual documents grouped under this source type.","items":{"type":"object","properties":{"title":{"type":"string","description":"Title of the source document."},"fragment":{"type":"array","description":"Quoted text fragments from this source.","items":{"type":"string"}},"source_type":{"type":"string","description":"Same as the parent `type`."},"link_id":{"type":"integer","description":"Internal id linking back to the underlying record (property id for `checkin_guide`, rule id for `automation_reply`, knowledge id for `host_knowledge`, or -1 when unknown)."}}}}}}},"display_type":{"type":"string","description":"The display type of the message.","enum":["Text","Box","FileAttachment","RequestToBook","BsRequestBook","SpecialOffer","ReservationAlteration","HouseLinkCard"]},"content":{"type":"string","description":"The text content of the message."},"attachment":{"type":"object","nullable":true,"description":"Any attachment included with the message."},"created_at":{"type":"string","format":"date-time","description":"The timestamp of when the message was created."}}}}}}},"type":"object"}]}}}}}},"post":{"summary":"Send Message","description":"Send a text or image message to the guest.","operationId":"send-message","tags":["Messages"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"send_message","description":"Send a text or image message to the guest in a specific conversation. Messages cannot be recalled once sent. Double-check that `conversation_id` is correct and that the content complies with channel policy (Airbnb \/ Booking, etc.) \u2014 do not include external contact info or third-party links, otherwise the channel may block the message or suspend the account.","intent_examples":["Reply to this guest and tell them the lock code is 6688","Send a welcome message in this thread"],"category":"messaging","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"conversation_id","in":"path","description":"The id of the conversation.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"The text content of the message. Max length depends on the limit of different channels."},"jpeg_base64":{"type":"string","description":"The base64 encoded string of the JPEG image."}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/conversations\/{conversation_id}\/note":{"patch":{"summary":"Update Conversation Note","description":"Set or clear the host's private note attached to a conversation thread. The note is stored only in Hostex (visible in the Hostex Inbox), is **never** sent to the guest or pushed to any channel, and is shared across operators inside the same account. Pass an empty string or `null` in `note` to clear the existing note.","operationId":"update-conversation-note","tags":["Messages"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_conversation_note","description":"Set or clear the host-side private note attached to a conversation thread. Notes are stored only in Hostex and are NEVER sent to the guest or any channel; they are shared across operators in the account so the team can leave context for each other. Call `search_conversations` first to obtain a `conversation_id`. Pass an empty string or null in `note` to clear the existing note. Returns the updated note and `updated_at`.","intent_examples":["Add a note on this thread: VIP guest, always confirm late check-in","Update the note on this conversation","Clear the note on this conversation"],"category":"messaging","read_only":false,"since_version":"3.7.0"},"parameters":[{"name":"conversation_id","in":"path","description":"The id of the conversation.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["note"],"properties":{"note":{"type":"string","nullable":true,"maxLength":5000,"description":"The host-side private note. Pass an empty string or `null` to clear the existing note. Max 5000 characters."}}}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"type":"object","required":["id","note"],"properties":{"id":{"type":"string","description":"The id of the conversation."},"note":{"type":"string","nullable":true,"description":"The current note value after the update (null when cleared)."},"updated_at":{"type":"string","format":"date-time","nullable":true,"description":"When the note was last updated, ISO 8601."}}}},"type":"object"}]}}}}}}},"\/conversations\/{conversation_id}\/special_offers":{"get":{"summary":"Get Special Offers","description":"List the special offers and pre-approvals that have been sent in a conversation, with their current status. Use the returned `id` to withdraw an offer that is still active. Only Airbnb and booking-site (direct booking) conversations can contain special offers.","operationId":"get-special-offers","tags":["Messages"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_special_offers","description":"List the special offers and pre-approvals already sent in a conversation, with their current status (active \/ accepted \/ declined \/ expired \/ withdrawn). Call `search_conversations` first to obtain a `conversation_id`. Use the returned offer `id` with `withdraw_special_offer` to withdraw an active offer.","intent_examples":["What special offers did I send to this guest?","Is the discount I offered this guest still active?","Show the offers in this conversation"],"category":"messaging","read_only":true,"since_version":"3.7.0"},"parameters":[{"name":"conversation_id","in":"path","description":"The id of the conversation.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"type":"object","required":["special_offers"],"properties":{"special_offers":{"type":"array","description":"The special offers sent in this conversation, most recent first.","items":{"type":"object","properties":{"id":{"type":"string","description":"The id of the special offer on the channel side. Use this id to withdraw the offer."},"offer_type":{"type":"string","enum":["special_offer","preapproval"],"description":"The kind of offer: a custom-priced special offer, or a pre-approval of the guest's inquiry."},"status":{"type":"string","description":"Current status of the offer, e.g. `active`, `accepted`, `declined`, `expired`, `withdrawn`."},"listing_id":{"type":"string","nullable":true,"description":"The channel listing the offer was sent for (as reported by the channel)."},"check_in_date":{"type":"string","format":"date","description":"Check-in date of the offered stay."},"check_out_date":{"type":"string","format":"date","description":"Check-out date of the offered stay."},"nights":{"type":"integer","description":"Number of nights of the offered stay."},"number_of_guests":{"type":"integer","description":"Total number of guests the offer covers."},"price":{"type":"number","description":"Total price of the offered stay, in major currency units."},"currency":{"type":"string","nullable":true,"description":"Currency of the price."},"expire_time":{"type":"string","nullable":true,"description":"When the offer expires, as reported by the channel."},"create_time":{"type":"string","nullable":true,"description":"When the offer was created, as reported by the channel."}}}}}}},"type":"object"}]}}}}}},"post":{"summary":"Send Special Offer","description":"Send a special offer to the guest in a conversation. A special offer invites the guest to book the given listing for the given dates at a custom total price, and typically expires 24 hours after being sent. Supported on Airbnb and booking-site (direct booking) conversations only; requests on other channels return an error. For booking-site conversations, `rate_plan_id` and `currency` are also required.","operationId":"send-special-offer","tags":["Messages"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"send_special_offer","description":"Send a special offer to the guest in a conversation: invite them to book a listing for given dates at a custom total price. Only works on Airbnb and booking-site (direct booking) conversations. Call `search_conversations` first to obtain a `conversation_id`, and `search_listings` to obtain the channel `listing_id`. For booking-site conversations `rate_plan_id` and `currency` are also required. The offer typically expires after 24 hours. This is sent to the guest immediately \u2014 confirm the price and dates with the user before calling.","intent_examples":["Offer this guest the week of July 4th for $1200 total","Send a special offer with a 10% discount to this guest","Give this guest a custom price for their dates"],"category":"messaging","read_only":false,"since_version":"3.7.0"},"parameters":[{"name":"conversation_id","in":"path","description":"The id of the conversation.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["listing_id","check_in_date","check_out_date","price","number_of_adults"],"properties":{"listing_id":{"type":"string","description":"The channel listing id to offer, as returned by `GET \/listings`."},"check_in_date":{"type":"string","format":"date","description":"Check-in date of the offered stay, `YYYY-MM-DD`."},"check_out_date":{"type":"string","format":"date","description":"Check-out date of the offered stay, `YYYY-MM-DD`. Must be after `check_in_date`."},"price":{"type":"number","description":"Total price for the whole stay, in major currency units (not per night)."},"number_of_adults":{"type":"integer","minimum":1,"description":"Number of adults."},"number_of_children":{"type":"integer","minimum":0,"description":"Number of children. Defaults to 0."},"number_of_infants":{"type":"integer","minimum":0,"description":"Number of infants. Defaults to 0."},"number_of_pets":{"type":"integer","minimum":0,"description":"Number of pets. Defaults to 0."},"rate_plan_id":{"type":"string","description":"The rate plan to offer. Required for booking-site (direct booking) conversations; ignored on Airbnb."},"currency":{"type":"string","description":"Currency code of `price`, e.g. `USD`. Required for booking-site (direct booking) conversations; ignored on Airbnb."}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/conversations\/{conversation_id}\/special_offers\/{special_offer_id}":{"delete":{"summary":"Withdraw Special Offer","description":"Withdraw a previously sent special offer or pre-approval that is still active. `special_offer_id` is the offer `id` returned by `GET \/conversations\/{conversation_id}\/special_offers`.","operationId":"withdraw-special-offer","tags":["Messages"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"withdraw_special_offer","description":"Withdraw a special offer or pre-approval that was previously sent in a conversation and is still active. Use `search_special_offers` to find the offer `id`. Withdrawal is visible to the guest \u2014 confirm with the user before calling.","intent_examples":["Withdraw the special offer I sent to this guest","Cancel the discount offer in this conversation"],"category":"messaging","read_only":false,"since_version":"3.7.0"},"parameters":[{"name":"conversation_id","in":"path","description":"The id of the conversation.","required":true,"schema":{"type":"string"}},{"name":"special_offer_id","in":"path","description":"The id of the special offer, as returned by `GET \/conversations\/{conversation_id}\/special_offers`.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/conversations\/{conversation_id}\/preapprovals":{"post":{"summary":"Send Pre-approval","description":"Pre-approve the guest's inquiry in a conversation, inviting them to book the listing and dates they asked about at the standard price. Supported on Airbnb conversations only; requests on other channels return an error. The pre-approval typically expires 24 hours after being sent. No request body is required.","operationId":"send-preapproval","tags":["Messages"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"send_preapproval","description":"Pre-approve the guest's inquiry in an Airbnb conversation, inviting them to book the listing and dates they asked about at the standard price. Only works on Airbnb conversations. Call `search_conversations` first to obtain a `conversation_id`. This is sent to the guest immediately \u2014 confirm with the user before calling.","intent_examples":["Pre-approve this guest","Let this Airbnb guest book the dates they asked about"],"category":"messaging","read_only":false,"since_version":"3.7.0"},"parameters":[{"name":"conversation_id","in":"path","description":"The id of the conversation.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/reviews":{"get":{"summary":"Query Reviews","description":"Query reviews like the [Reviews Page](https:\/\/hostex.io\/app\/reviews).","operationId":"query-reviews","tags":["Reviews"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_reviews","description":"List reviews. Filter by channel, property, rating, replied status, etc. Returns each review's channel, reservation, guest, rating, content, and host reply (if any). Common use cases: surface recent low-rating reviews, find unreplied reviews to handle.","intent_examples":["Show recent low-rating reviews","All reviews for Coastal Villa #1 this month","Which reviews haven't been replied to yet"],"category":"reservation","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"reservation_code","in":"query","description":"Filters the results by the specified reservation code.","required":false,"schema":{"type":"string"}},{"name":"property_id","in":"query","description":"Filters the results by the specified property ID.","required":false,"schema":{"type":"integer"}},{"name":"review_status","in":"query","description":"Filters the results by the specified review status. Default: `reviewed`","required":false,"schema":{"type":"string","enum":["pending_guest_review","pending_host_review","reviewed"]}},{"name":"start_check_out_date","in":"query","description":"Filters the results to include reservations with check-out dates starting from this date (inclusive). Default: 180 days ago.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_check_out_date","in":"query","description":"Filters the results to include reservations with check-out dates up to this date (inclusive). Less than 180 days from `start_check_out_date`. Default: today","required":false,"schema":{"type":"string","format":"date"}},{"name":"offset","in":"query","description":"Specifies the starting index from which the results should be returned. Default: 0","required":true,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"Determines the maximum number of results to be returned, up to a maximum of 100. Default: 20","required":true,"schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["reviews"],"properties":{"reviews":{"description":"List of the reviews","type":"array","items":{"type":"object","properties":{"reservation_code":{"type":"string","description":"The unique code identifying the reservation."},"property_id":{"type":"integer","description":"The id of the property the reservation is associated with."},"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"listing_id":{"$ref":"#\/components\/schemas\/ListingId"},"check_in_date":{"type":"string","format":"date","description":"The check-in date of the reservation."},"check_out_date":{"type":"string","format":"date","description":"The check-out date of the reservation."},"host_review":{"type":"object","nullable":true,"description":"Reviews made by the host about the guest. Return `null` if the host has not made a review yet.","properties":{"score":{"type":"number","description":"The rating score of the host review. The value is between 0 and 5."},"sub_score":{"type":"array","nullable":true,"description":"Category-level sub-scores for the host review. Only available for Airbnb channels. Returns `null` if not available. Rating is on a scale of 1\u20135.","items":{"type":"object","properties":{"category":{"type":"string","description":"The name of the rating category. Example: `accuracy`, `checkin`, `cleanliness`, `communication`, `location`, `value`."},"rating":{"type":"number","description":"The rating score for the category. The value is between 1 and 5."},"review_category_tags":{"type":"array","nullable":true,"description":"Structured tags associated with the category rating.","items":{"type":"string"}}}}},"content":{"type":"string","description":"The comment of the host."},"created_at":{"type":"string","format":"date-time","description":"The datetime when the host review was created in ISO 8601 format. Example: `2019-01-01T00:00:00+00:00`"}}},"guest_review":{"type":"object","nullable":true,"description":"Reviews made by the guest about their stay. Return `null` if the guest has not made a review yet.","properties":{"score":{"type":"number","description":"The rating score of the guest review. The value is between 0 and 5."},"sub_score":{"type":"array","nullable":true,"description":"Category-level sub-scores for the guest review. Available for Airbnb and Booking.com channels. Returns `null` if not available. Rating scale differs by channel: 1\u20135 for Airbnb, 1\u201310 for Booking.com.","items":{"type":"object","properties":{"category":{"type":"string","description":"The name of the rating category. Airbnb example: `accuracy`, `checkin`, `cleanliness`, `communication`, `location`, `value`. Booking.com example: `facilities`, `comfort`, `staff`, `value`, `clean`, `location`."},"rating":{"type":"number","description":"The rating score for the category. Between 1 and 5 for Airbnb, between 1 and 10 for Booking.com."},"review_category_tags":{"type":"array","nullable":true,"description":"Structured tags associated with the category rating. Only present for Airbnb channels.","items":{"type":"string"}}}}},"content":{"type":"string","description":"The comment of the guest."},"created_at":{"type":"string","format":"date-time","description":"The datetime when the guest review was created in ISO 8601 format. Example: `2019-01-01T00:00:00+00:00`"}}},"host_reply":{"type":"object","nullable":true,"description":"The host's reply to the guest's review. Return `null` if the host has not made a reply yet.","properties":{"content":{"type":"string","description":"The reply of the host."},"created_at":{"type":"string","format":"date-time","description":"The datetime when the reply was created in ISO 8601 format. Example: `2019-01-01T00:00:00+00:00`"}}}},"required":["reservation_code","property_id","channel_type","listing_id","check_in_date","check_out_date"]}}},"type":"object"}},"type":"object"}]}}}}}}},"\/reviews\/{reservation_code}":{"post":{"summary":"Create a review","description":"Create review or reply for a reservation. ","operationId":"create-review","tags":["Reviews"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_review","description":"Write a host review of a guest, or a host reply to the guest's review. \u26a0\ufe0f Irreversible and will be publicly shown on the channel (Airbnb \/ Booking, etc.), affecting both the host's and the guest's reputation scores. When drafting on behalf of the host, ensure the content is objective and contains no contact info or external links (otherwise the channel may block it or penalize the listing).","intent_examples":["Write a positive review for guest ABC123: punctual, respected the property","Reply to the guest's review on reservation XYZ"],"category":"reservation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"reservation_code","in":"path","description":"The unique code identifying the reservation.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"host_review_score":{"type":"number","description":"The rating score of the host review. The value is between 0 and 5."},"host_review_content":{"type":"string","description":"The comment of the host."},"host_reply_content":{"type":"string","description":"The reply of the host."},"category_ratings":{"type":"object","description":"Optional per-category sub-ratings submitted together with the host review. Only effective for channels that support category ratings (currently Airbnb and Zhenguo). When provided without `host_review_score`, the `overall_rating` value is used as the review score. Supported keys: `overall_rating`, `cleanliness`, `communication`, `respect_of_house_rules`, `recommend`. Each rating value is between 0 and 5 (`recommend` is a boolean 0\/1).","properties":{"overall_rating":{"type":"number","description":"Overall rating of the guest. The value is between 0 and 5."},"cleanliness":{"type":"number","description":"Cleanliness rating. The value is between 0 and 5."},"communication":{"type":"number","description":"Communication rating. The value is between 0 and 5."},"respect_of_house_rules":{"type":"number","description":"Respect of house rules rating. The value is between 0 and 5."},"recommend":{"type":"number","description":"Whether the host recommends the guest. 1 for yes, 0 for no (Airbnb only)."}}}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/automation\/actions":{"get":{"summary":"Query upcoming automation actions","description":"Returns scheduled automation **actions** that are waiting to run: either automated **messages** (`type=message`, same scope as the in-app \u201cupcoming message actions\u201d list, within the next 30 days) or automated **reviews** (`type=review`). Filters mirror the internal automation plan lists (keyword, property IDs, time range, channel types, rule event filters). Pagination uses `offset` and `limit` like other v3 list endpoints.","operationId":"query-automation-actions","tags":["Automation"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_automation_actions","description":"List pending (waiting-to-run) automation plans. Two kinds are covered: (1) automated messages (`type=message`, equivalent to the in-app 'upcoming messages' list within the next 30 days); (2) automated reviews (`type=review`). Filter by keyword, property ids, time range, channel, rule event. Common use cases: review which messages will be auto-sent to guests on a given day, find a specific pending plan to trigger or cancel manually.","intent_examples":["Which automated messages will go out tomorrow","Upcoming pending messages for Coastal Villa","Queued automated reviews"],"category":"automation","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"type","in":"query","description":"Kind of scheduled action: `message` for automated guest messages, `review` for scheduled host reviews.","required":true,"schema":{"type":"string","enum":["message","review"]}},{"name":"keyword","in":"query","description":"Optional text matched against the plan detail payload (same as the in-app keyword filter).","required":false,"schema":{"type":"string"}},{"name":"stay_code","in":"query","description":"The code of the stay.","required":false,"schema":{"type":"string"}},{"name":"property_ids","in":"query","description":"Enter property IDs to search. Comma-separated integer IDs (e.g. `1,2,3`) or a JSON array string (e.g. `[1,2,3]`).","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Include only actions scheduled at or after this time (inclusive). ISO 8601 or `Y-m-d H:i:s` as accepted by date validation.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","description":"Include only actions scheduled at or before this time (inclusive).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"channel_types","in":"query","description":"Filter by channel types. Comma-separated channel names, e.g. `airbnb,agoda`.","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","description":"Zero-based index of the first row to return. Default: 0.","required":false,"schema":{"type":"integer","default":0,"minimum":0}},{"name":"limit","in":"query","description":"Maximum number of rows to return (1\u2013100). Default: 20.","required":false,"schema":{"type":"integer","default":20,"minimum":1,"maximum":100}}],"responses":{"200":{"description":"List of upcoming automation actions and total count.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["actions","total"],"properties":{"actions":{"type":"array","description":"Scheduled actions, ordered by `scheduled_at`.","items":{"type":"object","required":["id","type","name","send_to","stay_code","property_id","property_title","scheduled_at","channel_type"],"properties":{"id":{"type":"integer","description":"Automation plan id."},"type":{"type":"string","enum":["message","review"],"description":"Action kind, matches the `type` query parameter."},"name":{"type":"string","description":"Human-readable title: action prefix plus linked rule event title."},"send_to":{"type":"string","description":"Recipient hint from the plan detail (e.g. thread or guest label)."},"stay_code":{"type":"string","nullable":true,"description":"Linked reservation (stay) code, or `null` if the plan is not tied to a stay."},"property_id":{"type":"integer","description":"Hostex property (house) id for this plan."},"property_title":{"type":"string","description":"Property display title for the plan\u2019s house."},"scheduled_at":{"type":"string","format":"date-time","description":"When the action is scheduled to run, in the operator's local timezone."},"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"}}}},"total":{"type":"integer","description":"Total number of matching actions (before `offset` \/ `limit`)."}},"type":"object"}},"type":"object"}]}}}}}}},"\/automation\/actions\/{plan_id}\/execute":{"post":{"summary":"Execute automation action now","description":"Dispatches a **waiting** message or review automation plan immediately (same behavior as executing an upcoming action in the app). For **review** plans, the reservation must have reached check-out date in the operator timezone. Requires a **writable** access token. Only `send_message` and `review` plan types are supported.","operationId":"execute-automation-action","tags":["Automation"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"execute_automation_action","description":"Immediately trigger a pending automation plan (a waiting-status `send_message` or `review` automation). Equivalent to tapping 'Run now' on a pending item in the app. \u26a0\ufe0f Irreversible: the message will be sent immediately \/ the review will be posted to the channel immediately. Only supports `send_message` and `review` plans; `review` additionally requires the reservation to have reached its check-out date.","intent_examples":["Send this pending welcome message now","Post this queued positive review immediately"],"category":"automation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"plan_id","in":"path","description":"Automation plan id from `GET \/automation\/actions` (`data.actions[].id`).","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Plan was queued for immediate execution.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}},"400":{"description":"Plan cannot be executed now (e.g. `review` plan whose reservation has not checked out yet, or unsupported action type).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/automation\/actions\/{plan_id}":{"delete":{"summary":"Delete upcoming automation action","description":"Removes a **waiting** message or review automation plan without running it (same as deleting an upcoming action in the app). Requires a **writable** access token. Only `send_message` and `review` plan types are supported.","operationId":"delete-automation-action","tags":["Automation"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_automation_action","description":"Delete a pending automation plan (a waiting-status `send_message` or `review` automation) so it will not be sent. \u26a0\ufe0f Irreversible \u2014 but only this single occurrence is cancelled; the underlying automation rule is untouched and will continue generating new plans on its next trigger. Only supports `send_message` and `review` plans.","intent_examples":["Cancel this pending welcome message","Don't post this review \u2014 delete it"],"category":"automation","read_only":false,"requires_confirmation":true,"since_version":"3.4.0"},"parameters":[{"name":"plan_id","in":"path","description":"Automation plan id from `GET \/automation\/actions` (`data.actions[].id`).","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Plan was deleted.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/webhooks":{"get":{"summary":"Query Webhooks","description":"Query Webhooks like the [Webhooks Page](https:\/\/hostex.io\/app\/api\/web-hooks).","operationId":"query-webhooks","tags":["Manage Webhooks"],"security":[{"HostexAccessToken":[]}],"parameters":[],"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["webhooks"],"properties":{"webhooks":{"description":"List of the webhooks","type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"The unique id."},"url":{"type":"string","description":"The webhook url."},"events":{"type":"array","description":"The list of event types this webhook subscribes to.","items":{"type":"string","enum":["reservation_created","reservation_updated","property_availability_updated","listing_calendar_updated","message_created","review_created","review_updated"]}},"manageable":{"type":"boolean","description":"Whether the webhook can be managed. You can only delete records that you are allowed to manage."},"created_at":{"type":"string","format":"date-time","description":"The timestamp of when the webhook was created."}},"required":["id","url","events","manageable","created_at"]}}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Webhook","description":"Create a webhook.","operationId":"create-webhook","tags":["Manage Webhooks"],"security":[{"HostexAccessToken":[]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"The webhook endpoint URL."},"events":{"type":"array","description":"The list of event types to subscribe to. Defaults to all events if omitted.","items":{"type":"string","enum":["reservation_created","reservation_updated","property_availability_updated","listing_calendar_updated","message_created","review_created","review_updated"]}}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/webhooks\/{id}":{"patch":{"summary":"Update Webhook","description":"Update the url or event subscriptions for a webhook. You can only update webhooks created by your own app.","operationId":"update-webhook","tags":["Manage Webhooks"],"security":[{"HostexAccessToken":[]}],"parameters":[{"name":"id","in":"path","description":"The id of the webhook.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"The new webhook endpoint URL."},"events":{"type":"array","description":"The list of event types to subscribe to.","items":{"type":"string","enum":["reservation_created","reservation_updated","property_availability_updated","listing_calendar_updated","message_created","review_created","review_updated"]}}}}}}},"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"delete":{"summary":"Delete webhook","description":"You can only delete webhooks created by your own app if they are manageable. Attempting to delete non-manageable webhooks from other apps will result in a 403 error.","operationId":"delete-webhook","tags":["Manage Webhooks"],"security":[{"HostexAccessToken":[]}],"parameters":[{"name":"id","in":"path","description":"The id of the webhook.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The request has been successfully submitted. ","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/knowledge_bases":{"get":{"summary":"Query Knowledge Bases","description":"You can query knowledge base entries by making a request to this endpoint. Results are paginated and can be filtered by property or channel.","operationId":"query-knowledge-bases","tags":["Knowledge Base"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_knowledge_bases","description":"Search\/paginate knowledge base entries. Filter by property IDs or channel types. Returns id, title, enable status, scope and processing status.","intent_examples":["List all my knowledge base entries","Find knowledge bases for a specific property","Search knowledge bases for Airbnb channel"],"category":"knowledge_base","read_only":true,"since_version":"3.5.0"},"parameters":[{"name":"offset","in":"query","description":"Zero-based index of the first row to return. Default: 0.","required":false,"schema":{"type":"integer","default":0,"minimum":0}},{"name":"limit","in":"query","description":"Maximum number of rows to return (1\u2013100). Default: 10.","required":false,"schema":{"type":"integer","default":10,"minimum":1,"maximum":100}},{"name":"property_ids","in":"query","description":"Filter by property IDs. Comma-separated integer IDs (e.g. `1,2,3`).","required":false,"schema":{"type":"string"}},{"name":"channel_types","in":"query","description":"Filter by channel types. Comma-separated channel names, e.g. `airbnb,booking.com`.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A paginated list of knowledge base entries","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["total","knowledge_bases"],"properties":{"total":{"description":"Total number of knowledge base entries.","type":"integer"},"knowledge_bases":{"description":"List of knowledge base entries","type":"array","items":{"required":["id","scope_property","scope_channel","is_enable","title","process_status"],"properties":{"id":{"description":"Unique identifier for the knowledge base entry","type":"integer","format":"int64"},"scope_property":{"description":"Property scope of this knowledge base entry","type":"object","required":["type","ids"],"properties":{"type":{"description":"Scope type. all, by_property, by_group, or by_room_type.","type":"string","enum":["all","by_property","by_group","by_room_type"]},"ids":{"description":"Scope IDs. [-1] for all; property IDs for by_property; group IDs for by_group; room type IDs for by_room_type.","type":"array","items":{"type":"integer"}}}},"scope_channel":{"description":"Channel scope of this knowledge base entry","type":"object","required":["type","channels"],"properties":{"type":{"description":"Scope type: all or by_channel.","type":"string","enum":["all","by_channel"]},"channels":{"description":"Channel names. `['unlimited']` for all; channel name array (e.g. `['airbnb', 'booking.com']`) for by_channel. See [Supported Channels](\/reference\/supported-channels).","type":"array","items":{"type":"string"}}}},"is_enable":{"description":"Whether the entry is enabled.","type":"boolean"},"title":{"description":"Title of the knowledge base entry","type":"string"},"process_status":{"description":"Processing status of the entry. waiting\/processing\/done\/failed.","type":"string","enum":["waiting","processing","done","failed"]}},"type":"object"}}},"type":"object"}},"type":"object"}]}}}}}},"post":{"summary":"Create Knowledge Base","description":"Create a new knowledge base entry for the HostGPT automation assistant. The entry defines AI content and the property\/channel scope where it applies.","operationId":"create-knowledge-base","tags":["Knowledge Base"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"create_knowledge_base","description":"Create a new knowledge base entry with AI reply content and scope (properties\/channels).","intent_examples":["Create a new knowledge base entry","Add an automated reply content"],"category":"knowledge_base","read_only":false,"requires_confirmation":true,"since_version":"3.5.0"},"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["scope_property","scope_channel","contents","is_enable"],"properties":{"scope_property":{"description":"The property scope configuration.","type":"object","required":["type","ids"],"properties":{"type":{"description":"The type of property scope.","type":"string","enum":["all","by_property","by_group","by_room_type"]},"ids":{"description":"Scope IDs interpreted according to `type`: property IDs for `by_property`, group IDs for `by_group`, room type IDs for `by_room_type`. Use `[-1]` for `all`.","type":"array","items":{"type":"integer"}}}},"scope_channel":{"description":"The channel scope configuration.","type":"object","required":["type","channels"],"properties":{"type":{"description":"Channel scope type: all or by_channel.","type":"string","enum":["all","by_channel"]},"channels":{"description":"Channel names this knowledge base applies to (e.g. `['airbnb', 'booking.com']`). Use `['unlimited']` for `all`. See [Supported Channels](\/reference\/supported-channels).","type":"array","items":{"type":"string"}}}},"contents":{"description":"The content entries of the knowledge base.","type":"array","minItems":1,"items":{"type":"object","required":["text","sub_title"],"properties":{"text":{"description":"The content text.","type":"string"},"sub_title":{"description":"The subtitle for this content block.","type":"string"}}}},"title":{"description":"Optional title for the knowledge base entry.","type":"string"},"is_enable":{"description":"Whether the entry is enabled.","type":"boolean"}}}}}},"responses":{"200":{"description":"The knowledge base entry has been created successfully.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/knowledge_bases\/{id}":{"get":{"summary":"Get Knowledge Base Detail","description":"Retrieve the full details of a single knowledge base entry by its ID.","operationId":"get-knowledge-base","tags":["Knowledge Base"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"get_knowledge_base","description":"Get full details of a single knowledge base entry by ID, including content, scope, and enable status.","intent_examples":["View knowledge base entry details","Get the content of this knowledge base"],"category":"knowledge_base","read_only":true,"since_version":"3.5.0"},"parameters":[{"name":"id","in":"path","description":"The ID of the knowledge base entry.","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"The knowledge base entry details.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["id","scope_property","scope_channel","title","contents","is_enable","process_status"],"properties":{"id":{"description":"Unique identifier for the knowledge base entry","type":"integer","format":"int64"},"scope_property":{"description":"Property scope of this knowledge base entry","type":"object","required":["type","ids"],"properties":{"type":{"description":"Scope type. all, by_property, by_group, or by_room_type.","type":"string","enum":["all","by_property","by_group","by_room_type"]},"ids":{"description":"Scope IDs. [-1] for all; property IDs for by_property; group IDs for by_group; room type IDs for by_room_type.","type":"array","items":{"type":"integer"}}}},"scope_channel":{"description":"Channel scope of this knowledge base entry","type":"object","required":["type","channels"],"properties":{"type":{"description":"Scope type: all or by_channel.","type":"string","enum":["all","by_channel"]},"channels":{"description":"Channel names. `['unlimited']` for all; channel name array (e.g. `['airbnb', 'booking.com']`) for by_channel. See [Supported Channels](\/reference\/supported-channels).","type":"array","items":{"type":"string"}}}},"title":{"description":"Title of the knowledge base entry.","type":"string"},"contents":{"description":"All content entries with text and subtitles, e.g. `[{\"sub_title\":\"WiFi\", \"text\":\"SSID: foo \/ pwd: bar\"}]`.","type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"sub_title":{"type":"string"}}}},"is_enable":{"description":"Whether the entry is enabled.","type":"boolean"},"process_status":{"description":"Processing status of the entry.","type":"string","enum":["waiting","processing","done","failed"]}},"type":"object"}},"type":"object"}]}}}},"404":{"description":"The knowledge base entry does not exist or does not belong to the operator.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"patch":{"summary":"Update Knowledge Base","description":"Replace an existing knowledge base entry. This endpoint performs a **full replacement** \u2014 `scope_property`, `scope_channel`, `contents` and `is_enable` must all be supplied. Use `GET \/knowledge_bases\/{id}` first if you only want to change one field.","operationId":"update-knowledge-base","tags":["Knowledge Base"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"update_knowledge_base","description":"Update all fields of a knowledge base entry, including content, scope, and enable status.","intent_examples":["Update the content of this knowledge base","Modify the scope of a knowledge base","Enable or disable this knowledge base"],"category":"knowledge_base","read_only":false,"requires_confirmation":true,"since_version":"3.5.0"},"parameters":[{"name":"id","in":"path","description":"The ID of the knowledge base entry to update.","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["scope_property","scope_channel","contents","is_enable"],"properties":{"scope_property":{"description":"The property scope configuration.","type":"object","required":["type","ids"],"properties":{"type":{"description":"The type of property scope.","type":"string","enum":["all","by_property","by_group","by_room_type"]},"ids":{"description":"Scope IDs interpreted according to `type`: property IDs for `by_property`, group IDs for `by_group`, room type IDs for `by_room_type`. Use `[-1]` for `all`.","type":"array","items":{"type":"integer"}}}},"scope_channel":{"description":"The channel scope configuration.","type":"object","required":["type","channels"],"properties":{"type":{"description":"Channel scope type: all or by_channel.","type":"string","enum":["all","by_channel"]},"channels":{"description":"Channel names this knowledge base applies to (e.g. `['airbnb', 'booking.com']`). Use `['unlimited']` for `all`. See [Supported Channels](\/reference\/supported-channels).","type":"array","items":{"type":"string"}}}},"contents":{"description":"The content entries of the knowledge base.","type":"array","minItems":1,"items":{"type":"object","required":["text","sub_title"],"properties":{"text":{"description":"The content text.","type":"string"},"sub_title":{"description":"The subtitle for this content block.","type":"string"}}}},"title":{"description":"Optional title for the knowledge base entry.","type":"string"},"is_enable":{"description":"Whether the entry is enabled.","type":"boolean"}}}}}},"responses":{"200":{"description":"The knowledge base entry has been updated successfully.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}},"404":{"description":"The knowledge base entry does not exist or does not belong to the operator.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}},"delete":{"summary":"Delete Knowledge Base","description":"Delete a knowledge base entry by its ID.","operationId":"delete-knowledge-base","tags":["Knowledge Base"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"delete_knowledge_base","description":"Delete a knowledge base entry.","intent_examples":["Delete this knowledge base","Remove this knowledge base entry"],"category":"knowledge_base","read_only":false,"requires_confirmation":true,"since_version":"3.5.0"},"parameters":[{"name":"id","in":"path","description":"The ID of the knowledge base entry to delete.","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"The knowledge base entry has been deleted successfully.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}},"404":{"description":"The knowledge base entry does not exist or does not belong to the operator.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/CommonResponse"}}}}}}},"\/channel_accounts":{"get":{"summary":"Query Channel Accounts","description":"Query the third-party channel accounts (Airbnb, Booking.com, etc.) that the operator has connected. Each entry exposes the account identity and current authorization status. Use `id` to fetch a single account.","operationId":"query-channel-accounts","tags":["Channels"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_channel_accounts","description":"List the third-party channel accounts (Airbnb, Booking.com, etc.) connected by the current operator. Returns each account's internal id, `channel_type`, username (login \/ identifier), channel-side account id (`origin_account_id`), and current authorization status (`auth_status`: active \/ connecting \/ disconnected \/ exception \/ unknown). Common use cases: inventory the connected OTAs, check whether a given channel account is still online, filter by `channel_type` to obtain `channel_account_id` for subsequent listing queries.","intent_examples":["Which OTAs am I connected to","Is my Airbnb account still online","What is the channel account id of my Booking account"],"category":"property","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"id","in":"query","description":"Internal id of a specific channel account.","required":false,"schema":{"type":"integer"}},{"name":"channel_type","in":"query","description":"Filter by channel type.","required":false,"schema":{"$ref":"#\/components\/schemas\/ChannelType"}},{"name":"offset","in":"query","description":"The starting point from which to begin returning results. Default: 0.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100. Default: 20.","required":false,"schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"A list of channel accounts.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["channel_accounts","total"],"properties":{"channel_accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"Internal id of the channel account."},"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"username":{"type":"string","description":"Login username \/ identifier on the channel side."},"origin_account_id":{"type":"string","description":"Account id on the channel side (when available)."},"auth_status":{"type":"string","description":"Current authorization \/ connection status of the channel account.","enum":["active","connecting","disconnected","exception","unknown"]},"created_at":{"type":"string","format":"date-time","nullable":true,"description":"When the account was connected, in ISO 8601 UTC."}}}},"total":{"type":"integer","description":"Total number of matching channel accounts."}},"type":"object"}},"type":"object"}]}}}}}}},"\/listings":{"get":{"summary":"Query Listings","description":"Query the listings (third-party properties) synced from the operator's connected channel accounts. A listing is a property as it exists on a specific channel, identified by `listing_id` (the channel-side property id). Filter by `channel_account_id`, `listing_id` and\/or `channel_type` to scope results.","operationId":"query-listings","tags":["Channels"],"security":[{"HostexAccessToken":[]}],"x-mcp":{"exposed":true,"tool_name":"search_listings","description":"List the listings synced from connected channel accounts (the OTA-side property entries). A listing represents one property's posting on one channel and is uniquely identified by `listing_id` (channel-side id) + `channel_type`. Can be filtered by `channel_account_id` (from `search_channel_accounts`), `listing_id`, or `channel_type`. Returns each listing's title, cover image, deep link URL, inventory, shelf status (`shelf_status`), and a pass-through `metadata` object (geo \/ images \/ rate plans and other channel-side metadata; structure varies by channel). Common use cases: inventory the listings on each OTA, look up specific listings under a channel account, fetch `listing_id` before pricing \/ restriction workflows.","intent_examples":["What listings do I have on Airbnb","How many listings are under this Booking account","Where is Coastal Villa posted across OTAs"],"category":"property","read_only":true,"since_version":"3.4.0"},"parameters":[{"name":"channel_account_id","in":"query","description":"Internal id of a channel account (from `GET \/channel_accounts`). Limits results to listings under this account.","required":false,"schema":{"type":"integer"}},{"name":"listing_id","in":"query","description":"Channel-side listing id (matches the `listing_id` exposed by other endpoints).","required":false,"schema":{"type":"string"}},{"name":"channel_type","in":"query","description":"Filter by channel type.","required":false,"schema":{"$ref":"#\/components\/schemas\/ChannelType"}},{"name":"offset","in":"query","description":"The starting point from which to begin returning results. Default: 0.","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","description":"The maximum number of results to return. The maximum value is 100. Default: 20.","required":false,"schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"A list of listings synced from connected channel accounts.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"required":["listings","total"],"properties":{"listings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"Internal id of the listing record."},"listing_id":{"type":"string","description":"Channel-side listing id. Matches the `listing_id` used in other endpoints."},"channel_type":{"$ref":"#\/components\/schemas\/ChannelType"},"channel_account_id":{"type":"integer","description":"Internal id of the channel account this listing belongs to (from `GET \/channel_accounts`)."},"origin_account_id":{"type":"string","description":"Account id on the channel side."},"url":{"type":"string","nullable":true,"description":"URL of the listing on the channel's website."},"title":{"type":"string","description":"Listing title as shown on the channel."},"cover":{"type":"string","nullable":true,"description":"Cover image URL for the listing."},"inventory":{"type":"integer","description":"Inventory (number of units) reported by the channel."},"shelf_status":{"type":"string","description":"Listing shelf status on the channel side.","enum":["on","off","deleted","unknown"]},"metadata":{"type":"object","nullable":true,"description":"Normalized channel-side listing metadata parsed from Hostex's internal cache. Schema varies by channel and is not guaranteed to be stable; commonly includes fields such as `city`, `country_name`, `longitude`, `latitude`, `house_picture_list`, `price_list`, etc. Treat this object as best-effort passthrough data and do not rely on the exact shape.","additionalProperties":true},"created_at":{"type":"string","format":"date-time","nullable":true,"description":"When the listing record was created in Hostex, in ISO 8601 UTC."},"updated_at":{"type":"string","format":"date-time","nullable":true,"description":"Last update time of the listing record, in ISO 8601 UTC."}}}},"total":{"type":"integer","description":"Total number of matching listings."}},"type":"object"}},"type":"object"}]}}}}}}},"\/oauth\/authorizations":{"post":{"summary":"Obtain\/Refresh Tokens","description":"This endpoint is used to obtain a new access token using various OAuth 2.0 grant types or refresh an existing token.","operationId":"obtain-token","tags":["OAuth"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["client_id","client_secret","grant_type"],"properties":{"client_id":{"type":"string","description":"The unique identifier for the client application requesting the token."},"client_secret":{"type":"string","description":"The secret key associated with the client application, used for authentication."},"grant_type":{"type":"string","enum":["authorization_code","refresh_token"],"description":"The OAuth 2.0 grant type. Possible values: 'authorization_code' or 'refresh_token'."},"code":{"type":"string","description":"The authorization code received from the authorization endpoint. Required if 'grant_type' is 'authorization_code'."},"refresh_token":{"type":"string","description":"The refresh token used to obtain a new access token. Required if 'grant_type' is 'refresh_token'."}}}}}},"responses":{"200":{"description":"","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"},{"required":["data"],"properties":{"data":{"type":"object","properties":{"access_token":{"type":"string","description":"The newly issued access token to be used for authorized API requests."},"refresh_token":{"type":"string","description":"A token that can be used to obtain a new access token once the current one expires."},"expires_in":{"type":"integer","description":"The duration in seconds until the access token expires."}},"required":["access_token","refresh_token","expires_in"]}},"type":"object"}]}}}}}}},"\/oauth\/revoke":{"post":{"summary":"Delete\/Revoke Tokens","description":"This endpoint allows clients to revoke an access or refresh token. Deleting\/revoking a token will disconnect the Host from your application.","operationId":"revoke-token","tags":["OAuth"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["client_id","client_secret","token"],"properties":{"client_id":{"type":"string","description":"The unique identifier for the client application requesting the token revocation."},"client_secret":{"type":"string","description":"The secret key associated with the client application, used to authenticate the revocation request."},"token":{"type":"string","description":"The access or refresh token to be revoked. Once revoked, the token cannot be used for further authentication."}}}}}},"responses":{"200":{"description":"Successfully revoked the specified token.","content":{"application\/json":{"schema":{"allOf":[{"$ref":"#\/components\/schemas\/CommonResponse"}]}}}}}}}},"components":{"schemas":{"CommonResponse":{"required":["request_id","error_code","error_msg"],"properties":{"request_id":{"description":"Unique identifier for the request.","type":"string"},"error_code":{"description":"Numeric error code representing the status of the response. A value of `200` indicates success. <br> See the [Error Codes](\/reference\/error-manual#error-codes) section for more information.","type":"integer","example":0},"error_msg":{"description":"Message detailing the status of the response.","type":"string","example":"Done."}},"type":"object"},"PropertyTag":{"type":"object","required":["id","name","color","property_ids","room_type_ids"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"color":{"type":"string"},"property_ids":{"type":"array","items":{"type":"integer"}},"room_type_ids":{"type":"array","items":{"type":"integer"}}}},"CalendarShareLink":{"type":"object","required":["id","scope","url","property_ids"],"properties":{"id":{"type":"integer","description":"Internal share link id."},"scope":{"type":"string","enum":["entire","partial"],"description":"`entire` covers every property of the operator; `partial` covers only the ids listed in `property_ids`."},"url":{"type":"string","description":"Public, read-only calendar URL. Anyone with this URL can view the calendar."},"property_ids":{"type":"array","items":{"type":"integer"},"description":"Property ids the link exposes. Empty array when `scope = entire`."},"created_at":{"type":"string","format":"date-time","nullable":true,"description":"ISO 8601 timestamp of when the share link was created."}}},"ListingId":{"description":"The unique identifier for different channels. <br>For example, the listing id for Airbnb is the Airbnb listing id, and the listing id for Booking.com is the Booking.com room id - rateplan id.","type":"string"},"ChannelTypeParam":{"description":"The type of the channel to be queried.","type":"string","enum":["airbnb","booking.com","agoda","expedia","vrbo","trip.com","booking_site","tujia_intl","houfy"]},"ChannelType":{"description":"The type of the channel. See [Supported Channels](\/reference\/supported-channels) for more information.","type":"string","enum":["airbnb","booking.com","agoda","expedia","vrbo","trip.com","booking_site","tujia_intl","hostex_direct","tujia","xiaozhu","meituan_bnb","meituan_hotel","muniao","fliggy","zhukeyun","tiktok","xiaohongshu","ctrip","houfy"]}},"securitySchemes":{"HostexAccessToken":{"type":"apiKey","description":"Access token to authenticate the request.","name":"Hostex-Access-Token","in":"header"}}}}