Skip to content
This page is available in Markdown format. Markdown is recommended for AI consumption. See /api/hotels/get-hotel-search-results/index.md for this page, or/llms.txt for the full documentation index.

Read hotel search results

Lean list cards; default 10, max 50 per page. searchComplete:true terminal, false advisory; poll snapshotCandidateCount to a steady non-zero. totalCandidates===0 = filters only if totalBeforeFilters>0, else none bookable once complete. ?refundable=true = witnessed.

View as MarkdownView this page as plain text
Carries onwardhotelId
Settlesimmediately
Id expiresyes · 404 means search again

GET /v1/hotels/searches/{searchId}/results

Lean list cards; default 10, max 50 per page. searchComplete:true terminal, false advisory; poll snapshotCandidateCount to a steady non-zero. totalCandidates===0 = filters only if totalBeforeFilters>0, else none bookable once complete. ?refundable=true = witnessed.

Operation ID: getHotelSearchResults

Parameters

Name In Type Required Constraints Description
searchId path string yes pattern ^[A-Za-z0-9._:~=-]{1,256}$ The opaque searchId returned by createHotelSearch. Ids expire; a 404 means the search is unknown or gone – create a new one.
page query integer no 1..100; default 1 Page number, 1-based (max 100). Defaults to 1.
pageSize query integer no 1..50; default 10 Results per page (1-50). Defaults to 10.
sort query relevance | price_asc | price_desc | star_desc | review_score_desc | guest_rating_desc | distance_asc no default "relevance" Sort order. relevance (default) is the metasearch ranking; price_asc / price_desc by cheapest per-night rate; star_desc by star; review_score_desc by guest score; guest_rating_desc by the ?guest-type= cohort’s own score, which requires that param (a hotel upstream did not score for the cohort sorts last, never zero-filled); distance_asc by distance to the city’s place-record coordinate (see distanceToCityCentre). With ?refundable=true the price sorts key off the cheapest refundable rate.
currency query string no pattern ^[A-Z]{3}$; default "USD" Pricing currency as a 3-letter ISO 4217 code (e.g. AED). Defaults to USD.
locale query string no length 1..35; default "en" Response language tag (e.g. en, ar). Defaults to en.
min-star query integer no 1..5 Keep hotels with at least this star rating (1-5).
max-star query integer no 1..5 Keep hotels with at most this star rating (1-5).
min-review-score query number no 0..10 Keep hotels whose ALL-GUESTS review score is at least this (0-10). This is the everybody-rated-it-well question; for a named guest cohort use ?guest-type= with ?min-guest-rating=, which is a different number on most hotels.
guest-type query business | couple | family | solo no - The guest cohort ?min-guest-rating= and sort=guest_rating_desc judge a hotel by: business, couple, family or solo. Read the vocabulary and this snapshot’s per-cohort hotel counts from metadata.filterOptions.guestTypes. Must be sent with ?min-guest-rating= or sort=guest_rating_desc, and both of those require it - a cohort with nothing to apply it to is rejected rather than silently ignored. Spelled differently from the /reviews ?guest-type= vocabulary (family here, family_with_children there) because the two upstreams segment guests differently; business exists only here and extended_group only there.
min-guest-rating query number no 0..10 Keep hotels the ?guest-type= cohort rates at least this (0-10). Requires ?guest-type=. Judged on that cohort’s own score, not the all-guests one: on a settled 420-hotel snapshot, of the 299 hotels scored for both, 58% had a family score at least 3 points from their overall one. A hotel upstream did not score for the cohort is DROPPED, and that absence means too little cohort data rather than a low score - upstream publishes no thin cohort rows, so a cohort score it does publish rests on more reviews than the all-guests figure sometimes does.
min-price query number no 0..1000000 Minimum price (inclusive), in the response currency. Bounds the all-in nightly figure: amountPerNight plus every per-night charge the card publishes beside it, localTaxPerNight and taxAmountPerNight where present. That figure covers every room in the search, so multiply a per-room budget by the room count in stay.occupancy.rooms. Read metadata.filterOptions.priceRange for the bounds this snapshot spans. With ?refundable=true it bounds the cheapest refundable rate.
max-price query number no 0..1000000 Maximum price (inclusive), in the response currency. Bounds the all-in nightly figure: amountPerNight plus every per-night charge the card publishes beside it, localTaxPerNight and taxAmountPerNight where present. That figure covers every room in the search, so multiply a per-room budget by the room count in stay.occupancy.rooms. Read metadata.filterOptions.priceRange for the bounds this snapshot spans. With ?refundable=true it bounds the cheapest refundable rate.
refundable query 0 | 1 | true | false no - Keep only hotels with a witnessed refundable Book-on-Wego rate, so a ‘cheapest refundable’ answer needs no per-hotel /rates calls. Exactly equivalent to ?rate-types=free_cancellation, and combines with it: this is the one rate type that has its own param. This is an UNDER-approximation: the results envelope is a rate sample, so a true keeps hotels with a seen refundable rate and a hotel’s absence is not authoritative – only GET /v1/hotels/{hotelId}/rates can prove a hotel has no refundable rate. Accepts true or false.
rate-types query string[] no items 1..* Keep hotels with a witnessed Book-on-Wego rate carrying ALL listed rate types (AND across terms; repeat or comma-separate), so ‘only rooms with breakfast’ needs no per-hotel /rates calls. Read the vocabulary from metadata.filterOptions.rateTypes (e.g. breakfast_included, free_cancellation) – unlike every other list filter these are matched EXACTLY (case-insensitively), not as substrings, because they are stable upstream codes rather than localized display names. Several terms mean ONE rate carrying all of them, and while any rate-type filter is active the card price, the price bounds, the price sorts and the cheapest badge all key off that matching rate. Like refundable, an UNDER-approximation: the results envelope is a rate sample, so a hotel’s absence is not proof it lacks the type – only GET /v1/hotels/{hotelId}/rates can prove that.
deals-only query 0 | 1 | true | false no - Keep only hotels whose card carries a price.deal, mirroring the ‘today’s deals’ filter on wego.com. Judged on the very price object the card publishes, so the kept hotels and the deals shown always agree – with ?refundable=true that means the refundable rate must be the discounted one. Like refundable, this is an UNDER-approximation: the results envelope is a rate sample that grows while searchComplete is false, so a hotel’s absence is not proof it has no discount. Accepts true or false.
amenities query string[] no items 1..* Keep hotels offering ALL listed amenities (AND across terms; repeat or comma-separate). Each term is matched case-insensitively as a substring against the name field in metadata.filterOptions.amenities – pick terms from there (e.g. Fitness Centre), not a guessed synonym (gym). One term can span several values (Pool also matches Indoor Pool).
property-types query string[] no items 1..* Keep hotels whose property type matches ANY listed term (OR; repeat or comma-separate). Matched case-insensitively as a substring against the name field in metadata.filterOptions.propertyTypes – pick from there rather than guessing.
brands query string[] no items 1..* Keep hotels whose brand matches ANY listed term (OR; repeat or comma-separate). Matched case-insensitively as a substring against the name field in metadata.filterOptions.brands – pick from there rather than guessing. Names parent companies as well as individual brands, and a term matches an entry name rather than a corporate relationship, so a group filed under several sibling brands needs each of those names listed.
chains query string[] no items 1..* Keep hotels whose chain matches ANY listed term (OR; repeat or comma-separate). Matched case-insensitively as a substring against the name field in metadata.filterOptions.chains – pick from there rather than guessing. Most hotels carry no chain and some entries name a loyalty programme, so a hotel group may be reachable only through brands, or split across both vocabularies.
districts query string[] no items 1..* Keep hotels whose district matches ANY listed term (OR; repeat or comma-separate). Matched case-insensitively as a substring against the name field in metadata.filterOptions.districts – pick from there rather than guessing.
view query card no default "card" Response projection. card is the only value: the lean results-list projection (price summary, refundability witness, star/review, location names). The former default projection was removed in issue #1308 – read GET /v1/hotels/{hotelId} for a hotel’s amenities, images and address.

