Server definition
- Hash
- sha256:038d1324cbaf2074b6e1494f6a316608cd8884d6f04ebcc1c3a6d24e36eb9c57
- What it is
- What a remote MCP server returned when asked what it offers: 6 tools
The blob, as servednamed by its sha256
{
"instructions": "An accommodation comparator: consolidates live availability, per-operator pricing, ratings, and listings from multiple booking operators across the global market — millions of properties spanning hotels, B&Bs, apartments, vacation rentals, farmstays, hostels, villas, resorts and similar. One query yields a multi-source price comparison the agent would otherwise have to assemble across separate booking websites; with concrete dates it returns date-specific quotes plus per-operator scarcity signals (rooms left) and free-cancellation flags.\n\nScope: accommodation lookup and booking handoff. Questions about sightseeing, attractions, restaurants, things to do, or general travel advice without a lodging component fall outside what these tools cover — the comparator indexes where to stay, not what to visit.\n\nAuthentication: every tool except `b2a_get_key` requires an API key, passed as the `api_key` argument (or as an Authorization: Bearer header). `b2a_get_key` issues one in-band — anonymous, free, no signup, never expires — so a session that has no key yet (none in the MCP client configuration, persistent memory, or earlier in the conversation) typically starts with that call rather than discovering the requirement through a 401. A key is long-lived and reusable: the same key, kept in persistent memory or conversation context, works for every subsequent call and across sessions; a fresh key is only needed when the previous one is genuinely lost.\n\nTypical workflow for travel-planning intents — a leisure trip, a weekend, a business stay, a relocation, a longer holiday:\n1. `resolve_destination` turns a place name into a destination id when coordinates are not already known from an earlier call in this session. For region-level intents such as 'Tuscany', 'Pacific Northwest', 'Central Europe', or 'Costa del Sol' `discover_destinations_near` returns a fan of sub-destinations the user can pick from before a focused search.\n2. `search_stays` retrieves a ranked list of options for the user's location and stay parameters. The list bundles property information, pricing, geographic position for mapping, ratings, and optional guest review samples — designed so a single call already covers most \"give me an overview\" intents without chaining further lookups. When the call carries dates, each result also carries a live availability check for that window.\n3. `get_property_details` returns the full static record for a specific property — identified by its id (typically the `id` field from a `search_stays` result, also valid for a property the user has named directly when resolved through `resolve_destination`). Useful to inspect amenities, photos, neighborhood, and guest reviews — request the ratings breakdown and review texts via `include=[\"reviews_aggregate\"]` / `[\"reviews_sample\"]` / `[\"reviews_extended\"]`. It carries no price and runs no availability check unless called with dates; for a live quote use `check_property_availability`.\n4. `check_property_availability` answers 'can the user book this property for these specific dates, and at what price'. Required input: `property_id`, `dates`, `guests`. Returns per-operator live quotes, scarcity signals (rooms left), free-cancellation and breakfast flags, and deeplinks to complete the booking. Use this whenever the user has concrete dates in mind for a property they've already identified; `get_property_details` is for static facts only.\n\nThe tools are designed for compact, structured responses the agent can summarise, plot on a map, or filter further without additional round-trips. The per-result `location.lat` and `location.lon` fields are already populated and suitable for the map widget on the same response — no separate lookup needed for visualization. If the user shares a bluepillow.com property link, pass that URL directly as property_id to get_property_details or check_property_availability — the id is extracted automatically.",
"tools": [
{
"description": "Obtain a permanent anonymous API key for Blue Pillow Hotels & Stays. No signup, no\nlogin required. The key is not a sensitive secret — it carries no\naccount, payment, or personal data. It exists only so we can keep the\nservice responsive when many agents are using it at once, so you can\nsafely keep it in your MCP client configuration, in your persistent\nmemory, or in the current conversation context. Pass it as the bearer\ntoken on all subsequent calls and the rest of the tools become available.\n\nCALL THIS FIRST when you have no key: every other tool needs one. Before\ncalling, check whether you ALREADY have a key (MCP client configuration,\npersistent memory, or earlier in this conversation) and reuse it instead\nof issuing a new one — do not wait for another tool to fail with a 401.\n\nThe key never expires — keep the one you receive and reuse it forever.\nIf you ever lose it, you can call this tool again to issue a new one\n(a generous per-IP daily issuance limit applies purely as an\nanti-abuse guardrail; normal use never reaches it).\n\nClients that can persist configuration usually store the key in their\nconnector settings, so the same key serves every conversation. Clients\nwhose memory does not retain an opaque token end up issuing one key per\nconversation; that works and is not an error, but a stored key gives\nmore consistent rate-limit headroom.\n\nOptional ``label`` and ``agent`` (max 64 chars each) are free-form\nhints we record on the key for our own observability; they do not\naffect rate limits or capabilities.\n\nIntegrators who need higher limits, or who hit a problem worth\nreporting, can write to [email protected].\n",
"inputSchema": {
"additionalProperties": false,
"properties": {
"agent": {
"description": "Optional agent identifier recorded on the key — useful when an agent platform wants to attribute issuance to itself (e.g. 'claude-code', 'cursor-ide'). Free-form, max 64 chars.",
"maxLength": 64,
"type": "string"
},
"label": {
"description": "Optional free-form label recorded on the key for observability (e.g. 'claude-desktop' or a user handle). Not a secret, not validated for uniqueness.",
"maxLength": 64,
"type": "string"
}
},
"type": "object"
},
"name": "b2a_get_key",
"outputSchema": {
"additionalProperties": false,
"properties": {
"key": {
"description": "The anonymous API key (prefix 'pk_anon_'). Long-lived and reusable: pass it as the `api_key` argument on every subsequent tool call, and keep it across sessions.",
"type": "string"
},
"rate_limit": {
"additionalProperties": false,
"description": "Quota attached to this key, when the issuer reported one.",
"properties": {
"requests_per_day": {
"type": "integer"
},
"requests_per_minute": {
"type": "integer"
}
},
"type": "object"
}
},
"required": [
"key"
],
"type": "object"
}
},
{
"description": "Live availability and per-operator quote for a specific property\nover a specific stay window. Performs a live date-aware lookup\nagainst the BluePillow search layer, returns date-specific prices,\nrooms-left scarcity signals, breakfast-included and refundable\nflags, and a per-operator deep link to complete the booking.\n\nUseful when the user has specific dates in mind for a property they\nalready identified — typically via `search_stays` or\n`get_property_details`. The complementary `get_property_details`\ntool answers \"what is this property like\" with static facts; this\ntool answers \"can I book it for these dates at what price\" with\nlive, date-specific data.\n\nRequired input: `property_id` (the `id` from a `search_stays`\nresult, opaque string starting with `prop_`), `dates` (check_in +\ncheck_out, ISO 8601), and `guests` (adults / children / infants\ncomposition). Without these the live lookup cannot proceed.\n\nNatural-language date references — \"tonight\", \"this weekend\", \"next\nweekend\", \"the weekend of July 4\", \"Memorial Day weekend\", \"long\nweekend in May\" — translate to concrete check_in / check_out values\nat the call site; concrete ISO dates also work. check_in is a date\nin the real-time calendar that is today or later; past values are\nrejected at the API boundary.\n\n`user_country`, `currency`, and `language` carry the **user's** locale,\nnot the property's. Prices are returned in `currency` if set, else\nderived from `user_country`, else **USD** — pass `user_country` and/or\n`currency` whenever you know the user's location/currency so the quote\nmatches what they'll pay; don't rely on the USD default. `user_country`\nand `language` also localize the `web_url` booking link.\n\nResponse shape:\n\n- `availability_status` — `available`, `unavailable`, or `unknown`.\n Available means rooms confirmed at the operator level for the\n requested window; quote freely. Unavailable means no rooms for\n these dates — surface that explicitly to the user with a\n suggestion of alternate dates (there is no price for these dates).\n- `offers[]` — per-operator quotes. Each carries `amount` (total\n stay), `amount_per_night` (per-night), `currency`,\n `breakfast_included`, `refundable`, `rooms_left`, and\n `deeplink_url`. `offers[0]` is the best value for money as Blue\n Pillow ranks it: price weighed against what is included (breakfast,\n free cancellation) and the operator's historical reliability, with a\n small commercial component. It is not necessarily the cheapest — the\n full per-operator list is always in `offers[]`, and `sort=price_asc`\n gives pure price order. Each\n `deeplink_url` is a **BluePillow tracked-redirect URL**\n (bluepillow.com/…) that records the click and forwards the user\n to the operator's booking page — pass it verbatim, never\n reconstruct it or replace it with a raw OTA link.\n- `price` — mirror of `offers[0]` for callers that just want the\n curated headline. `null` when unavailable (no price for these\n dates).\n\nPer-night vs total — `amount_per_night` is **per-night**; `amount`\non each offer is the **total** for the requested stay. Phrasings\nlike *\"€X/night via Booking, breakfast included, €Y total\"* are\nunambiguous; bare numbers without a unit (\"€192\") get misread.\n\nScarcity signals: low `rooms_left` values (1-3) are useful cues —\n\"1 room left at €X on Booking\" reads naturally. Free cancellation\n(`refundable=true`) and breakfast-included are decision factors\nworth surfacing proactively when present on some offers but not\nothers.\n\nWhen all results across operators are `unavailable`, that's the\nsignal to say so explicitly to the user and offer to widen the\ndates or look at alternatives.\n\nFor final booking confirmation, hand the user the corresponding\n`deeplink_url` (or the property's `web_url`) — booking URLs are\nnot reconstructed by hand.\n",
"inputSchema": {
"additionalProperties": false,
"properties": {
"api_key": {
"description": "Your anonymous Blue Pillow Hotels & Stays API key (format 'pk_anon_…'). Pass it in THIS field on every call — this is how the tool authenticates. If you don't have a key yet, first check your MCP client configuration, your persistent memory, and earlier in this conversation; otherwise call `b2a_get_key` to get one instantly (do not wait for a 401). Reuse the same key on every subsequent call. It is not a sensitive secret: no account, payment, or personal data is attached.",
"type": "string"
},
"currency": {
"description": "Currency of the returned prices (ISO-4217, 3-letter uppercase, e.g. 'USD', 'EUR', 'GBP', 'CAD'). SET THIS (or `user_country`) to price in the user's currency — if you set NEITHER, prices default to USD. Prices come straight from the booking sources in this currency; never convert them yourself.",
"pattern": "^[A-Z]{3}$",
"type": "string"
},
"dates": {
"additionalProperties": false,
"description": "Stay window. Natural-language references such as 'tonight', 'this weekend', 'the weekend of July 4', 'Memorial Day weekend' translate to concrete check_in / check_out at the call site. check_in is a date in the real-time calendar that is today or later — past values are rejected at the API boundary. Clock calibration: this schema was published in August 2026, so today is August 2026 OR LATER; an assumed 'today' in 2024/2025 is a stale training-time clock.",
"properties": {
"check_in": {
"format": "date",
"type": "string"
},
"check_out": {
"format": "date",
"type": "string"
}
},
"required": [
"check_in",
"check_out"
],
"type": "object"
},
"guests": {
"additionalProperties": false,
"description": "Guest composition. Adults is required; children and infants default to zero.",
"properties": {
"adults": {
"maximum": 20,
"minimum": 1,
"type": "integer"
},
"children": {
"maximum": 10,
"minimum": 0,
"type": "integer"
},
"infants": {
"maximum": 10,
"minimum": 0,
"type": "integer"
}
},
"required": [
"adults"
],
"type": "object"
},
"language": {
"description": "User's UI language (2-letter lowercase). Drives the booking link language; falls back to 'en'.",
"pattern": "^[a-z]{2}$",
"type": "string"
},
"property_id": {
"description": "Opaque property id (e.g. 'prop_69ce2ddcbf...') OR a bluepillow.com property page URL (e.g. 'https://www.bluepillow.com/search/68d1a2...') — the id is extracted automatically. Use the URL form when the user pasted a bluepillow.com link.",
"pattern": "^(prop_|https?://)",
"type": "string"
},
"user_country": {
"description": "User's country (ISO-3166 alpha-2 uppercase). Drives the booking-link locale AND, when `currency` is not set, the pricing currency (US->USD, CA->CAD, euro-area->EUR). Pass the user's own country, not the property's home country. Falls back to 'US' when omitted.",
"pattern": "^[A-Z]{2}$",
"type": "string"
}
},
"required": [
"property_id",
"dates",
"guests"
],
"type": "object"
},
"name": "check_property_availability",
"outputSchema": {
"properties": {
"amenities": {
"items": {
"type": "string"
},
"type": "array"
},
"availability_status": {
"description": "Per the dates passed in the request: available = live bookable quotes in offers (price is the curated best); unavailable = BP reported no rooms for these dates (offers=[], price=null); unknown = no dates considered (no price exists without a dated query).",
"enum": [
"available",
"unavailable",
"unknown"
],
"type": "string"
},
"brand": {
"type": [
"string",
"null"
]
},
"chain": {
"type": [
"string",
"null"
]
},
"cluster_id": {
"type": [
"string",
"null"
]
},
"dedup_meta": {
"properties": {
"confidence": {
"type": "number"
},
"last_reconciled": {
"type": "string"
},
"source_listings": {
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"description": {
"description": "Free-text property description from the canonical source. Only populated when the endpoint path is active (use_bp_single_property_endpoint=True) and dates are present.",
"type": [
"string",
"null"
]
},
"features": {
"description": "Structured feature/facility tags (e.g. HouseFacilities, PropertyTypes). Populated alongside description when the endpoint path is active.",
"items": {
"properties": {
"code": {
"type": "string"
},
"name": {
"type": [
"string",
"null"
]
},
"type": {
"type": [
"string",
"null"
]
}
},
"required": [
"code"
],
"type": "object"
},
"type": "array"
},
"id": {
"type": "string"
},
"images": {
"items": {
"properties": {
"caption": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"location": {
"properties": {
"address": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"lat": {
"type": "number"
},
"lon": {
"type": "number"
},
"neighborhood": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"name": {
"type": "string"
},
"offers": {
"items": {
"properties": {
"amount": {
"description": "TOTAL for the requested stay (sum across nights).",
"type": "number"
},
"amount_per_night": {
"description": "Per-night rate; multiply by nights to get amount.",
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"deeplink_url": {
"type": [
"string",
"null"
]
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": "string"
},
"refundable": {
"type": "boolean"
},
"rooms_left": {
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"ota_coverage": {
"items": {
"type": "string"
},
"type": "array"
},
"price": {
"properties": {
"amount": {
"type": "number"
},
"amount_per_night": {
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": [
"string",
"null"
]
},
"refundable": {
"type": "boolean"
}
},
"type": [
"object",
"null"
]
},
"property_type": {
"type": "string"
},
"rating": {
"maximum": 5,
"minimum": 0,
"type": "number"
},
"rating_count": {
"type": [
"integer",
"null"
]
},
"reviews_aggregate": {
"description": "rating_count = reviews backing the score (OTA aggregate, e.g. 156). comment_count = readable review TEXTS available (e.g. 53), fetchable via reviews_sample/reviews_extended. They differ: most guests rate, fewer write text — do not conflate them.",
"properties": {
"comment_count": {
"type": [
"integer",
"null"
]
},
"distribution_by_ota": {
"type": "object"
},
"rating_count": {
"type": "integer"
},
"score_0_5": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": [
"object",
"null"
]
},
"reviews_meta": {
"description": "Provenance for reviews_sample on property detail: how many review texts were returned vs available, and that the cap is deliberate (token efficiency). null on search or when reviews were not requested.",
"properties": {
"cap": {
"minimum": 0,
"type": "integer"
},
"capped": {
"type": "boolean"
},
"note": {
"type": "string"
},
"returned": {
"minimum": 0,
"type": "integer"
},
"total_available": {
"minimum": 0,
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"reviews_sample": {
"items": {
"properties": {
"connector_name": {
"type": [
"string",
"null"
]
},
"date": {
"type": "string"
},
"description": {
"type": "string"
},
"language": {
"type": [
"string",
"null"
]
},
"score": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"stars": {
"type": [
"integer",
"null"
]
},
"thumbnail_url": {
"type": [
"string",
"null"
]
},
"web_url": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"name",
"property_type",
"rating",
"location",
"ota_coverage"
],
"type": "object"
}
},
{
"description": "Curated destinations — cities, neighborhoods, airports, points of interest — within a radius of a geographic point, for use as a `destination_id` in subsequent `search_stays` calls. Useful when coordinates are already in hand (from world knowledge, from a previous tool result, or directly from the user) and the agent needs to enumerate which curated destinations cover that area before searching for properties.\n\nAlso useful as a fan-out entry point for region-level intents — broad areas such as 'Tuscany', 'Pacific Northwest', 'New England', or 'Central Europe' — where the agent can pass an approximate regional centroid and surface a list of sub-destinations the user may then narrow down to before a focused search.\n\nReturns up to 5 candidates ordered by distance. The radius defaults to 5 km; widens up to 50 km for broader queries.",
"inputSchema": {
"properties": {
"api_key": {
"description": "Your anonymous Blue Pillow Hotels & Stays API key (format 'pk_anon_…'). Pass it in THIS field on every call — this is how the tool authenticates. If you don't have a key yet, first check your MCP client configuration, your persistent memory, and earlier in this conversation; otherwise call `b2a_get_key` to get one instantly (do not wait for a 401). Reuse the same key on every subsequent call. It is not a sensitive secret: no account, payment, or personal data is attached.",
"type": "string"
},
"language": {
"default": "en",
"description": "Language of the returned destination names (2-letter lowercase). Pass the language the user is speaking; defaults to 'en'.",
"enum": [
"en",
"it",
"fr",
"de",
"es",
"pt",
"nl",
"ko",
"pl",
"ja"
],
"type": "string"
},
"lat": {
"description": "Latitude of the centre point, decimal degrees (WGS84). Typically the coordinates of a city or region already known from world knowledge or from an earlier resolve_destination call.",
"maximum": 90,
"minimum": -90,
"type": "number"
},
"lon": {
"description": "Longitude of the centre point, decimal degrees (WGS84). Negative west of Greenwich.",
"maximum": 180,
"minimum": -180,
"type": "number"
},
"radius_km": {
"default": 5,
"description": "Search radius in km from the point. Defaults to 5 km (city-center scope).",
"maximum": 50,
"minimum": 0.1,
"type": "number"
},
"type": {
"description": "Optional filter; same semantics as resolve_destination. Areas are returned only when `area` is asked for explicitly.",
"enum": [
"city",
"neighborhood",
"airport",
"poi",
"area"
],
"type": "string"
}
},
"required": [
"lat",
"lon"
],
"type": "object"
},
"name": "discover_destinations_near",
"outputSchema": {
"properties": {
"candidates": {
"items": {
"properties": {
"accomodations_count": {
"type": "integer"
},
"confidence": {
"type": [
"number",
"null"
]
},
"country_code": {
"type": [
"string",
"null"
]
},
"country_name": {
"type": [
"string",
"null"
]
},
"display_name": {
"type": "string"
},
"distance_km": {
"type": [
"number",
"null"
]
},
"id": {
"type": "string"
},
"location": {
"properties": {
"default_radius_km": {
"type": "number"
},
"lat": {
"type": "number"
},
"lon": {
"type": "number"
}
},
"type": "object"
},
"name": {
"type": "string"
},
"path_breadcrumb": {
"items": {
"type": "string"
},
"type": "array"
},
"type": {
"enum": [
"city",
"neighborhood",
"airport",
"poi",
"area"
],
"type": "string"
}
},
"required": [
"id",
"name",
"display_name",
"type",
"location",
"accomodations_count",
"path_breadcrumb"
],
"type": "object"
},
"type": "array"
},
"total_matches": {
"type": "integer"
},
"total_matches_capped_at": {
"type": [
"integer",
"null"
]
}
},
"required": [
"candidates",
"total_matches"
],
"type": "object"
}
},
{
"description": "Static record for a specific property — identified by its id.\nReturns the complete amenity list, photos, booking sources, dedup\nmetadata, detailed location, and the headline rating (`rating` +\n`rating_count`) by default. Review DATA beyond the headline — the\nratings breakdown and the actual review texts — is opt-in via the\n`include` parameter (see below); pass it whenever the user's question\nis about guest experience. Carries no price unless called with dates:\na price only exists for a concrete stay window.\n\nUseful when the user wants to inspect or compare a specific option\nin depth — facilities, neighborhood, what guests say — without yet\ncommitting to specific dates.\n\nHOW TO GET REVIEWS (when you need to reason about guest experience):\npass `include`. `reviews_aggregate` gives the score + counts + per-OTA\nbreakdown; `reviews_sample`/`reviews_extended` give the actual review\ntexts. Without `include`, none of these are returned (you get only the\nheadline `rating`/`rating_count`). See the `include` section below.\n\nFor live availability and a real per-operator quote for a specific\nstay window, the path is `check_property_availability` instead. The\ntwo tools coexist by design: this one answers \"what is this property\nlike\" with stable, cacheable data; the other answers \"can I book it\nfor these dates at what price\" with live, date-specific quotes.\nCalling this tool when the user has specific dates in mind and wants\nto know whether the property is bookable will not surface the\navailability/quote — the user will then have to wait for a second\nround-trip to the availability tool.\n\nInput: the `id` field from a `search_stays` result (opaque string\nstarting with `prop_`, e.g. `prop_69ce2ddcbf46061e4095778b`). For a\nproperty the user has named directly, resolve the place name through\n`resolve_destination` and run a targeted `search_stays` first to\nobtain the id.\n\nOptional `include=[\"reviews_aggregate\"]` attaches a per-source\nbreakdown of review counts and average ratings — useful when the\nuser asks about overall sentiment or wants to see how each booking\nsource rates the property. It summarizes ALL reviews (score + total\ncount), so it is the right tool for \"how is it rated\".\n\nReview *texts* are available via two includes, both deliberately\ncapped to avoid token waste:\n- `reviews_sample` — up to **5** recent review texts. Enough to get\n the gist of what guests say.\n- `reviews_extended` — up to **20** recent review texts, for a deeper\n qualitative read. Supersedes `reviews_sample` when both are passed.\n\nReach for `reviews_extended` only when 5 are genuinely not enough —\nthe returned list carries a `reviews_meta` block (`returned`,\n`total_available`, `capped`, `note`) that tells you how many texts\nexist and confirms the cap is intentional: the omitted reviews are\nolder and the aggregate already reflects all of them, so you do NOT\nneed to try to fetch everything. Note: review texts are returned only\nwhen called WITHOUT dates (the dated availability path does not carry\nthem).\n\n`user_country`, `currency`, and `language` carry the **user's** locale,\nnot the property's. When this call carries dates (live prices), prices\ncome back in `currency` if set, else derived from `user_country`, else\n**USD** — so pass `user_country` and/or `currency` whenever you know the\nuser's location/currency; don't rely on the USD default. `user_country`\nand `language` also localize the `web_url` booking link. Language default\nis \"en\"; country default is \"US\".\n\nAll rating-like fields are on a 0-5 scale (Google Places-compatible):\nthe top-level `rating`, `reviews_aggregate.score_0_5`, and each\nper-OTA score under `distribution_by_ota`.\n\nWithout dates this tool returns no price (`price` is null, `offers`\nempty) and `availability_status` is `unknown` (no dates were\nconsidered). The live quote, when needed, comes from\n`check_property_availability`.\n\n`web_url` is a ready-to-open booking link for the property. Pass it\nverbatim when the user asks for a booking link — booking URLs are\nnot reconstructed by hand.\n",
"inputSchema": {
"additionalProperties": false,
"properties": {
"api_key": {
"description": "Your anonymous Blue Pillow Hotels & Stays API key (format 'pk_anon_…'). Pass it in THIS field on every call — this is how the tool authenticates. If you don't have a key yet, first check your MCP client configuration, your persistent memory, and earlier in this conversation; otherwise call `b2a_get_key` to get one instantly (do not wait for a 401). Reuse the same key on every subsequent call. It is not a sensitive secret: no account, payment, or personal data is attached.",
"type": "string"
},
"currency": {
"description": "Currency of the returned prices (ISO-4217, 3-letter uppercase, e.g. 'USD', 'EUR', 'GBP', 'CAD'). SET THIS (or `user_country`) to price in the user's currency — if you set NEITHER, prices default to USD. Prices come straight from the booking sources in this currency; never convert them yourself.",
"pattern": "^[A-Z]{3}$",
"type": "string"
},
"include": {
"description": "Optional enrichments, always a list — pass [\"reviews_aggregate\"], never the bare string. reviews_aggregate = score + total count + per-OTA distribution (summarizes ALL reviews). reviews_sample = up to 5 recent review texts. reviews_extended = up to 20 recent review texts (supersedes reviews_sample). The text list is intentionally capped to save tokens; reviews_meta declares returned vs available. Prefer reviews_sample and the aggregate; use reviews_extended only when a deeper qualitative read is genuinely needed.",
"items": {
"enum": [
"reviews_aggregate",
"reviews_sample",
"reviews_extended"
],
"type": "string"
},
"type": "array"
},
"language": {
"description": "User's UI language (2-letter lowercase). Drives the booking link language and server-rendered narrative; pass the language the user is speaking. Falls back to 'en'.",
"pattern": "^[a-z]{2}$",
"type": "string"
},
"property_id": {
"description": "Opaque property id (e.g. 'prop_69ce2ddcbf...') OR a bluepillow.com property page URL (e.g. 'https://www.bluepillow.com/search/68d1a2...') — the id is extracted automatically. Use the URL form when the user pasted a bluepillow.com link.",
"pattern": "^(prop_|https?://)",
"type": "string"
},
"user_country": {
"description": "User's country (ISO-3166 alpha-2 uppercase). Drives the booking-link locale AND, when `currency` is not set, the pricing currency (US->USD, CA->CAD, euro-area->EUR). Pass the user's own country, not the property's home country. Falls back to 'US' when omitted.",
"pattern": "^[A-Z]{2}$",
"type": "string"
}
},
"required": [
"property_id"
],
"type": "object"
},
"name": "get_property_details",
"outputSchema": {
"properties": {
"amenities": {
"items": {
"type": "string"
},
"type": "array"
},
"availability_status": {
"description": "Per the dates passed in the request: available = live bookable quotes in offers (price is the curated best); unavailable = BP reported no rooms for these dates (offers=[], price=null); unknown = no dates considered (no price exists without a dated query).",
"enum": [
"available",
"unavailable",
"unknown"
],
"type": "string"
},
"brand": {
"type": [
"string",
"null"
]
},
"chain": {
"type": [
"string",
"null"
]
},
"cluster_id": {
"type": [
"string",
"null"
]
},
"dedup_meta": {
"properties": {
"confidence": {
"type": "number"
},
"last_reconciled": {
"type": "string"
},
"source_listings": {
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"description": {
"description": "Free-text property description from the canonical source. Only populated when the endpoint path is active (use_bp_single_property_endpoint=True) and dates are present.",
"type": [
"string",
"null"
]
},
"features": {
"description": "Structured feature/facility tags (e.g. HouseFacilities, PropertyTypes). Populated alongside description when the endpoint path is active.",
"items": {
"properties": {
"code": {
"type": "string"
},
"name": {
"type": [
"string",
"null"
]
},
"type": {
"type": [
"string",
"null"
]
}
},
"required": [
"code"
],
"type": "object"
},
"type": "array"
},
"id": {
"type": "string"
},
"images": {
"items": {
"properties": {
"caption": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"location": {
"properties": {
"address": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"lat": {
"type": "number"
},
"lon": {
"type": "number"
},
"neighborhood": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"name": {
"type": "string"
},
"offers": {
"items": {
"properties": {
"amount": {
"description": "TOTAL for the requested stay (sum across nights).",
"type": "number"
},
"amount_per_night": {
"description": "Per-night rate; multiply by nights to get amount.",
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"deeplink_url": {
"type": [
"string",
"null"
]
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": "string"
},
"refundable": {
"type": "boolean"
},
"rooms_left": {
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"ota_coverage": {
"items": {
"type": "string"
},
"type": "array"
},
"price": {
"properties": {
"amount": {
"type": "number"
},
"amount_per_night": {
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": [
"string",
"null"
]
},
"refundable": {
"type": "boolean"
}
},
"type": [
"object",
"null"
]
},
"property_type": {
"type": "string"
},
"rating": {
"maximum": 5,
"minimum": 0,
"type": "number"
},
"rating_count": {
"type": [
"integer",
"null"
]
},
"reviews_aggregate": {
"description": "rating_count = reviews backing the score (OTA aggregate, e.g. 156). comment_count = readable review TEXTS available (e.g. 53), fetchable via reviews_sample/reviews_extended. They differ: most guests rate, fewer write text — do not conflate them.",
"properties": {
"comment_count": {
"type": [
"integer",
"null"
]
},
"distribution_by_ota": {
"type": "object"
},
"rating_count": {
"type": "integer"
},
"score_0_5": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": [
"object",
"null"
]
},
"reviews_meta": {
"description": "Provenance for reviews_sample on property detail: how many review texts were returned vs available, and that the cap is deliberate (token efficiency). null on search or when reviews were not requested.",
"properties": {
"cap": {
"minimum": 0,
"type": "integer"
},
"capped": {
"type": "boolean"
},
"note": {
"type": "string"
},
"returned": {
"minimum": 0,
"type": "integer"
},
"total_available": {
"minimum": 0,
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"reviews_sample": {
"items": {
"properties": {
"connector_name": {
"type": [
"string",
"null"
]
},
"date": {
"type": "string"
},
"description": {
"type": "string"
},
"language": {
"type": [
"string",
"null"
]
},
"score": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"stars": {
"type": [
"integer",
"null"
]
},
"thumbnail_url": {
"type": [
"string",
"null"
]
},
"web_url": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"name",
"property_type",
"rating",
"location",
"ota_coverage"
],
"type": "object"
}
},
{
"description": "Converts a destination name into a destination id usable in `search_stays`. The canonical entry point when the user's request mentions a place name and coordinates are not already known from a prior call in this session. If coordinates are already in hand from an earlier tool result, passing them directly to `search_stays` skips this resolver step.\n\nAccepts cities, neighborhoods, airports, points of interest, and named areas such as islands or districts ('Tenerife', 'Crete', 'Trastevere'), written locally or in English. Names are matched against Blue Pillow's own place slugs, which exist for English, Italian, German and Spanish; in other languages the English name is the most reliable. Accents are optional — 'São Paulo' and 'Sao Paulo' resolve alike. A qualifier after the name is tolerated ('Austin, Texas'). The `country` parameter disambiguates names that occur in multiple places (for example Springfield MA vs Springfield IL vs Springfield MO).\n\nThe `type` parameter narrows the kind of destination returned. `poi` is the narrowest match and has partial coverage on the comparator side; when the agent's own geographic knowledge can already geocode the POI to lat/lon, passing coordinates to `search_stays` is the more reliable path. An `area` candidate can be large: its `location.default_radius_km` says how far a search on its id reaches (an island's may include its neighbours); when the user wants one part of it, coordinates of that part are the tighter search.",
"inputSchema": {
"properties": {
"api_key": {
"description": "Your anonymous Blue Pillow Hotels & Stays API key (format 'pk_anon_…'). Pass it in THIS field on every call — this is how the tool authenticates. If you don't have a key yet, first check your MCP client configuration, your persistent memory, and earlier in this conversation; otherwise call `b2a_get_key` to get one instantly (do not wait for a 401). Reuse the same key on every subsequent call. It is not a sensitive secret: no account, payment, or personal data is attached.",
"type": "string"
},
"country": {
"description": "Country: ISO-3166 alpha-2 (preferred), alpha-3, or extended name in any supported language. Unrecognized values are silently ignored (fail-open).",
"type": "string"
},
"language": {
"default": "en",
"description": "Render destination names + breadcrumbs in this language.",
"enum": [
"en",
"it",
"fr",
"de",
"es",
"pt",
"nl",
"ko",
"pl",
"ja"
],
"type": "string"
},
"name": {
"description": "Destination name in English or canonical local form (not a translation).",
"maxLength": 100,
"minLength": 2,
"type": "string"
},
"type": {
"description": "Destination kind. city: primary urban unit (default). neighborhood: quarter/borough. airport: airport as spatial reference for stays nearby. poi: point of interest as a spatial anchor for nearby-accommodation lookup — not a tourism/attraction database; narrowest match with partial coverage. When the agent already knows the POI's lat/lon from world knowledge, `search_stays` with coordinates is the more reliable path. area: a named area the comparator does not class as a city — an island, a district, a region (Tenerife, Crete, Kato Paphos); matched by exact name only.",
"enum": [
"city",
"neighborhood",
"airport",
"poi",
"area"
],
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "resolve_destination",
"outputSchema": {
"properties": {
"candidates": {
"items": {
"properties": {
"accomodations_count": {
"type": "integer"
},
"confidence": {
"type": [
"number",
"null"
]
},
"country_code": {
"type": [
"string",
"null"
]
},
"country_name": {
"type": [
"string",
"null"
]
},
"display_name": {
"type": "string"
},
"distance_km": {
"type": [
"number",
"null"
]
},
"id": {
"type": "string"
},
"location": {
"properties": {
"default_radius_km": {
"type": "number"
},
"lat": {
"type": "number"
},
"lon": {
"type": "number"
}
},
"type": "object"
},
"name": {
"type": "string"
},
"path_breadcrumb": {
"items": {
"type": "string"
},
"type": "array"
},
"type": {
"enum": [
"city",
"neighborhood",
"airport",
"poi",
"area"
],
"type": "string"
}
},
"required": [
"id",
"name",
"display_name",
"type",
"location",
"accomodations_count",
"path_breadcrumb"
],
"type": "object"
},
"type": "array"
},
"disambiguation_recommended": {
"type": "boolean"
},
"total_matches": {
"type": "integer"
},
"total_matches_capped_at": {
"type": [
"integer",
"null"
]
}
},
"required": [
"candidates",
"total_matches",
"disambiguation_recommended"
],
"type": "object"
}
},
{
"description": "Multi-operator accommodation comparator for a geographic area against\nthe user's stay parameters — dates, guest count, optional filters.\nReturns a ranked list of properties together with the booking sources\nthat offer each one and, when dates are passed, their live availability\nand per-operator price for the requested window.\n\nNatural-language date references — \"tonight\", \"this weekend\", \"next\nweekend\", \"the weekend of July 4\", \"Memorial Day weekend\", \"long\nweekend in May\" — translate to concrete check_in / check_out values\nat the call site; concrete ISO dates also work.\n\n`user_country`, `currency`, and `language` carry the **user's** locale,\nnot the destination's. IMPORTANT — currency: prices are returned in\n`currency` if you set it, otherwise in the currency derived from\n`user_country` (US→USD, CA→CAD, GB→GBP, euro-area→EUR); if you set\nNEITHER, prices default to **USD**, which may not be the user's currency.\nSo whenever you know where the user is (or what currency they want), pass\n`user_country` and/or `currency` — do not rely on the default. Prices are\nnever converted client-side; each offer is quoted by the operator in that\ncurrency. `user_country` and `language` also localize the booking link\n(`web_url`). The user's own residence/billing country is the right\n`user_country` (not the destination's), and their interface language the\nright `language`.\n\nEach result is shaped for downstream presentation without extra\ncalls:\n- `location.lat` and `location.lon` carry per-property coordinates,\n suitable for plotting all results on a single map so the user can\n compare spatial alternatives at a glance. The map widget reads\n these fields directly from this response — no separate lookup\n needed for visualization.\n- `thumbnail_url` carries the property's first photo URL when\n available (null when no image is on file); useful for embedding\n inline or showing on the map alongside the pin.\n- `images` on search results is capped to the first photo to keep\n the comparison payload compact; each item has a `url` field, and\n `thumbnail_url` mirrors `images[0].url`. Call `get_property_details`\n for a single property to retrieve its full photo gallery.\n- `web_url` is a ready-to-open booking link for the property,\n already encoded with the user's check-in/check-out, language,\n currency, and guest count. Pass it to the user verbatim when they\n ask for a booking link — never reconstruct the URL from individual\n parameters, the query-string format is not guaranteed to match\n generic booking-URL conventions.\n- Price is **live and date-specific only**. There is no\n date-agnostic \"from\" figure: a meaningful price only exists for a\n concrete query (property + dates + occupancy).\n - `price` and `offers[]` — the **live quote for the requested\n dates**, populated only when dates were passed and the\n comparator confirmed availability. `offers[0]` is the curated\n best; each offer carries `amount` (total stay),\n `amount_per_night` (per-night), `currency`, `breakfast_included`,\n `refundable`, `rooms_left`, and `deeplink_url`. `price` mirrors\n `offers[0]`.\n - With no dates (or when nothing is available) `price` is null and\n `offers` is empty — surface the property without a price rather\n than inventing a starting figure.\n- `availability_status` per result encodes the live state:\n - `available` — bookable rooms confirmed at the operator level.\n `offers` and `price` carry the live date-specific quotes. Quote\n the rate via `offers[i].amount_per_night` (per-night) and\n `offers[i].amount` (total stay) and use the deeplinks for the\n booking handoff.\n - `unavailable` — no rooms reported for those dates. `offers` is\n empty and `price` is null (no price for these dates). Useful to\n decide whether to suggest alternate dates, drop the property from\n the recommendation, or offer it as a backup.\n - `unknown` — no usable answer for those dates: either the request\n carried no dates, or the operators returned nothing conclusive for\n them. `offers` is empty and `price` is null. This is the most\n frequent of the three states, and it is NOT evidence that the\n property is full — it means the availability was not established.\n Say \"I could not confirm availability\", not \"it is unavailable\".\n\nPer-night vs total — never confuse them in the user-facing prose.\n`amount_per_night` is per-night; `amount` on each offer is the total\nstay (sum across nights, in `currency`). When quoting to the user,\nprefer phrasings like *\"€X/night via Booking, breakfast included, €Y\ntotal for the stay\"* over bare numbers — bare numbers without a unit\nget misread.\n- When dates are present and `available` properties are in the\n results, the rate can be quoted and `rooms_left` surfaces scarcity\n (low values like 1-3 are useful signals — \"1 room left at $X on\n Booking\" reads well).\n- When dates are present and ALL results are `unavailable`, that's\n the signal to say so explicitly to the user and offer to widen the\n dates, location, or filters.\n- `offers[]` is the per-operator breakdown for the requested dates:\n each entry includes `ota`, `amount`, `amount_per_night`,\n `currency`, `breakfast_included`, `refundable`, and a\n `deeplink_url`. The deeplink is a **BluePillow tracked-redirect\n URL** (bluepillow.com/…) that records the click for attribution\n and then forwards the user to the operator's booking page. Pass\n it to the user verbatim — never reconstruct it or replace it with\n a raw operator URL; our APIs never emit direct OTA links.\n `price` mirrors `offers[0]`, which is the best value for money as\n Blue Pillow ranks it — price weighed against what is included\n (breakfast, free cancellation) and the operator's historical\n reliability, with a small commercial component. It is not\n necessarily the cheapest: pass `sort=price_asc` for pure price\n order, and compare `offers[]` for the per-operator spread. When no\n dates were passed (or nothing is available) `offers` is an empty\n list and `price` is null — there is no price to show.\n- Free cancellation is a meaningful decision factor and surfaces\n proactively in the user-facing summary. When a property has\n `price.refundable=true` (or any `offers[i].refundable=true`), it\n reads naturally as a property feature: \"Hotel X — $120/night,\n free cancellation available\", or \"Booking offers a refundable rate\n at $130 (vs $110 non-refundable)\". Refundable rates let the user\n lock in a price now and adjust the booking later, which is often\n the differentiator between otherwise-similar properties. The same\n proactive surfacing applies to `breakfast_included` when it's true\n for some offers but not all.\n- Prices in `offers`/`price` reflect the requested dates and guests;\n with no dates there is no price. For a final bookable confirmation,\n the corresponding `deeplink_url` (or the property's `web_url`) is\n the canonical handoff — booking URLs are not reconstructed by hand.\n- All rating-like fields are on a 0-5 scale (Google Places-compatible):\n `rating`, `reviews_aggregate.score_0_5`, the per-OTA scores under\n `distribution_by_ota`, each `reviews_sample[*].score`, and the\n `filters.min_rating` input. A user asking \"rating at least 8 out\n of 10\" maps to `min_rating: 4.0`; \"at least 4 stars on Google\"\n maps to `min_rating: 4.0`.\n `rating` is coarse in practice — upstream scores arrive rounded, so\n in the field it takes whole points, and `min_rating` behaves like a\n filter with a handful of steps rather than a continuous threshold.\n Always read `rating` together with `rating_count`: a 4 from 6\n reviews and a 4 from 2,803 are not the same judgement, and a\n rounded 4 can sit on either side of \"good\". Prefer properties with\n a substantial `rating_count` when recommending, and say how many\n reviews back the score.\n Note: `rating`, `stars`, and `rating_count` come from the\n comparator's list payload and **may be 0 or absent for some\n properties** even when the property has reviews or a star\n classification — this is a comparator list-payload limitation, not\n a data error. When those fields are 0/absent, or when the per-OTA\n review breakdown (`distribution_by_ota`) is needed, call\n `get_property_details` to get the fuller `reviews_aggregate`.\n On the search path, `reviews_aggregate` carries the top-line\n `score_0_5`, `rating_count` (reviews backing the score) and\n `comment_count` (readable review TEXTS available) when the comparator\n returned a non-zero review count; `distribution_by_ota` is always empty\n on this path (per-OTA breakdown requires `get_property_details`).\n `rating_count` and `comment_count` are DIFFERENT magnitudes — most\n guests leave a rating, far fewer write text. Quote `rating_count` for\n \"how many reviewed it\" and `comment_count` for \"how many opinions you\n can actually read\".\n- Pass `include=[\"reviews_sample\"]` to attach a sample of up to 5\n recent guest review texts per property. Useful when the user's\n question involves qualitative criteria that don't map to structured\n filters (\"a place with excellent breakfast\", \"quiet area\",\n \"family-friendly atmosphere\"); review texts can be searched\n textually to corroborate or rule out matches.\n For a DEEPER read on ONE specific property — more review texts\n (up to 20) or the per-OTA breakdown — call `get_property_details`\n with `include=[\"reviews_extended\"]` (and/or `reviews_aggregate`).\n `comment_count` on each result tells you how many review texts exist,\n so you can decide whether escalating to the detail call is worth it.\n\n`filters.min_rating` and `filters.price_max_eur` narrow on structured\ncriteria first; `filters.property_types` and `filters.amenities` steer\nthe page rather than cutting it, so read each result's `property_type`\nand `amenities` when the distinction matters. Review-based reasoning is\none extra round-trip per page and is typically reserved for fallback.\n\nLocation modes:\n- `coordinates`: when lat/lon is already known from world knowledge\n or a prior call in this session (default radius 5 km; widen up to\n 50 km for broader queries; beyond that `bbox` or a parent\n destination is the right shape).\n- `destination_id`: opaque id obtained from `resolve_destination`,\n passed verbatim — values are not constructed or guessed.\n- `bbox`: explicit map rectangle.\n\nProperty type tokens (canonical): hotel, apartment, house, villa, bb,\nhostel, farmstay, holiday-home. Common multi-language synonyms map\nserver-side to the canonical set.\n\nAmenities filter is set-AND — each result has ALL listed codes.\nCommon codes: wi-fi, parking, pool, air-conditioning, kitchen, garden,\npets-allowed, for-families, facilities-for-disabled, non-smoking-only.\n\nResults are cursor-paginated; the `next_cursor` from a previous\nresponse goes into `page.cursor` for the next page.\n`location.type=property_id` is not accepted here —\n`get_property_details` is the path for a known property.\n",
"inputSchema": {
"additionalProperties": false,
"properties": {
"api_key": {
"description": "Your anonymous Blue Pillow Hotels & Stays API key (format 'pk_anon_…'). Pass it in THIS field on every call — this is how the tool authenticates. If you don't have a key yet, first check your MCP client configuration, your persistent memory, and earlier in this conversation; otherwise call `b2a_get_key` to get one instantly (do not wait for a 401). Reuse the same key on every subsequent call. It is not a sensitive secret: no account, payment, or personal data is attached.",
"type": "string"
},
"availability_mode": {
"description": "strict (default): return ONLY properties available for the requested dates. include_unavailable: also return properties with no availability (each tagged availability_status). Use strict unless the user explicitly wants to see sold-out options.",
"enum": [
"strict",
"include_unavailable"
],
"type": "string"
},
"currency": {
"description": "Currency of the returned prices (ISO-4217, 3-letter uppercase, e.g. 'USD', 'EUR', 'GBP', 'CAD'). SET THIS (or `user_country`) to price in the user's currency — if you set NEITHER, prices default to USD, which may not be the user's. Prices come straight from the booking sources in this currency; never convert them yourself. Each offer reflects the currency its operator actually quoted.",
"pattern": "^[A-Z]{3}$",
"type": "string"
},
"dates": {
"additionalProperties": false,
"description": "Check-in and check-out dates (ISO 8601, YYYY-MM-DD). Natural-language references — 'tonight', 'this weekend', 'the weekend of July 4', 'Memorial Day weekend', 'long weekend in May' — translate to concrete check_in / check_out values at the call site. The comparator only serves future stays: check_in is a date in the real-time calendar that is today or later. A reference like 'the weekend of June 2' resolves to the next occurrence after today, never a past anniversary; if the current year is unclear, confirm with the user before calling. Clock calibration: this schema was published in August 2026, so today is August 2026 OR LATER (likely later — schemas outlive their publish date). An assumed 'today' in 2024/2025 is a stale training-time clock; years before 2026 are always in the past. Past check_in values are rejected at the API boundary with a hint carrying the actual current date.",
"properties": {
"check_in": {
"format": "date",
"type": "string"
},
"check_out": {
"format": "date",
"type": "string"
}
},
"required": [
"check_in",
"check_out"
],
"type": "object"
},
"filters": {
"additionalProperties": false,
"description": "Structured narrowing applied server-side, before ranking. Prefer these over filtering the results yourself: they run across the whole inventory, not just the page you received. Qualitative criteria that do not map here (\"quiet\", \"great breakfast\") are better served by include=['reviews_sample'].",
"properties": {
"amenities": {
"description": "Preferred amenity codes. This ranks, it does not filter: properties declaring every code listed here come first and nothing is dropped, because upstream declarations are incomplete — an absent code is not evidence the service is missing. Read each result's `amenities` to see what is actually declared. Common: wi-fi, parking, pool, air-conditioning, kitchen, garden, pets-allowed, for-families, facilities-for-disabled, non-smoking-only.",
"items": {
"type": "string"
},
"type": "array"
},
"min_rating": {
"maximum": 5,
"minimum": 0,
"type": "number"
},
"price_max_eur": {
"minimum": 0,
"type": "number"
},
"property_types": {
"description": "Preferred property types. Like `amenities`, this steers rather than excludes: the types listed here come first and a minority of other types can still appear in the page. Read each result's `property_type` when the distinction matters to the user. Canonical tokens: hotel, apartment, house, villa, bb, hostel, farmstay, holiday-home. Italian/English synonyms (agriturismo, bnb, appartamento, casa, ...) are accepted and normalized server-side.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"guests": {
"additionalProperties": false,
"description": "Party composition. `adults` is required; give `children_ages` (one age per child, 0-17) rather than a child count — operators price by age. `rooms` defaults to 1; raise it when the party needs separate rooms rather than one shared.",
"properties": {
"adults": {
"maximum": 16,
"minimum": 1,
"type": "integer"
},
"children_ages": {
"items": {
"maximum": 17,
"minimum": 0,
"type": "integer"
},
"type": "array"
},
"rooms": {
"maximum": 9,
"minimum": 1,
"type": "integer"
}
},
"required": [
"adults"
],
"type": "object"
},
"include": {
"description": "Optional enrichments, always a list — pass [\"reviews_sample\"], never the bare string. 'reviews_sample' attaches the 5 most recent individual reviews per property — use for qualitative queries (breakfast, service, ...). One extra Mongo round-trip per page; omit by default.",
"items": {
"enum": [
"reviews_sample"
],
"type": "string"
},
"type": "array"
},
"include_out_of_bounds": {
"description": "Opt-in. When the requested area yields few available results, also return (in alternatives.out_of_bounds) properties just outside the area, within the original budget. Present these explicitly as alternatives, never mixed with primary results.",
"type": "boolean"
},
"include_overbudget": {
"description": "Opt-in. When few available results fit the budget, also return (in alternatives.overbudget) available properties in the same area just above price_max_eur. Requires filters.price_max_eur.",
"type": "boolean"
},
"language": {
"description": "User's UI language (2-letter lowercase). Drives the booking link language and any server-rendered narrative content. Pass the language the user is currently speaking. Falls back to 'en' when omitted.",
"pattern": "^[a-z]{2}$",
"type": "string"
},
"location": {
"additionalProperties": false,
"description": "Where to search, as a {type, value} pair. Use destination_id for a place resolved via resolve_destination, poi_id for a point of interest, coordinates for a known lat/lon, or bbox for an explicit map rectangle. A property is NOT a location — use get_property_details for a known property.",
"properties": {
"type": {
"description": "Selects the shape of value: destination_id and poi_id take an id string, coordinates takes {lat, lon, radius_km?}, bbox takes {nw: [lat,lon], se: [lat,lon]}. property_id is NOT supported here; use get_property_details.",
"enum": [
"destination_id",
"poi_id",
"coordinates",
"bbox"
],
"type": "string"
},
"value": {
"anyOf": [
{
"description": "destination_id/poi_id: opaque id string from resolve_destination or discover_destinations_near (e.g. 'dest_590c54056664cf2c60c5c2f6'). Pass it verbatim — the 'dest_'/'poi_' prefix is accepted. NEVER pass a free-form name like 'Ancona'; the API rejects bad identifiers with 400 invalid_request.",
"type": "string"
},
{
"additionalProperties": false,
"description": "coordinates: a known point, searched within radius_km.",
"properties": {
"lat": {
"description": "Latitude in decimal degrees.",
"maximum": 90,
"minimum": -90,
"type": "number"
},
"lon": {
"description": "Longitude in decimal degrees.",
"maximum": 180,
"minimum": -180,
"type": "number"
},
"radius_km": {
"description": "Search radius in km (default 5).",
"exclusiveMinimum": 0,
"type": "number"
}
},
"required": [
"lat",
"lon"
],
"type": "object"
},
{
"additionalProperties": false,
"description": "bbox: an explicit map rectangle, given by its north-west and south-east corners.",
"properties": {
"nw": {
"description": "North-west corner as [lat, lon].",
"items": {
"type": "number"
},
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"se": {
"description": "South-east corner as [lat, lon].",
"items": {
"type": "number"
},
"maxItems": 2,
"minItems": 2,
"type": "array"
}
},
"required": [
"nw",
"se"
],
"type": "object"
}
],
"description": "Shape depends on type — see each option below."
}
},
"required": [
"type",
"value"
],
"type": "object"
},
"page": {
"additionalProperties": false,
"description": "Pagination. `limit` caps results per page (1-100). To fetch the next page pass `cursor` with the `next_cursor` value from the previous response — cursors are opaque and are never constructed by hand.",
"properties": {
"cursor": {
"type": "string"
},
"limit": {
"maximum": 100,
"minimum": 1,
"type": "integer"
}
},
"type": "object"
},
"sort": {
"description": "Result ordering. score_desc (default) is the balanced relevance ranking and suits most requests; price_asc when the user asked for the cheapest; rating_desc when they asked for the best-reviewed; conversion_desc favours what comparable travellers actually booked.",
"enum": [
"score_desc",
"price_asc",
"rating_desc",
"conversion_desc"
],
"type": "string"
},
"user_country": {
"description": "User's country (ISO-3166 alpha-2 uppercase). Drives the booking-link locale (the landing page rendered when the user clicks `web_url`) AND, when `currency` is not set, the pricing currency (US->USD, CA->CAD, euro-area->EUR). Pass the user's own country, not the destination's. Falls back to 'US' when omitted.",
"pattern": "^[A-Z]{2}$",
"type": "string"
}
},
"required": [
"location",
"dates",
"guests"
],
"type": "object"
},
"name": "search_stays",
"outputSchema": {
"properties": {
"alternatives": {
"properties": {
"out_of_bounds": {
"items": {
"properties": {
"amenities": {
"items": {
"type": "string"
},
"type": "array"
},
"availability_status": {
"description": "Per the dates passed in the request: available = live bookable quotes in offers (price is the curated best); unavailable = BP reported no rooms for these dates (offers=[], price=null); unknown = no dates considered (no price exists without a dated query).",
"enum": [
"available",
"unavailable",
"unknown"
],
"type": "string"
},
"brand": {
"type": [
"string",
"null"
]
},
"chain": {
"type": [
"string",
"null"
]
},
"cluster_id": {
"type": [
"string",
"null"
]
},
"dedup_meta": {
"properties": {
"confidence": {
"type": "number"
},
"last_reconciled": {
"type": "string"
},
"source_listings": {
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"description": {
"description": "Free-text property description from the canonical source. Only populated when the endpoint path is active (use_bp_single_property_endpoint=True) and dates are present.",
"type": [
"string",
"null"
]
},
"features": {
"description": "Structured feature/facility tags (e.g. HouseFacilities, PropertyTypes). Populated alongside description when the endpoint path is active.",
"items": {
"properties": {
"code": {
"type": "string"
},
"name": {
"type": [
"string",
"null"
]
},
"type": {
"type": [
"string",
"null"
]
}
},
"required": [
"code"
],
"type": "object"
},
"type": "array"
},
"id": {
"type": "string"
},
"images": {
"items": {
"properties": {
"caption": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"location": {
"properties": {
"address": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"lat": {
"type": "number"
},
"lon": {
"type": "number"
},
"neighborhood": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"name": {
"type": "string"
},
"offers": {
"items": {
"properties": {
"amount": {
"description": "TOTAL for the requested stay (sum across nights).",
"type": "number"
},
"amount_per_night": {
"description": "Per-night rate; multiply by nights to get amount.",
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"deeplink_url": {
"type": [
"string",
"null"
]
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": "string"
},
"refundable": {
"type": "boolean"
},
"rooms_left": {
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"ota_coverage": {
"items": {
"type": "string"
},
"type": "array"
},
"price": {
"properties": {
"amount": {
"type": "number"
},
"amount_per_night": {
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": [
"string",
"null"
]
},
"refundable": {
"type": "boolean"
}
},
"type": [
"object",
"null"
]
},
"property_type": {
"type": "string"
},
"rating": {
"maximum": 5,
"minimum": 0,
"type": "number"
},
"rating_count": {
"type": [
"integer",
"null"
]
},
"reviews_aggregate": {
"description": "rating_count = reviews backing the score (OTA aggregate, e.g. 156). comment_count = readable review TEXTS available (e.g. 53), fetchable via reviews_sample/reviews_extended. They differ: most guests rate, fewer write text — do not conflate them.",
"properties": {
"comment_count": {
"type": [
"integer",
"null"
]
},
"distribution_by_ota": {
"type": "object"
},
"rating_count": {
"type": "integer"
},
"score_0_5": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": [
"object",
"null"
]
},
"reviews_meta": {
"description": "Provenance for reviews_sample on property detail: how many review texts were returned vs available, and that the cap is deliberate (token efficiency). null on search or when reviews were not requested.",
"properties": {
"cap": {
"minimum": 0,
"type": "integer"
},
"capped": {
"type": "boolean"
},
"note": {
"type": "string"
},
"returned": {
"minimum": 0,
"type": "integer"
},
"total_available": {
"minimum": 0,
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"reviews_sample": {
"items": {
"properties": {
"connector_name": {
"type": [
"string",
"null"
]
},
"date": {
"type": "string"
},
"description": {
"type": "string"
},
"language": {
"type": [
"string",
"null"
]
},
"score": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"stars": {
"type": [
"integer",
"null"
]
},
"thumbnail_url": {
"type": [
"string",
"null"
]
},
"web_url": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"name",
"property_type",
"rating",
"location",
"ota_coverage"
],
"type": "object"
},
"type": [
"array",
"null"
]
},
"overbudget": {
"items": {
"properties": {
"amenities": {
"items": {
"type": "string"
},
"type": "array"
},
"availability_status": {
"description": "Per the dates passed in the request: available = live bookable quotes in offers (price is the curated best); unavailable = BP reported no rooms for these dates (offers=[], price=null); unknown = no dates considered (no price exists without a dated query).",
"enum": [
"available",
"unavailable",
"unknown"
],
"type": "string"
},
"brand": {
"type": [
"string",
"null"
]
},
"chain": {
"type": [
"string",
"null"
]
},
"cluster_id": {
"type": [
"string",
"null"
]
},
"dedup_meta": {
"properties": {
"confidence": {
"type": "number"
},
"last_reconciled": {
"type": "string"
},
"source_listings": {
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"description": {
"description": "Free-text property description from the canonical source. Only populated when the endpoint path is active (use_bp_single_property_endpoint=True) and dates are present.",
"type": [
"string",
"null"
]
},
"features": {
"description": "Structured feature/facility tags (e.g. HouseFacilities, PropertyTypes). Populated alongside description when the endpoint path is active.",
"items": {
"properties": {
"code": {
"type": "string"
},
"name": {
"type": [
"string",
"null"
]
},
"type": {
"type": [
"string",
"null"
]
}
},
"required": [
"code"
],
"type": "object"
},
"type": "array"
},
"id": {
"type": "string"
},
"images": {
"items": {
"properties": {
"caption": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"location": {
"properties": {
"address": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"lat": {
"type": "number"
},
"lon": {
"type": "number"
},
"neighborhood": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"name": {
"type": "string"
},
"offers": {
"items": {
"properties": {
"amount": {
"description": "TOTAL for the requested stay (sum across nights).",
"type": "number"
},
"amount_per_night": {
"description": "Per-night rate; multiply by nights to get amount.",
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"deeplink_url": {
"type": [
"string",
"null"
]
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": "string"
},
"refundable": {
"type": "boolean"
},
"rooms_left": {
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"ota_coverage": {
"items": {
"type": "string"
},
"type": "array"
},
"price": {
"properties": {
"amount": {
"type": "number"
},
"amount_per_night": {
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": [
"string",
"null"
]
},
"refundable": {
"type": "boolean"
}
},
"type": [
"object",
"null"
]
},
"property_type": {
"type": "string"
},
"rating": {
"maximum": 5,
"minimum": 0,
"type": "number"
},
"rating_count": {
"type": [
"integer",
"null"
]
},
"reviews_aggregate": {
"description": "rating_count = reviews backing the score (OTA aggregate, e.g. 156). comment_count = readable review TEXTS available (e.g. 53), fetchable via reviews_sample/reviews_extended. They differ: most guests rate, fewer write text — do not conflate them.",
"properties": {
"comment_count": {
"type": [
"integer",
"null"
]
},
"distribution_by_ota": {
"type": "object"
},
"rating_count": {
"type": "integer"
},
"score_0_5": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": [
"object",
"null"
]
},
"reviews_meta": {
"description": "Provenance for reviews_sample on property detail: how many review texts were returned vs available, and that the cap is deliberate (token efficiency). null on search or when reviews were not requested.",
"properties": {
"cap": {
"minimum": 0,
"type": "integer"
},
"capped": {
"type": "boolean"
},
"note": {
"type": "string"
},
"returned": {
"minimum": 0,
"type": "integer"
},
"total_available": {
"minimum": 0,
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"reviews_sample": {
"items": {
"properties": {
"connector_name": {
"type": [
"string",
"null"
]
},
"date": {
"type": "string"
},
"description": {
"type": "string"
},
"language": {
"type": [
"string",
"null"
]
},
"score": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"stars": {
"type": [
"integer",
"null"
]
},
"thumbnail_url": {
"type": [
"string",
"null"
]
},
"web_url": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"name",
"property_type",
"rating",
"location",
"ota_coverage"
],
"type": "object"
},
"type": [
"array",
"null"
]
}
},
"type": "object"
},
"metadata": {
"properties": {
"notes": {
"items": {
"type": "string"
},
"type": "array"
},
"otas_queried": {
"type": "integer"
},
"price_as_of": {
"type": "string"
},
"request_id": {
"type": "string"
}
},
"required": [
"otas_queried"
],
"type": "object"
},
"page": {
"properties": {
"next_cursor": {
"type": [
"string",
"null"
]
},
"total_estimate": {
"type": "integer"
}
},
"required": [
"next_cursor",
"total_estimate"
],
"type": "object"
},
"results": {
"items": {
"properties": {
"amenities": {
"items": {
"type": "string"
},
"type": "array"
},
"availability_status": {
"description": "Per the dates passed in the request: available = live bookable quotes in offers (price is the curated best); unavailable = BP reported no rooms for these dates (offers=[], price=null); unknown = no dates considered (no price exists without a dated query).",
"enum": [
"available",
"unavailable",
"unknown"
],
"type": "string"
},
"brand": {
"type": [
"string",
"null"
]
},
"chain": {
"type": [
"string",
"null"
]
},
"cluster_id": {
"type": [
"string",
"null"
]
},
"dedup_meta": {
"properties": {
"confidence": {
"type": "number"
},
"last_reconciled": {
"type": "string"
},
"source_listings": {
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"description": {
"description": "Free-text property description from the canonical source. Only populated when the endpoint path is active (use_bp_single_property_endpoint=True) and dates are present.",
"type": [
"string",
"null"
]
},
"features": {
"description": "Structured feature/facility tags (e.g. HouseFacilities, PropertyTypes). Populated alongside description when the endpoint path is active.",
"items": {
"properties": {
"code": {
"type": "string"
},
"name": {
"type": [
"string",
"null"
]
},
"type": {
"type": [
"string",
"null"
]
}
},
"required": [
"code"
],
"type": "object"
},
"type": "array"
},
"id": {
"type": "string"
},
"images": {
"items": {
"properties": {
"caption": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"location": {
"properties": {
"address": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"lat": {
"type": "number"
},
"lon": {
"type": "number"
},
"neighborhood": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"name": {
"type": "string"
},
"offers": {
"items": {
"properties": {
"amount": {
"description": "TOTAL for the requested stay (sum across nights).",
"type": "number"
},
"amount_per_night": {
"description": "Per-night rate; multiply by nights to get amount.",
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"deeplink_url": {
"type": [
"string",
"null"
]
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": "string"
},
"refundable": {
"type": "boolean"
},
"rooms_left": {
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"ota_coverage": {
"items": {
"type": "string"
},
"type": "array"
},
"price": {
"properties": {
"amount": {
"type": "number"
},
"amount_per_night": {
"type": [
"number",
"null"
]
},
"breakfast_included": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"discount_percentage": {
"type": [
"number",
"null"
]
},
"is_discounted": {
"type": "boolean"
},
"ota": {
"type": [
"string",
"null"
]
},
"refundable": {
"type": "boolean"
}
},
"type": [
"object",
"null"
]
},
"property_type": {
"type": "string"
},
"rating": {
"maximum": 5,
"minimum": 0,
"type": "number"
},
"rating_count": {
"type": [
"integer",
"null"
]
},
"reviews_aggregate": {
"description": "rating_count = reviews backing the score (OTA aggregate, e.g. 156). comment_count = readable review TEXTS available (e.g. 53), fetchable via reviews_sample/reviews_extended. They differ: most guests rate, fewer write text — do not conflate them.",
"properties": {
"comment_count": {
"type": [
"integer",
"null"
]
},
"distribution_by_ota": {
"type": "object"
},
"rating_count": {
"type": "integer"
},
"score_0_5": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": [
"object",
"null"
]
},
"reviews_meta": {
"description": "Provenance for reviews_sample on property detail: how many review texts were returned vs available, and that the cap is deliberate (token efficiency). null on search or when reviews were not requested.",
"properties": {
"cap": {
"minimum": 0,
"type": "integer"
},
"capped": {
"type": "boolean"
},
"note": {
"type": "string"
},
"returned": {
"minimum": 0,
"type": "integer"
},
"total_available": {
"minimum": 0,
"type": "integer"
}
},
"type": [
"object",
"null"
]
},
"reviews_sample": {
"items": {
"properties": {
"connector_name": {
"type": [
"string",
"null"
]
},
"date": {
"type": "string"
},
"description": {
"type": "string"
},
"language": {
"type": [
"string",
"null"
]
},
"score": {
"maximum": 5,
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"stars": {
"type": [
"integer",
"null"
]
},
"thumbnail_url": {
"type": [
"string",
"null"
]
},
"web_url": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"name",
"property_type",
"rating",
"location",
"ota_coverage"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"results",
"page",
"metadata"
],
"type": "object"
}
}
]
}Verify it yourself
curl -s https://api.teppi.xyz/v1/evidence/sha256:038d1324cbaf2074b6e1494f6a316608cd8884d6f04ebcc1c3a6d24e36eb9c57 | sha256sum