Changelog
[3.12.0] - 2026-08-24
Added
GET /transactionsandPOST /transactionsnow acceptreservation_code— the reservation the entry belongs to — and every income / expense entry returned byGET /transactionsnow carries areservation_codefield. This is the same codeGET /reservationsreturns asreservation_code, so a transaction can now be joined back to a reservation without translating identifiers. Entries not linked to a reservation (property- or operator-level) returnnull.
Deprecated
stay_code, on bothGET /transactionsandPOST /transactionsand in theGET /transactionsresponse, is deprecated in favour ofreservation_code. It continues to work and is not scheduled for removal; the two are interchangeable on input, and on output they always hold the same value. Sending both in one request is rejected with400.
Changed
- The documentation now spells out that an income / expense entry belongs to a reservation, not to a single unit of it. On a multi-unit reservation there is one reservation code and several stays, and an entry recorded against any one of those stays is stored against the reservation as a whole — the amount is then spread across the units in proportion to their room rates, and it reads back under the reservation's code rather than the stay code that was submitted. This is long-standing behaviour and is unchanged; only the documentation was wrong, describing the parameter as if it pinned the entry to one unit. Note that the resolution is silent:
POST /transactionswith a secondary stay's code returns201with no error and no warning, and the created entry then reports the reservation code. To record an amount against one specific unit, useproperty_idinstead.
[3.11.0] - 2026-08-14
Added
POST /reservationsnow accepts an optionalchannel_id— an external reservation reference, typically the booking id in your own system — which makes the create idempotent. Within one Hostex account a givenchannel_idcan only ever produce one reservation, so a create that is retried after a timeout cannot result in a duplicate booking: submitting the same value again returns the existing reservation instead of creating a second one. Uniqueness is enforced by a database primary key rather than a check-then-insert, so a retry that runs concurrently with the original request is safe as well. The scope is the Hostex account — sub-accounts share their parent's namespace — not your application and not the custom channel, and a value stays claimed permanently, including after the reservation is cancelled. Letters and digits only (^[A-Za-z0-9]+$, at most 32 characters): the value becomes part of the reservation code, where punctuation takes on special meaning in some code paths. It is stored as the reservation'schannel_idand can be read back throughGET /reservations?channel_id=— the recommended way to find out whether a create actually landed after a timeout.POST /reservationsnow returnsstatusnext toreservation_code(wait_accept/wait_pay/accepted/cancelled/denied/timeout). A newly created reservation is alwaysaccepted; when an existingchannel_idis submitted again the field reflects the current state of the reservation that already exists — replaying one that has since been cancelled returns200withstatus=cancelled, meaning the reservation is cancelled and the room is not held. Check this field rather than the HTTP status code.- New built-in custom channel Naver Reservation (
custom_channel_id = 35), returned byGET /custom_channelsfor every account without having to be created on the Custom Options page, so it can be treated as a constant. Available onhttps://api.hostex.io/v3only — it is not listed on the China site (https://api.myhostex.com/v3).
Fixed
GET /transactions:item_namenow follows the account's income / expense item dictionary for system items too. The built-in item list previously overwrote the dictionary entry, so a system item could be reported under a name other than the one the dictionary holds. The dictionary is now authoritative, and the built-in name is used only for system items that have no dictionary row.
[3.10.0] - 2026-07-31
Added
-
Three new webhook events covering income / expense entries, so subscribers no longer have to poll
GET /transactionsover a wideaction_atwindow — editing an entry does not move itsaction_at, so a narrow polling window silently misses edits to older entries:transaction_created— an entry was created, whether throughPOST /transactions, the Hostex portal, or a system-generated charge such as a refund.transaction_updated— an existing entry was modified.transaction_deleted— an entry was deleted; remove it from your mirror.
Payloads follow the existing thin-payload convention (
{ event, transaction_id, timestamp }); fetch the current state withGET /transactions?id={transaction_id}. Subscribe throughPOST /webhooksorPATCH /webhooks/{id}like any other event. See Webhook Event Types.
[3.9.1] - 2026-07-17
Changed
POST /conversations/{conversation_id}(Send Message) documentation now states explicitly that the endpoint is not idempotent and returns no message ID. If a request times out the outcome is unknown — Hostex cannot determine whether the channel has already delivered the message, and that uncertainty cannot be resolved on our side, so no idempotency guarantee is offered. Behaviour is unchanged; the guarantee is simply now written down, along with our recommendation: on error, retry — a guest receiving a duplicate message is better than a guest receiving no message at all.
[3.9.0] - 2026-06-25
Added
GET /reservationsnow returns apaymentobject 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) andstatus(unreceived/partial/received/over_received). Settlement is computed at the order level, so stays sharing the samereservation_codecarry identicalpaymentvalues. Most meaningful for Hostex Direct (manually created) reservations whose income is recorded viaPOST /transactions.
[3.8.0] - 2026-06-17
Added
GET /listings/airbnb/price_and_rulesandPOST /listings/airbnb/price_and_rulesnow supporthigh_rated_guest_discountandmobile_only_discountboolean fields to read and toggle Airbnb's highly-rated guest discount and mobile-only discount promotions.
[3.7.0] - 2026-06-12
Added
- New
Messagesendpoints to manage special offers and pre-approvals in a conversation (previously only available in the Hostex Inbox UI):GET /conversations/{conversation_id}/special_offerslists the special offers and pre-approvals sent in a conversation, with their current status (active/accepted/declined/expired/withdrawn). The returnedidis used to withdraw an offer. Exposed as MCP toolsearch_special_offers.POST /conversations/{conversation_id}/special_offerssends a special offer to the guest, inviting them to book the given listing (listing_id) for the given dates at a custom totalprice, 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 requirerate_plan_idandcurrency. Offers typically expire 24 hours after being sent. Exposed as MCP toolsend_special_offer.POST /conversations/{conversation_id}/preapprovalspre-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 toolsend_preapproval.DELETE /conversations/{conversation_id}/special_offers/{special_offer_id}withdraws a previously sent offer that is still active. Exposed as MCP toolwithdraw_special_offer.
- New read endpoints for listing-level pricing and rules, complementing the existing write endpoints:
GET /listings/airbnb/price_and_rulesreturns an Airbnb listing's current prices, fees, discounts, booking settings and availability rules, read in real time from Airbnb. The response mirrors thesettingsobject accepted byPOST /listings/airbnb/price_and_rules(values can be written back as-is), pluseligible_cancellation_policieslisting the validcancellation_policyvalues for the listing. Rate limited to 120 requests per minute, same as write operations.GET /listings/vrbo/price_and_rulesreturns 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 thesettingsobject accepted byPOST /listings/vrbo/price_and_rules.
[3.6.0] - 2026-06-01
Added
POST /reviews/{reservation_code}now accepts an optionalcategory_ratingsobject 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). Whenhost_review_scoreis omitted, theoverall_ratingvalue is used as the review score.- 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):
POST /listings/airbnb/price_and_rulesupdates 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.POST /listings/vrbo/price_and_rulesupdates a Vrbo listing's prices, fees and booking rules (base_priceor per-weekdaynightly_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.
[3.5.0] - 2026-05-25
Added
- New
Messageswrite endpoint to manage the host-side note attached to a conversation thread (the samenotealready exposed read-only onGET /conversations/{conversation_id}):PATCH /conversations/{conversation_id}/notesets 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 ornullinnoteto clear the existing note (max 5000 chars). Exposed as MCP toolupdate_conversation_note.
- New write operations on the
Propertygroup dictionary, complementing the existingGET /groups:POST /groupscreates a new property group (namerequired; optionalproperty_idsto pre-attach properties). Group names must be unique within the operator's account. Exposed as MCP toolcreate_property_group.PATCH /groups/{id}updates a group.namerenames it;property_idsreplaces the full property assignment (empty array detaches all). Exposed as MCP toolupdate_property_group.DELETE /groups/{id}deletes a group and its pivot rows; the underlying properties are unaffected. Exposed as MCP tooldelete_property_group.
- New write operations on the
Propertytag dictionary, complementing the existingGET /tags:POST /tagscreates a new property tag (namerequired; optionalcolorfrom 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 toolcreate_property_tag.PATCH /tags/{id}updates a tag.name/colorchange the tag itself;property_ids/room_type_idseach replace the full attached list (empty arrays detach all). Exposed as MCP toolupdate_property_tag.DELETE /tags/{id}deletes a tag and its property / room-type pivot rows. Exposed as MCP tooldelete_property_tag.
- New
Reservation Tagssection with read/write coverage of the operator's reservation tag dictionary (the tags thatPOST /reservations/{stay_code}/tagscan attach to a reservation):GET /reservation_tagslists the operator's reservation tag dictionary, including both system default tags (is_default = true, shared across operators) and the operator's own custom tags. Supportsoffset/limitpagination,idlookup andkeywordsubstring search. Exposed as MCP toolsearch_reservation_tags.POST /reservation_tagscreates a new custom tag (tag_nameonly, 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 toolcreate_reservation_tag.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 tooldelete_reservation_tag.
- New
Calendar Share Linkssection with read/write coverage of public, read-only calendar share links (the same artefacts the Hostex Host Portal exposes under "Share calendar"):GET /calendar_share_linkslists the operator's share links. Each entry returnsid,scope(entire/partial), the shareurland theproperty_idsthe link exposes (empty whenscope = entire). Exposed as MCP toolsearch_calendar_share_links.POST /calendar_share_linkscreates a new share link.scope = entirecovers every property (idempotent: returns the existing link if any).scope = partialrequires a non-emptyproperty_idslist; each id must belong to the operator. Exposed as MCP toolcreate_calendar_share_link.DELETE /calendar_share_links/{id}invalidates a share link; anyone holding the previous URL will get ashare link invaliderror. Exposed as MCP tooldelete_calendar_share_link.
Changed
GET /tagsx-mcp metadata:descriptionandintent_examplesclarified — this endpoint returns property tags (the tags attached to properties / room types), not reservation tags. The new MCP toolsearch_reservation_tagscovers the reservation tag dictionary. The response shape itself is unchanged.GET /reservations: each reservation now includescheckin_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 — including images not yet linked to a guest record (client_idisnullfor those). Each entry hasid,client_idandurl(extra-large CDN variant). Existing per-guestguests[].id_imagesis unchanged.GET /reservations: each reservation now exposesrates.tax, the reservationTAXESamount as a standalone{ currency, amount }object (nullwhen the reservation has no taxes). The aggregatedrates.rateandrates.detailsare unchanged.
[3.4.1] - 2026-05-21
Changed
- BREAKING
GET /knowledge_bases:property_idsquery parameter is now a comma-separated integer string (e.g.1,2,3) instead of a repeated array, matchingGET /automation/actionsand the rest of the v3 list endpoints. - BREAKING
POST /knowledge_basesandPATCH /knowledge_bases/{id}:scope_property.scope_idsrenamed toscope_property.idsso the field name matches the value returned byGET /knowledge_basesandGET /knowledge_bases/{id}.
Added
GET /knowledge_bases/{id}: response now includesprocess_status(string enumwaiting/processing/done/failed), matching the list endpoint.GET /automation/actions: each item inactions[]now includestype(message/review) andstay_code(linked reservation code, may benull).POST /automation/actions/{plan_id}/execute: documented400response for unsupported plan types orreviewplans whose reservation has not checked out yet.
Fixed
GET /knowledge_bases: filtering bychannel_typesno longer crashes with aTypeError;scope_propertyin 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 emptyby_propertyset.GET /knowledge_bases/{id}: samescope_propertycorrectness fix as above.POST /knowledge_basesandPATCH /knowledge_bases/{id}: whenscope_channel.typeisall, the upstream channel list is no longer populated with anunknownsentinel; permission failures onPATCH /knowledge_bases/{id}andDELETE /knowledge_bases/{id}now consistently return404.GET /knowledge_bases: pagination now respects arbitraryoffsetvalues instead of always advancing by a full page (previousceil(offset / limit) + 1madeoffset=5, limit=10return rows 11–20 instead of 6–15).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. Thetotalcount also matches the number of returnedactions[]rows (plans missing their rule or detail row are filtered in SQL instead of skipped in PHP).POST /automation/actions/{plan_id}/execute: same-day reviews are no longer rejected as "not yet checked out" — the check-out date comparison now uses the date portion of the reservation's check-out timestamp instead of a lexicographic string compare.
[3.4.0] - 2026-05-20
Added
- New
Knowledge Basesection 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:GET /knowledge_basesto list entries, with pagination and optional filtering by property or channel.GET /knowledge_bases/{id}to fetch the full detail of a single entry.POST /knowledge_basesto create a new entry.PATCH /knowledge_bases/{id}to update an existing entry.DELETE /knowledge_bases/{id}to delete an entry.
- New
Channelssection with read-only access to the operator's connected channel accounts and the listings synced from them:GET /channel_accountsreturns the third-party platform accounts the operator has connected (Airbnb, Booking.com, etc.) withchannel_type,username,origin_account_idand a readableauth_statusenum (active/connecting/disconnected/exception). Supports filtering byidandchannel_type. Accounts withchannel_type=booking_siteare excluded. Exposed as MCP toolsearch_channel_accounts.GET /listingsreturns the listings (channel-side properties) synced under those accounts withlisting_id,channel_type,channel_account_id,title,cover,url,inventory, a readableshelf_statusenum and ametadatapassthrough object exposing the normalized channel-side data Hostex caches internally (geo, pictures, price list, etc.; shape varies by channel). Supports filtering bychannel_account_id,listing_idandchannel_type. Exposed as MCP toolsearch_listings.
GET /tasks: new optionalidquery parameter for fetching a single task by its internal id (still scoped to the current operator). Other filters remain unchanged.GET /transactions: new optionalidquery parameter for fetching a single transaction entry by its internal id. Whenidis supplied,start_dateandend_datemay be omitted; otherwise the existing date-range requirement (and 366-day cap) still applies.GET /reservations: each entry inguestsnow includes anid_imagesarray exposing the ID document images uploaded for that guest. Each item carries the imageidand aurlpointing to the extra-large variant served by the image CDN. Returns an empty array when no image has been uploaded.GET /conversations/{id}: each entry inmessagesnow includes:sender_name: display name of the sender when known (operator account name for host-side messages,HostGPTfor HostGPT-generated messages, localized HostGPT label for shadow preview messages).nullfor guest messages and other cases where the sender cannot be resolved.sources: knowledge sources cited by HostGPT to generate the message, grouped bytype(e.g.checkin_guide,automation_reply,host_knowledge,thread,host_assistant). Each group exposesdocs[].title/docs[].fragment/docs[].source_type/docs[].link_id. Empty array for human-sent messages and HostGPT messages without resolved citations.
PATCH /reservations/{stay_code}/check_in_details: new optionalid_requiredfield 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 theneed_credentialfield of the per-stay check-in guide and triggers the same downstream check-in unlocking logic as the Hostex Host Portal.GET /reservations: each entry incheck_in_detailsnow exposes the matchingid_requiredstring enum (defaults tonot_requiredwhen no setting has been applied to the stay).GET /reservations:order_bynow acceptscreated_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 remainsbooked_at.POST /tasks: new optionalstay_codefield links the task to a specific reservation by writing into theschedule_task__reservationpivot. Whenstay_codeis supplied withoutproperty_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".GET /tasks: each task entry now includes astay_codefield (string, nullable) — the reservation the task is linked to, ornullfor unlinked tasks.- New
Propertywrite endpoint:POST /propertiescreates a new property (room) under the current operator. Onlytitleis 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.
- New
Room Typewrite endpoint:POST /room_typescreates a new room type under the current operator. Optionally acceptsproperty_idsto 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.
- New
GET /pricing_ratiosendpoint (underListing 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 exposeschannel_type,listing_id,listing_title,ratio(percent) andreadonly. This enables a "change price by property / room type" workflow at the skill / client layer without a dedicated server endpoint: read the ratios, computetarget_price = round(base_price * ratio / 100)for every non-readonly listing, then callPOST /listings/pricesonce per listing (readonly: truelistings — e.g. Airbnb child rate plans — must be skipped).
[3.3.1] - 2026-05-11
Fixed
GET /transactions:start_dateandend_dateare now consistently interpreted in the operator's configured timezone, matching how entries are stored and howaction_atis 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.POST /transactionsandPATCH /transactions/{id}:action_atvalues supplied as UTC ISO 8601 are now correctly converted to the operator's timezone before being persisted, so the round-trip withGET /transactionsreturns the same instant.
[3.3.0] - 2026-05-08
Added
GET /reservations: new optionalchannel_idquery parameter to filter reservations by the channel-side reservation ID (the same value returned aschannel_idin the response).
[3.2.0] - 2026-04-29
Added
- New
Incomes & Expensessection, with full read/write coverage of income and expense entries (transactions):GET /transactionsfor querying entries. Supports filtering by date range (start_date/end_date),property_id,stay_code,direction,item_id,payment_method_id,currencyandkeyword. Each entry exposesdirection(income/expense),link_type(property/reservation/operator) andstatus(paid/outstanding) as readable string enums, and resolvesitem_name/payment_method_namefrom the dictionaries below.POST /transactionsto record a new entry. The link target is inferred from the request: providestay_codeto record against a specific stay,property_idto record against a property, or neither for an operator-level entry (master operator only).amountis always positive — sign is derived fromdirection.currencyis required unlessstay_codeis provided, in which case it is inherited from the reservation order.PATCH /transactions/{id}to update an entry'samount,item_id,payment_method_id,action_atornote. Direction, link target and currency are immutable.DELETE /transactions/{id}to permanently delete an entry.- New dictionary endpoints
GET /income_items,GET /expense_items,GET /income_methodsandGET /expense_methodsdecode theitem_id/payment_method_idreturned byGET /transactions.
- New
Taskwrite endpoints:POST /tasksto create a schedule task. Optionalproperty_idandstaff_idlink the task to a property and assign a staff;levelis only meaningful for cleaning tasks.expected_date/expected_timeare interpreted in the operator's configured timezone. Returns the newtask_id.PATCH /tasks/{id}to update an existing task. All fields are optional; passproperty_id=0orstaff_id=0to detach. The fullstatuslifecycle (pending/in_progress/completed/cancelled) can be set here.expected_date/expected_timeare interpreted in the operator's configured timezone.DELETE /tasks/{id}to delete a task.
- New
Staffwrite endpoints:POST /staffsto create a schedule staff (created as active). Useproperty_idsto scope the staff to specific properties. International operators must providemobilein+<country code> <number>format.PATCH /staffs/{id}to update an existing staff. Passingproperty_idsreplaces the full assignment list; pass an empty array to clear.is_activetoggles enable/disable.DELETE /staffs/{id}to delete a staff (and remove their property assignments).
Changed
PATCH /reservations/{stay_code}(Update Reservation Basic Info): the path parameter is nowstay_codeinstead ofreservation_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-facingPOST /reservations/{reservation_code}/approve|declinekeepreservation_codesince they operate at the order level.
Fixed
GET /reservations: thecustom_channel.idfield now returns the same id used byGET /custom_channels(previously returned an internal table primary key that could not be matched against the dictionary).
[3.1.2] - 2026-04-28
Added
- New
TaskendpointsGET /tasksandGET /staffsfor querying schedule tasks and staffs. GET /taskssupports filtering by date range (start_date/end_date),staff_id,property_id,typeandstatus.- Task
type,statusandlevelare returned as readable string enums (e.g.cleaning,pending,standard).
[3.1.1] - 2026-03-10
Added
- New
PropertyendpointGET /tagsreturning all tags with their associated property and room type ids. GET /propertiessupportstag_idfilter and now returns atagsarray on each property.GET /room_typessupportsidandtag_idfilters and now returns atagsarray on each room type.
[3.1.0] - 2026-01-21
Added
- New
PropertyendpointGET /groupsreturning all property groups with their associated property ids. GET /propertiessupportsgroup_idfilter and now returns agroupsarray on each property.
[3.0.0]
Added
- Initial release of the Hostex OpenAPI v3, with endpoints covering Properties, Room Types, Reservations, Availabilities, Listing Calendar, Messaging, Reviews, Automation and Webhooks.