Responses

Status Description
200 Ranked hotels, as lean list cards. Amenities, the full image list, the address and brand/chain are not on a card – read the hotel for the one row you picked.
400 Invalid request parameters.
401 Missing or invalid bearer token.
404 Unknown or expired search.
429 Rate limit exceeded; retry after the Retry-After seconds.
502 The upstream hotels service returned an invalid response.
503 The hotels service is unavailable (upstream_unavailable) or rate-limited upstream (upstream_rate_limited); retry after the Retry-After seconds.

200 body

Field Type Always present Description
searchId string yes The id of the search this snapshot belongs to.
currencyCode string yes Currency the prices in this snapshot are quoted in.
searchComplete boolean yes Upstream aggregation flag. true is authoritative/terminal; conclude NO BOOK-ON-WEGO BOOKABLE INVENTORY only when true AND metadata.totalBeforeFilters === 0 – never that no hotel exists, since only Book-on-Wego inventory was requested. A zero totalCandidates on its own means only that this read’s filters matched nothing, and an empty page with totalCandidates > 0 is pagination. false is inconclusive, so watch metadata.snapshotCandidateCount convergence to stop sooner.
stay object no What upstream priced: the dates and occupancy every price on this read covers. Present when upstream states them.
checkIn string yes Check-in date priced upstream, YYYY-MM-DD.
checkOut string yes Check-out date priced upstream, YYYY-MM-DD.
nights integer yes Nights between checkIn and checkOut. price.total covers this many nights of price.amountPerNight.
occupancy object yes The occupancy priced upstream for this search (ages resolved, incl. fallback).
metadata object yes Pagination, the snapshot’s filter vocabulary, the settle counters for this read, and what it resolved currency and locale to.
page integer yes 1-based page number of this snapshot.
pageSize integer yes Hotels requested per page.
resultCount integer yes Hotels on this page. The page only – judge a filter on totalCandidates.
totalCandidates integer yes Hotels matching this read’s filters across the snapshot – the count that judges a filter, not the page. A filter that matched nothing is totalCandidates 0 with totalBeforeFilters above 0.
totalBeforeFilters integer yes Hotels that survived the Book-on-Wego join, before this read’s filters ran. A filter that matched nothing is totalCandidates === 0 with totalBeforeFilters > 0. Zero means no Book-on-Wego-bookable inventory surfaced for these dates – it is NOT proof that no hotel exists, since the join runs over a sampled rate list. Equal to totalCandidates on an unfiltered read.
filterOptions object yes The filterable vocabulary of the hotels in this snapshot, ordered by count, over the same population as totalBeforeFilters. The amenities / property-types / brands / chains / districts query params take an entry’s name field VERBATIM (matched case-insensitively as a substring), so pick from here rather than guessing a synonym. A term listed here matches AT LEAST its count on an unfiltered read; the count is a lower bound, since one term can span several values (Pool also matches Indoor Pool). rateTypes and guestTypes are the exceptions: their names are stable codes, matched exactly rather than as substrings, so their counts are precise rather than a lower bound. guestTypes counts a smaller population than the rest for a different reason - it counts only the hotels upstream scored for that cohort, and upstream publishes no thin cohort rows, so a hotel absent from a cohort has too little data for it rather than a poor rating. Still growing while searchComplete is false. priceRange does the same job for the numeric bounds: it states the span min-price / max-price are measured on, so read it before choosing either.
hasMore boolean yes Another page of hotels follows.
snapshotCandidateCount integer yes Upstream aggregation counter – the practical early convergence signal. Two spaced (not back-to-back), equal, non-zero reads ≈ settled enough to render; it stabilizes well before searchComplete flips, so use it to stop polling sooner. A heuristic, not proof of completion (searchComplete:true is that). Not the same as totalCandidates (the post-Book-on-Wego-join hotel count).
createdAt string no When this search was created (ISO 8601) – the freshness anchor for these prices. A search older than about 10 minutes may answer 404 as expired. Absent when the search service omits it.
currencyCode string yes The currency this read ASKED upstream for, and the one every price on it is meant to be in. Read it beside currencyCodeSource before you show a number: a price computed in the wrong currency renders as a perfectly normal price, with no error and no odd shape to notice, so the response states which one rather than leaving it to be inferred. Where the operation also publishes a top-level currencyCode, that field reports the currency the prices actually came back in; the two agree unless upstream declined to reprice.
currencyCodeSource explicit | default yes How the API resolved currencyCode: explicit (the caller sent currency – including a value equal to the default) or default (USD, no currency sent). A default here is the one signal that the request never carried the currency you meant.
locale string yes The language tag this read asked upstream for – what any localized text on it was resolved in (room and board names, airline and airport names, review prose).
localeSource explicit | default yes How the API resolved locale: explicit (the caller sent locale – including a value equal to the default) or default (en, no locale sent). A default here explains text that came back in a language the caller did not ask for.
results object[] yes The requested page of ranked hotels, as list cards.
hotelId number yes The hotel’s numeric id; read its detail with GET /v1/hotels/{hotelId}.
name string yes Hotel display name.
pageUrl string yes The hotel’s page on wego.com. It is not tied to a search, so it keeps working after this search expires. Give it to a traveller who wants to look at the hotel, and use it in anything that is saved or sent on. It opens with no dates set.
star number no Star rating (1-5), when classified.
review object no Aggregate guest review score and count.
reviewsByGuestType object no Guest review score and count per cohort, on the same 0-10 scale as review (which is the all-guests figure). These are the exact values ?guest-type= accepts and the same vocabulary metadata.filterOptions.guestTypes counts. A cohort is present only when upstream scored it, and an ABSENT cohort means too little data for that cohort, never a low score - upstream publishes no thin cohort rows. Read these to explain a pick as well as make one: a hotel rated 8.5 overall and 7.6 by families is a different recommendation than one rated 8.5 by both. Omitted when no cohort was scored.
price object yes A card’s per-night and stay price. Every amount covers the whole booking, all rooms in the search, so quote these figures as they stand. Upstream rounds per booking, so total is the exact stay figure and amountPerNight is one night of it. Any per-night figure published beside amountPerNight is charged ON TOP of it: add localTaxPerNight, and taxAmountPerNight when it appears, to reach what a guest pays and what the price sorts and bounds rank on.
refundable available | unknown yes Refundability WITNESS, not a boolean. ‘available’ = a free-cancellation Book-on-Wego rate was seen in this snapshot. ‘unknown’ = none was seen, which is NOT evidence that none exists – this envelope carries only a sample of each hotel’s rates, so a negative is not computable here. To answer ‘does this hotel have a refundable room’, read the hotel’s rooms/rates.
lowestRefundablePrice object no Lowest refundable Book-on-Wego rate. Present exactly when refundable is ‘available’.
rateTypes string[] no Rate types WITNESSED on this hotel’s Book-on-Wego rates in this snapshot (e.g. breakfast_included, free_cancellation), sorted. A witness on the same terms as refundable, never a negative: this envelope carries only a sample of each hotel’s rates, so an absent type is not evidence the hotel lacks it. These are the exact values ?rate-types= accepts, and the same vocabulary metadata.filterOptions.rateTypes counts. Omitted when no rate type was witnessed.
cityName string no City the hotel is in.
districtName string no District or neighbourhood the hotel is in.
lat number no Hotel latitude in decimal degrees. Use with lng to compute distance to any landmark you choose.
lng number no Hotel longitude in decimal degrees. Use with lat to compute distance to any landmark you choose.
distanceToCityCentre number no Kilometres from the city’s place-record coordinate (the point GET /v1/places reports for the city), and the ?sort=distance_asc key. Where a city record covers an island, a city-state or a whole administrative area, that point can sit far from the commercial centre. For locality prefer the districts filter, or compute distance from lat/lng to a landmark you choose. Present when upstream reports it.
image string no Primary image URL, if any.
badges string[] yes Full-result-set badges this hotel wins (e.g. cheapest).

Example

curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.wego.com/v1/hotels/searches/$SEARCH_ID/results"

FORM WG-REF · SEQ 004821The API and the ways in to it are early and may change.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close