Skip to content

SearchLatest

POST
/wink.partner.v1.Search/SearchLatest
curl --request POST \
--url https://example.com/wink.partner.v1.Search/SearchLatest \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "userSession": { "itinerary": { "startDate": "example", "nights": 1, "room": { "adults": 1, "children": [ { "age": 1, "quantity": 1 } ], "quantity": 1 } }, "languageCode": "example", "quoteCurrencies": [ "example" ], "promotionalCodes": [ "example" ] }, "page": 1, "size": 1, "imageFormat": "example" }'

The newest properties

Return the properties most recently added to the platform that you can sell, newest first. Use it for a “just added” shelf.

This search knows no total. total_elements is a lower bound while a full page comes back and becomes exact on the first short page, and last is false until then, so paging until last is true reads every property.

Media typeapplication/json

Request for SearchLatest.

object
userSession

Traveller context. Required.

object
itinerary

Stay dates and occupancy. Required — searches without an itinerary cannot be priced.

object
startDate

Check-in date, ISO-8601 “YYYY-MM-DD”. Required. Must be today or later – a past date is rejected with INVALID_ARGUMENT.

string
nights

Number of nights. Billing caps this at 90; a longer stay is rejected with INVALID_ARGUMENT.

integer format: int32
room

The room being searched for, and how many of it. Required.

SINGULAR. This was once a list, on the promise that several occupancies could be priced in one call — two adults in one room and a family of four in another. The platform never delivered it: every consumer read the FIRST entry and the room count came from the list’s SIZE, so a second entry was priced as though it did not exist while still moving the count that volume discounts and availability key off. Ask for several identical rooms with RoomConfiguration.quantity; ask for several DIFFERENT occupancies as separate calls, and assemble them in your own cart.

object
adults

Adults in this room. Defaults to 1.

integer format: int32
children

Children in this room, by age. Ages are REQUIRED, not optional detail: properties price children in age bands, and an unpriceable age produces a rate the guest cannot actually book.

Array<object>

A number of children of the same age.

object
age

Age at check-in, in years. Zero is valid — infants are priced differently from older children, not ignored.

integer format: int32
quantity

How many children of this age. Defaults to 1.

integer format: int32
quantity

How many identical rooms of this configuration. Defaults to 1.

integer format: int32
languageCode

ISO 639-1 language, e.g. “en”. Affects the little text this surface returns; for descriptions and other prose, pass the language to the Content service instead. Defaults to “en”.

string
quoteCurrencies

ISO 4217 currencies you want an exchange rate into, e.g. [“EUR”, “JPY”]. At most 10 distinct codes, each exactly three letters. Optional.

The platform currency (USD) is ALWAYS quoted in addition to these, so a caller reporting to an analytics tool in USD needs to ask for nothing. Asking for the property’s own currency is allowed and yields a rate of 1. A currency we hold no usable rate for is LEFT OUT of that property’s fx_quotes rather than failing the call, so check the list for the currency you need. Only a missing USD rate fails the call, with NOT_FOUND.

Array<string>
promotionalCodes

Promotional codes to apply. Codes your account is not entitled to are ignored, not rejected.

Array<string>
page

Zero-based page number. Defaults to 0. Only the first 10000 results can be paged to; a page that reaches past result 10000 is rejected with INVALID_ARGUMENT, so narrow the search instead.

integer format: int32
size

Results per page. Defaults to 20, which is also the maximum. A larger value is rejected with INVALID_ARGUMENT rather than clamped. Every property returned is billed, so the cap bounds cost as well as fan-out.

integer format: int32
imageFormat

IANA media type for image delivery URLs: image/jpeg (the default), image/png, image/webp, or image/*. Empty means image/jpeg. An unrecognised value is rejected with INVALID_ARGUMENT.

string

Example generated

{
"userSession": {
"itinerary": {
"startDate": "example",
"nights": 1,
"room": {
"adults": 1,
"children": [
{
"age": 1,
"quantity": 1
}
],
"quantity": 1
}
},
"languageCode": "example",
"quoteCurrencies": [
"example"
],
"promotionalCodes": [
"example"
]
},
"page": 1,
"size": 1,
"imageFormat": "example"
}

The RPC completed with gRPC status OK.

Media typeapplication/json

Response for SearchLatest.

object
page

The page. total_elements is a lower bound while a full page comes back, and last is false until the first short page; see the RPC.

object
content

The properties on this page.

Array<object>

One property and its live prices.

Carries only what a result list needs to render, plus the prices. For anything else about the property — descriptions, full gallery, address, amenities, room detail, policies — call the Content service with property_id and cache the answer against its cache_token.

object
propertyId

Stable property identifier. Your key for everything, including Content lookups.

string
urlName

Url-safe slug, stable and safe to build links from.

string
uniqueId

The property’s globally unique short code.

string
name

Property name in the requested language. Enough to label a result row; full localized content comes from the Content service.

string
geoLocation

Where the property is, for map pins and distance sorting.

Bare latitude and longitude, not GeoJSON: this field carries only coordinates, and the surrounding JSON already tells you what kind of thing they belong to. Named geo_location rather than location so a generated client’s field name says what it is without opening the type.

object
longitude

Degrees east of the prime meridian, -180 to 180.

number format: double
latitude

Degrees north of the equator, -90 to 90.

number format: double
city

The city this property is in, with the identifiers the destination surfaces take.

Lets a result row offer “more properties in this city” without a Content call first: geo_name_id goes straight back into SearchByCity, url_name into RankByCity. Absent when the property has no city on record.

object
geoNameId

GeoNames id, e.g. “1609350” for Bangkok. Pass to Search.SearchByCity.

Always set when this message is present: every property that has a city has this.

string
name

The city’s name.

NOT localized, unlike every other name on this surface. The lightweight GeoNames record this comes from deliberately excludes alternate-name translations, so this is the canonical GeoNames name whatever language_code you asked for. Said plainly because a caller would otherwise reasonably assume it follows the rest of the response.

string
urlName

Url-safe slug. Pass to Search.RankByCity, which takes the url name rather than the GeoNames id.

EMPTY for a substantial minority of properties – 601 of 3,230 in production, about 19% – because the slug is populated separately from the GeoNames link. Check it before building a RankByCity call; an empty value here does not mean the property has no city, only that this particular handle is missing.

string
countryCode

ISO 3166-1 alpha-2 country code of the city, e.g. “TH”.

string
distanceInMeters

How far this property is from the point you searched from, in metres.

Set only when area held a point — a polygon has no single origin to measure from, so this is unset on containment searches. On a point search the page is ordered by this value, nearest first.

It is the distance to the property’s nearest bookable inventory item, which is the property’s own location for all current inventory types.

optional so a genuine near-zero distance (the property is essentially at the search coordinates) is distinguishable from “not applicable”: a plain, non-optional double serializes identically to its own default at exactly 0, so proto3 JSON would otherwise omit both cases the same way.

number format: double
starRating

Official star rating, 1-5. Zero when unrated.

integer format: int32
heroImageUrl

A ready-to-use delivery URL for a single representative image of the property, scaled to 1024px wide (Cloudinary’s medium variant), the same convention SearchRoomTypeOffers.hero_image_url already uses for a room. The lowest-sorted published image; unset when the property has none.

A plain URL rather than the full Multimedia object deliberately: this is a pricing surface, not a content surface, and the full object carries localized captions, camera angle and lifestyle tagging – real content, not routing information for one image. The complete gallery is in Content.

string
lastUpdate

When this property’s record last changed, ISO-8601 “YYYY-MM-DDThh:mm:ss” in UTC.

A coarse hint that something about the property moved, and a display value. It is NOT the content-change signal: refresh Content by sending the cache_token you stored as known_versions. This value lags and does not move for every edit. It advances when the property or any inventory item beneath it is added, removed or edited.

Edits to child entities advance it too — room types, rate plans, master rates, cancellation policies and every ancillary item, on create, edit, remove and translate alike.

One documented gap: PERKS. A perk is defined once for the whole platform rather than per property, so editing one cannot be attributed to a single property and does not move any property’s value. Perk text you have cached can therefore go stale silently. Perks are small and few — Search returns every perk referenced by a result inline — so read them from a search response, or Content, rather than caching them against this value, and re-sync content periodically regardless. (Content’s cache_token is a hash of the returned content and DOES move on a perk edit.)

string
roomTypes

Offers for this property, grouped by room type, cheapest room first. Search returns the single best offer per room type; use Inventory for every rate and occupancy combination.

Array<object>
object
roomTypeId

The room type. Join to Content for the full gallery, amenities and long-form descriptions.

string
name

The room type’s name, in the requested language where a translation exists.

string
heroImageUrl

A ready-to-use delivery URL for a single representative image of the room, scaled to 1024px wide (Cloudinary’s medium variant — c_scale, dpr_auto, f_auto, q_auto:best, w_1024). The lowest-sorted published image; unset when the room has none.

A plain URL rather than the full Multimedia object deliberately: this is a rates surface, not a content surface, and shipping the full media object – id, descriptions, every delivery-URL variant – for every room type on every rate response would make the payload about images instead of about rates. The complete gallery is in Content.

string
rates

The single best offer for this room – one entry, not a list of every rate and occupancy combination. Repeated rather than singular so that a room whose rate WAS computed but is not bookable (occupancy mismatch, sold out) can still report it, rather than vanishing from the results.

EMPTY, not a single unavailable entry, when the room type has no priced rate to report at all – master rates exist but none priced for these dates. That case has nothing meaningful to distinguish one property’s placeholder from another’s on a page ranking hundreds of them, so it is omitted rather than published as an all-blank entry.

Unavailable-but-computed offers sort last, never first: they report 0 across all amounts, so ordering purely by price would put “not priced” ahead of the cheapest real rate. For every rate and occupancy combination, call Inventory.

Array<object>
object
roomRateId

Stable identifier for this offer, and the id you carry into a booking.

This IS the master rate identifier — it maps from roomRateIdentifier, whose own schema calls it “Specified master rate identifier”. The name says room_rate for historical reasons and is kept rather than duplicated: publishing a second master_rate_id field with the same value would be two representations of one thing that can disagree, which this API forbids elsewhere for prices.

string
ratePlanId

The rate plan this offer sells under. Resolve it with Content’s GetRatePlan; a rate plan is shared by many offers, so it is referenced rather than repeated on each one.

string
available

True if THIS offer, at the requested occupancy, is bookable for the itinerary. Narrower than PropertySearchResult.available, which is true when ANY offer at the property is. An unavailable offer is still returned rather than dropped, so you can show the traveller why it cannot be booked.

boolean
startDate

Check-in date, ISO-8601 “YYYY-MM-DD”.

string
endDate

Check-out date, ISO-8601 “YYYY-MM-DD”.

string
roomNights

Nights covered by this rate.

integer format: int32
adults

Adults the rate is priced for, after the property’s occupancy policy is applied.

integer format: int32
children

Children the rate is priced for, after the property’s occupancy policy is applied.

integer format: int32
unitStrikethroughPrice

ONE room, whole stay, BEFORE discounts — step 1 above. The “was” price: render it struck through next to unit_price.

GUARANTEED >= unit_price. Occupancy surcharges and rate premiums are already inside it, so the gap between the two is only ever the discounts. Equal to unit_price when nothing is discounted, in which case show no strikethrough.

string format: int64
unitPrice

ONE room, whole stay, after every adjustment — step 2 above. The “now” price, and the figure the discount is measured against. Excludes the rate plan’s fixed charges.

Not named net or source_total: everywhere else in this platform “source” means the PROPERTY’S OWN CURRENCY, and this figure is in the caller’s. Reusing the word would have the next mapper author reach for the domain’s getSourceTotal() and quote the wrong currency.

string format: int64
unitExtraCharges

ONE room, whole stay — fixed charges attached to the rate plan, a one-time cleaning fee and the like. Reported separately so a traveller sees them as their own line rather than as an unexplained difference. NEVER discounted, which is why they sit outside both prices above. Zero when the rate plan has none.

string format: int64
total

What the guest pays for every room: (unit_price + unit_extra_charges) x quantity. This is the number to show and the number to charge.

Only meaningful when available is true. An unavailable offer reports 0 across every amount, which means “not priced” rather than “free” — show the offer with its reason, never with a price of zero.

string format: int64
meals

Meals included in the rate. These change which offer a traveller picks, so they are here rather than behind an identifier.

object
breakfast

Breakfast included.

boolean
brunch

Brunch included.

boolean
lunch

Lunch included.

boolean
dinner

Dinner included.

boolean
allInclusive

All meals included.

boolean
allInclusivePlusAlcohol

All meals plus alcohol included.

boolean
refundable

True if the stay can be cancelled without charge before the policy’s deadline.

boolean
refundableUntilDays

How many days from TODAY the traveller has left to cancel free of charge, and -1 when the rate is not refundable at all. Zero means the free-cancellation window closes today.

Derived as (days until check-in) − (the policy’s days-before-arrival deadline), floored at 0 — the same calculation RoomTypeBestPriceForDateRange publishes. It is relative to the moment of the response and will drift as the stay approaches, so treat it as display data, not something to cache.

integer format: int32
cancellationPolicyId

Cancellation policy identifier. Join to Content for the full terms and wording.

string
perkIds

Identifiers of the perks bundled with this rate’s master rate, resolved against PropertySearchResult.perks (or Content with CONTENT_SCOPE_PERK). There is deliberately no monetary “perk value” on this surface.

Array<string>
quantity

How many identical rooms this offer is priced for — the quantity you set on the matching RoomConfiguration. At least 1. What the PROPERTY has left is rooms_left, which is a different number entirely.

It is echoed back because it is a MULTIPLIER on total, not merely a restatement of your request: without it you cannot tell whether total covers one room or five. It can also change the unit price itself, since a property may attach a rate to a room-count range — book three and every room may be cheaper than booking one.

integer format: int32
discountPercent

The saving as a fraction of unit_strikethrough_price — 0.15 for 15%. Zero when nothing is discounted.

Published rather than left to you because there is one correct rounding of it and several plausible ones, and a paid API where two integrators compute “18%” and “17%” from the same response is a support burden rather than a saving. Quantity-invariant: discounting every room equally does not change the percentage.

number format: double
adjustments

Every adjustment that moved this rate away from the property’s plain price, one entry per kind, for showing a traveller WHY the number is what it is. Empty when nothing applied.

These reconcile exactly: the signed amounts sum to unit_price minus the property’s unadjusted price. They are per-unit, like the prices they explain.

Array<object>

One reason this rate differs from the property’s plain price.

SIGNED, and the sign is the whole point: unit_amount is negative for anything that lowered the price and positive for anything that raised it, so a caller can render a list of lines and add them up without knowing which types are discounts. Amounts are per-unit minor units, matching the prices they explain.

The surcharges and premiums here are already inside unit_strikethrough_price, and the discounts are the gap between it and unit_price. This message explains the arithmetic; it does not add to it.

object
type

What kind of adjustment this is.

string
Allowed values: ADJUSTMENT_TYPE_UNSPECIFIED ADJUSTMENT_TYPE_EXTRA_ADULT ADJUSTMENT_TYPE_EXTRA_CHILD ADJUSTMENT_TYPE_SINGLE_OCCUPANCY ADJUSTMENT_TYPE_PREMIUM ADJUSTMENT_TYPE_PROMOTION ADJUSTMENT_TYPE_CHANNEL
unitAmount

How much it moved the price for ONE room over the whole stay, in minor units. Negative lowered the price, positive raised it. Never zero — an adjustment that changed nothing is not returned.

string format: int64
offerDetails

The property’s own wording for the promotion or premium in force, in English plus your requested language. Empty when neither applies.

At the RATE level, not on each adjustment, because that is how the platform stores it — one list of descriptions covering the special rates that fired. Attaching a label to each PriceAdjustment would have meant publishing a field nothing could ever fill.

Array<object>

A short piece of localized text.

The API returns descriptions already filtered to the language on your request, so you will normally see exactly one entry per collection. language_code is still present so you can tell which language you got when the requested one was unavailable and the property’s default was substituted.

object
name

Short label for this description.

string
description

The description body.

string
languageCode

ISO 639-1 language code of name and description.

string
promotionalCodes

Promotional codes that were actually ACCEPTED and are reflected in the price above — not the codes you sent. A code your account is not entitled to is ignored rather than rejected, so comparing this against what you submitted is how you tell which ones bit.

Array<string>
roomsLeft

How many rooms the property still has for the WHOLE stay — the “only 2 left” number.

The SMALLEST nightly allotment across the stay, not the first night’s and not an average. A three-night stay whose middle night has two rooms free has two rooms left, however many are free either side: you cannot sell a third room a guest would be evicted from on night two. The check-out date is excluded, since nobody occupies a room that night.

NOT the same as quantity, which is how many rooms YOU asked for. The relationship is rooms_left >= quantity whenever available is true — an offer that cannot house the party you requested is not bookable and says so. Reading quantity as “what the property has” overstates availability, which is why they are named as differently as they are.

Zero means none are free for these dates, and only ever appears alongside available = false. It is a real answer, not a missing one.

This is the property’s true position, not a banded or capped figure. Treat it as commercially sensitive: it is exact enough to reconstruct a property’s booking curve if sampled over time.

integer format: int32
addOnCount

How many extras – add-ons plus in-room ancillaries – can be bought alongside this offer. Zero when it sells none.

A COUNT, not the items. Search is a list surface: the count is enough to render “3 extras available” and decide whether to show a badge, and that is the only add-on decision a result row makes. The items themselves are per-offer objects with their own prices and booking identifiers, which is a detail-view payload – fetch them from Inventory, where RoomRate.add_on_ids and RoomRate.room_type_ancillaries carry the full picture.

The two kinds are summed rather than reported separately because nothing you can do with this number on a search row distinguishes them. They ARE different at booking time – an ancillary quotes this rate’s room_rate_id as its inventory id, an add-on does not – and that difference is exactly why resolving them belongs to the surface that can act on it.

integer format: int32
sort

The property’s own display order for its room types, ascending, when it has expressed one; 0 when it has not. This describes the ROOM, which is why it is here rather than on each rate – the domain defines it as “how the room types should be sorted and displayed”.

It is a merchandising hint, not the delivered order: room_types is already ordered by price.

integer format: int32
perks

Every perk referenced by any RoomRate.perk_ids above, deduplicated — one entry per distinct perk, not one per rate. Resolve a perk id here rather than calling Content; a handful of distinct perks typically cover every rate in this response.

Array<object>

A perk bundled with a rate.

Lives here rather than in partner_content.proto because Search returns a deduplicated dictionary of these alongside its rates (PropertySearchResult.perks): inlining the perk on every rate would repeat a handful of distinct perks across every rate of every room type of every property in a search result. Inventory does NOT return the dictionary (PropertyInventory.perks is deprecated and empty); resolve its perk_ids through Content.

descriptions carries the display name and body together — Description has both.

object
id

Stable perk identifier. Matches an entry in RoomRate.perk_ids.

string
descriptions

Localized name and description, in English plus your requested language.

Array<object>

A short piece of localized text.

The API returns descriptions already filtered to the language on your request, so you will normally see exactly one entry per collection. language_code is still present so you can tell which language you got when the requested one was unavailable and the property’s default was substituted.

object
name

Short label for this description.

string
description

The description body.

string
languageCode

ISO 639-1 language code of name and description.

string
guaranteed

Whether the perk is guaranteed rather than subject to availability.

boolean
level

Perk tier; higher is more valuable.

integer format: int32
sort

Display order, ascending.

integer format: int32
commission

Commission rate your account earns on this property, as a fraction — 0.15 for 15%. A property-channel term rather than a per-rate one: it describes your commercial relationship with the property, so it holds for every offer below.

A double rather than a float because this multiplies money. 0.15 has no exact binary representation, and the wider type keeps the error far enough below a minor unit that total * commission does not drift into a visible discrepancy on large bookings.

number format: double
direct

True if this is direct inventory, with no intermediary between you and the property.

boolean
available

True if AT LEAST ONE room type at this property is bookable for the itinerary. Per-room-type availability is RoomPrice.available; this is the “is anything here bookable at all” flag. When false, prices still carries the unavailable offers rather than being empty, so you can show why.

boolean
currency

The currency every amount on this property is in, and the exchange rates out of it.

object
currencyCode

ISO 4217 code the property’s amounts are denominated in, e.g. “THB”.

string
currencyExponent

How many decimal places currency_code has: 2 for THB and USD, 0 for JPY, KRW and VND. Amounts are integers in MINOR UNITS, so the real value is amount / 10^currency_exponent. Published rather than assumed because a fixed divide-by-100 is wrong for a real slice of Wink’s inventory – a JPY stay priced at 15000 is ¥15,000, not ¥150.

integer format: int32
fxQuotes

Exchange rates out of currency_code: the platform currency first, then each of user_session.quote_currencies in the order you sent them, each once. A requested currency with no usable rate is omitted.

Find a rate by its currency_code, never by position: when the platform rate is missing, the first entry is a requested currency, not USD.

In a page of search results, a property whose currency has no usable platform rate is returned with the quotes that do exist, possibly none, rather than failing the whole page: its amounts are in currency_code and are correct either way, so treat an empty or short list as “no rate to convert with”, never as a zero rate. The calls that price ONE property or a batch of them (Inventory.GetPropertyInventory, Inventory.GetRatePeriod and Inventory.ListPropertyInventory, which is atomic) return NOT_FOUND instead.

Array<object>

An exchange rate from a property’s currency into one other currency.

object
currencyCode

ISO 4217 code this rate converts INTO.

string
rate

Units of currency_code per ONE unit of the property’s currency, as a decimal string such as “0.0275”. A string rather than a double so the digits you receive are exactly the digits we hold. Always positive.

string
asOf

When this rate was recorded, ISO-8601 in UTC, e.g. “2026-10-19T11:00:00Z”.

string
asLowAs

The lowest nightly price this property is indicatively offered at, in MINOR UNITS of currency (real value is as_low_as / 10^currency.currency_exponent).

Indicative, not a quote: it ignores the dates you searched and availability, and is scoped to the channels your account sells through. Use the offers in room_types for a bookable price. Absent when the property has no band for your channel scope – never zero. Populated on search and rank responses built from search hits (SearchByGeo, SearchByCity, RankByCity, RankGlobal and the like); NOT returned by RankByAgency. Also omitted if the band’s currency ever differs from currency. optional so absence is distinguishable from a genuine zero on the wire.

Minor-unit int64 rather than a Money message, like every other amount on this surface (see the MONEY note at the top of this file): the property already declares its currency and exponent once.

string format: int64
butNoMoreThan

The highest nightly price this property is indicatively offered at, in MINOR UNITS of currency. Same semantics as as_low_as: indicative, for your channel scope, absent when the property has no band, and NOT returned by RankByAgency.

string format: int64
number

Zero-based index of this page.

integer format: int32
size

Requested page size.

integer format: int32
totalElements

Total matching properties across all pages.

string format: int64
totalPages

Total number of pages.

integer format: int32
numberOfElements

Properties on this page. Differs from size on the last page.

integer format: int32
first

True if this is the first page.

boolean
last

True if this is the last page.

boolean
languageCode

ISO 639-1 language the names and other text in this response are in – the one you asked for in user_session.language_code, or English when it was unavailable.

string

Example

{
"page": {
"content": [
{
"roomTypes": [
{
"rates": [
{
"adjustments": [
{
"type": "ADJUSTMENT_TYPE_UNSPECIFIED"
}
]
}
]
}
]
}
]
}
}