building
roomUmiltà 36
A quiet boutique hotel a few minutes from the Trevi Fountain.€962.00 2 nights · direct · observedFilters or free text in, ranked hotel cards out, with cached prices when you send dates.
Free text, semantic: $0.012 / search, search.loose.semantic.
{
"query": "quiet place near the Trevi Fountain with a rooftop, under 500 a night",
"ranking": "semantic"
}
building
roomUmiltà 36
A quiet boutique hotel a few minutes from the Trevi Fountain.€962.00 2 nights · direct · observedwhy[0]“quiet” · supported · from reviewstotal_estimate 143 · the next page of this search is free
Send a query, filters, or both. A query makes the call loose and we parse it; filters alone keep it structured. ranking decides between plain filter order and semantic ranking on each hotel's photos, reviews and description.
Where the query and the filters disagree, filters win, and resolved.overrides says so. When a search can't go on without an answer (two Cambridges), it returns needs_clarification, which costs nothing. Answer by sending the same request again with its search_id and answers (each a clarification_id and an option_id); there's no separate follow-up shape. A question's answer_type is single_choice, multi_choice or free_text.
A budget is always per room per night (basis: per_room_per_night) and needs a currency. near needs both lat and lng. A stay without rooms means one room for two adults.
The price follows the input and the ranking. Pages of the same search_id are free; results past 10 on a page add 5% of the base price each.
| Input | Ranking | SKU | Price |
|---|---|---|---|
| Structured | Filters | search.structured.filters | $0.003 |
| Loose | Filters | search.loose.filters | $0.005 |
| Structured | Semantic | search.structured.semantic | $0.008 |
| Loose | Semantic | search.loose.semantic | $0.012 |
/v2/searchSynchronous; needs the search scope. Send a natural-language query, structured filters, or both; at least one of query, filters.location, filters.near or filters.hotel_ids is required. Billed per call: a query makes it loose (else structured) and ranking picks filters or semantic, giving search.structured.filters, search.loose.filters, search.structured.semantic or search.loose.semantic, plus search.extra_results for each result beyond 10. Further pages of the same search_id are free, and a needs_clarification response is free; answer it with {search_id, answers}.
query present → loose, else structured; ranking picks filters or semantic. Results beyond 10 add search.extra_results (5% of the base price each). Pages of the same search_id are free. A needs_clarification response is free; the answered follow-up is billed at the original price. An empty result with status: completed is billed; a 503 is not.
Request body
| Field | Type | Description |
|---|---|---|
query | string | null | What the traveller asked for in their own words; dates, budget, place and amenities are read from it, and it makes the search bill as loose. |
filters | object | null | Hard constraints, which win over anything read from query. |
filters.location | object | null | City or place to search in. |
filters.location.city | string | null | City name, for example Rome; with no country an ambiguous city may come back as a clarification. |
filters.location.country | string | null | ISO 3166-1 alpha-2 country code of the city, for example IT. |
filters.location.place_id | string | null | A resolved.location.place_id from an earlier search, a slug of city and country such as rome-it. |
filters.near | object | null | Point and radius to search around. |
filters.near.latREQUIRED | number | Latitude of the centre in decimal degrees. -90–90. |
filters.near.lngREQUIRED | number | Longitude of the centre in decimal degrees. -180–180. |
filters.near.radius_m | integer | Search radius in metres, 50 to 50,000; also the anchor for each card's distance_m. Default 2000. |
filters.hotel_ids | string (uuid)[] | null | Limit the search to these hotels, up to 10,000 uuids, for example your own inventory; results never include other hotels. |
filters.stay | Stay | null | Dates and rooms of a stay, up to 30 nights and 9 rooms. |
filters.budget | object | null | Price band per room per night. |
filters.budget.min | string | null | Lowest acceptable price per room per night, a decimal string in currency; values of zero or less are ignored. |
filters.budget.max | string | null | Highest acceptable price per room per night, a decimal string in currency; values of zero or less are ignored. |
filters.budget.currencyREQUIRED | string | ISO 4217 currency of min and max. |
filters.budget.basis | string | What the amounts cover; per_room_per_night is the only value. Always per_room_per_night. |
filters.min_stars | integer | null | Minimum official star rating, 1 to 5. |
filters.amenities | string[] | null | Uppercase amenity codes from GET /v2/amenities, up to 30; a hotel must have all of them, and a group code matches any of its members. |
filters.hotel_name | string | null | Part of the hotel's name to match. |
preferences | object | null | Soft signals for semantic ranking. |
preferences.text | string | null | Free-text taste, for example romantic, great breakfast, added to the semantic query; ignored when ranking is filters. |
preferences.tags | string[] | Short free-form tags such as ROMANTIC, up to 20, added to the semantic query and matched against review aspects. |
ranking | string | null | semantic ranks by fit to the query and preferences using reviews and images and fills why[]; filters ranks matches by review score. Defaults to semantic when query is set, else filters. One of filters, semantic. |
limit | integer | Hotels per page, 1 to 50; each result beyond 10 bills search.extra_results, and at most 50 results can be paged in total. Default 10. |
cursor | string | null | The next_cursor of an earlier response, valid for 30 minutes; the page is served free from that search and other fields are ignored. |
rates | string | null | cached adds the latest stored rate to each card and needs filters.stay; none skips rates. Defaults to cached when a stay is set, else none. Search never fetches live prices. One of none, cached. |
images | integer | Images per card, 0 to 10; thumbnail is returned even at 0. Default 6. |
currency | string | null | ISO 4217 currency assumed for a budget written in query without one; card prices stay in the currency they were observed in. |
locale | string | null | Language tag of the caller; it does not change the search response and only selects the language of the hotel detail prepared for a follow-up GET /v2/hotels/{hotel_id}. |
clarification | object | null | What to do when the request is ambiguous; auto when omitted. |
clarification.policy | string | auto returns needs_clarification with a question (free); never returns partial with no hotels and the ambiguous field in resolved.unresolved (also free). One of auto, never. Default auto. |
search_id | string | null | With answers: the search_id of a needs_clarification response being answered, within 30 minutes. |
answers | ClarificationAnswer[] | null | With search_id: the chosen option for the pending clarification; the original search then runs and is billed at its original price. At most 10. |
answers[].clarification_idREQUIRED | string | The clarifications[].id being answered. |
answers[].option_id | string | null | The chosen clarifications[].options[].id, for a single_choice question. |
answers[].value | string | null | The answer in the traveller's words, for a free_text question, for example Lisbon. |
Example
curl -X POST 'https://api.vistalink.com/v2/search' \
-H "Authorization: Bearer $VISTALINK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "quiet place near the Trevi Fountain with a rooftop, under 500 a night",
"filters": {
"location": {
"city": "Rome",
"country": "IT"
},
"stay": {
"check_in": "2026-11-14",
"check_out": "2026-11-16",
"rooms": [
{
"adults": 2,
"children_ages": []
}
]
},
"budget": {
"min": "100",
"max": "500",
"currency": "EUR",
"basis": "per_room_per_night"
},
"min_stars": 4,
"amenities": [
"POOL",
"SPA"
]
},
"preferences": {
"text": "romantic, great breakfast",
"tags": [
"ROMANTIC"
]
},
"ranking": "semantic",
"limit": 10,
"rates": "cached",
"images": 6,
"currency": "EUR",
"locale": "en",
"clarification": {
"policy": "auto"
}
}'{
"billing": {
"amount": "0.012",
"currency": "USD",
"sku": "search.loose.semantic",
"units": 1
},
"clarifications": [],
"hotels": [
{
"amenities": [
"POOL",
"SPA"
],
"hotel_id": "43d0be71-5f3c-4c8e-9a52-1d7e2b6f0a19",
"hotel_type": "hotel",
"images": [
{
"height": 427,
"image_id": "b2e4d6f8-0a1c-4e3a-9d5b-7f9a1c3e5d2c",
"label": "room",
"url": "https://images.vistalink.com/h/43d0be71/room.jpg?w=640",
"width": 640
}
],
"location": {
"address": "Via dell'Umiltà 36",
"city": "Rome",
"country": "IT",
"distance_m": 420,
"lat": 41.9,
"lng": 12.48
},
"name": "Umiltà 36",
"rank": 1,
"rate": {
"currency": "EUR",
"includes_taxes_and_fees": true,
"nights": 2,
"observed_at": "2026-10-07T09:30:00Z",
"offer_id": "off_t3c8e1a9b4f2d7e6a5c0b",
"source": "direct",
"status": "observed",
"total": "962.00"
},
"review_count": 2056,
"review_score": 9.1,
"star_rating": 5,
"summary": "A quiet boutique hotel a few minutes from the Trevi Fountain.",
"thumbnail": {
"image_id": "a1f3c5e7-9b2d-4f6a-8c0e-2d4f6a8c0e1b",
"label": "building",
"url": "https://images.vistalink.com/h/43d0be71/ext.jpg?w=640"
},
"why": [
{
"assessment": "supported",
"criterion": "quiet",
"evidence": "review"
}
]
}
],
"next_cursor": "c_eyJzIjoic3JjaF8zZjljMmE3ZTRiMWQ0YzhhOWU2ZjBiMmQ1YTdjMWU5MyIsIm8iOjEwfQ",
"request_id": "req_8f2c1a9b3d4e5f60",
"resolved": {
"amenities": [
{
"code": "POOL",
"origin": "filters"
}
],
"budget": {
"basis": "per_room_per_night",
"currency": "EUR",
"max": "500",
"origin": "query"
},
"location": {
"label": "Rome, IT",
"lat": 41.9,
"lng": 12.5,
"origin": "filters",
"place_id": "rome-it"
},
"overrides": [],
"stay": {
"check_in": "2026-11-14",
"check_out": "2026-11-16",
"origin": "filters",
"rooms": [
{
"adults": 2,
"children_ages": []
}
]
},
"unresolved": []
},
"search_id": "srch_3f9c2a7e4b1d4c8a9e6f0b2d5a7c1e93",
"status": "completed",
"total_estimate": 143,
"versions": {
"contract": "2.0",
"ranking": "r2026.10"
},
"warnings": [
{
"code": "rates_unavailable",
"message": "Some hotels have no observed rate for these dates."
}
]
}Response 200
Successful Response
| Field | Type | Description |
|---|---|---|
request_idREQUIRED | string | Opaque id of this request, also sent as the X-Request-Id header; quote it when contacting support. |
billing | Billing | null | What a billed call cost. Present on every billed response; billing is null on free ones. |
search_idREQUIRED | string | Id of this search, srch_ plus 32 hex characters, valid for 30 minutes for paging, answering a clarification and GET /v2/hotels/{hotel_id}?search_id=. |
statusREQUIRED | string | completed when the search ran (even with no hotels), needs_clarification when a question must be answered first (free), partial when policy never stopped an ambiguous search (free). One of completed, needs_clarification, partial. |
resolved | object | What the search understood and applied. |
resolved.location | object | null | The place searched; null when the search had no location (for example hotel_ids only). |
resolved.location.place_id | string | null | Slug of city and country, such as rome-it, reusable as filters.location.place_id; null for a near search. |
resolved.location.label | string | null | Readable name of the place, City, CC; null for a near search. |
resolved.location.lat | number | null | Latitude of the city centre or the near point; null when only the city name is known. |
resolved.location.lng | number | null | Longitude of the city centre or the near point; null when only the city name is known. |
resolved.location.origin | string | null | query when the place was read from the query text, filters when it came from filters. One of query, filters. |
resolved.stay | object | null | The stay used for rates; null when none was given or read. |
resolved.stay.check_in | string (date) | null | Arrival date, YYYY-MM-DD. |
resolved.stay.check_out | string (date) | null | Departure date, YYYY-MM-DD. |
resolved.stay.rooms | Occupancy[] | The party per room; a party read from the query is split evenly over its rooms and has no children. |
resolved.stay.rooms[].adultsREQUIRED | integer | Adults in the room. |
resolved.stay.rooms[].children_ages | integer[] | Age of each child in the room; empty for adults only. |
resolved.stay.origin | string | null | query when the stay was read from the query text, filters when it came from filters.stay; null on hotel detail. One of query, filters. |
resolved.budget | object | null | The price band applied; null when none. |
resolved.budget.min | string | null | Lowest price per room per night, a decimal string in currency. |
resolved.budget.max | string | null | Highest price per room per night, a decimal string in currency. |
resolved.budget.currency | string | null | ISO 4217 currency of the band; null when the query named an amount without a currency and none was sent. |
resolved.budget.basis | string | null | What the amounts cover; always per_room_per_night. Always per_room_per_night. |
resolved.budget.origin | string | null | query when the band was read from the query text, filters when it came from filters.budget. One of query, filters. |
resolved.amenities | ResolvedAmenity[] | Amenity requirements applied, all of which a hotel must have. |
resolved.amenities[].codeREQUIRED | string | Amenity code, a group code such as POOL when the term named a group. |
resolved.amenities[].origin | string | null | query when the amenity was read from the query text, filters when it came from filters.amenities. One of query, filters. |
resolved.overrides | Override[] | Conflicts between the query and filters, which the filters won. |
resolved.overrides[].fieldREQUIRED | string | The criterion in conflict: location, stay, budget or hotel_name. One of location, stay, budget, hotel_name. |
resolved.overrides[].query_said | string | null | The value read from the query, for example Paris or 2026-11-14/2026-11-16. |
resolved.overrides[].filters_said | string | null | The value from filters, which was used. |
resolved.overrides[].usedREQUIRED | string | Which value the search used; always filters. One of query, filters. |
resolved.unresolved | string[] | Criteria the search could not apply: location, stay (dates in the query could not be read), budget_currency (a budget without a currency), amenities (a term with no amenity code). One of location, stay, budget_currency, amenities. |
clarifications | Clarification[] | The question to answer when status is needs_clarification; empty otherwise. |
clarifications[].idREQUIRED | string | Clarification id to send back as answers[].clarification_id. |
clarifications[].fieldREQUIRED | string | The criterion that is ambiguous or missing; location (a city or landmark with several matches, or no place at all) is the only one asked today. |
clarifications[].questionREQUIRED | string | The question to show the traveller, in English. |
clarifications[].answer_type | string | How to answer: single_choice (send one of options as option_id) or free_text (no options; send the traveller's answer as value, for example a city when the search named no place). One of single_choice, multi_choice, free_text. Default single_choice. |
clarifications[].options | ClarificationOption[] | The possible answers: at least two for single_choice, none for free_text. |
clarifications[].options[].idREQUIRED | string | Option id to send back as answers[].option_id, for example opt_gb. |
clarifications[].options[].labelREQUIRED | string | What to show the traveller, for example Cambridge, England. |
hotels | SearchHotel[] | This page of results, best first; empty unless status is completed. |
total_estimate | integer | null | Size of the ranked candidate pool behind the results, not a catalogue-wide count; at most 50 can be paged. Null unless status is completed. |
next_cursor | string | null | Pass as cursor for the next page, free of charge; null on the last page. |
warnings | Warning_[] | Things the search could not fully do. |
versions | object | Contract and ranking versions. |
versions.contract | string | API contract version, 2.0. Default 2.0. |
versions.ranking | string | null | Version of the ranking model, for example r2026.10; results from the same version are comparable. |
Errors
| Status | Code | When |
|---|---|---|
| 400 | bad_request | Validation errors carry details.fields[]. |
| 401 | unauthorized | No key, or the key is unknown or revoked. |
| 402 | insufficient_credit | Not enough credit for the call. Checked before any work starts, so nothing was billed. |
| 403 | forbidden | Missing scope. |
| 429 | rate_limited | Over the per-minute limit for the tier. Wait Retry-After seconds. |
| 503 | unavailable | We're temporarily unable to serve the call. Retry with backoff. |
/v2/chatSynchronous; needs the chat scope and bills chat.turn per turn, except turns that only ask a clarifying question, which are free. Same request as /v1/chat plus search_id; hotels[] use the search card shape, and the conversation is remembered per session_id.
Billed per turn. Clarification-only turns are free.
Request body
| Field | Type | Description |
|---|---|---|
messageREQUIRED | string | What the traveller said, up to 4,000 characters. |
session_id | string | null | Conversation to continue, a uuid from an earlier response; omit to start a new conversation. |
guest_id | string | null | Your id for the traveller, a uuid, recorded on a new conversation; ignored when session_id is set. |
currency | string | null | ISO 4217 currency the assistant should talk in; card prices stay in the currency they were observed in. |
locale | string | null | Language of the conversation as a language tag; en when omitted. |
context | object | null | Structured context passed to the assistant, for example a stay as check_in, check_out, rooms and adults; with a stay, hotel cards carry cached rates. |
clarification_id | string | null | The clarification_pending.clarification_id being answered. |
clarification_option_id | string | null | The chosen option of that clarification. |
user_location | object | null | The traveller's current position, for questions like 'near me'. |
user_location.latREQUIRED | number | Latitude in decimal degrees. -90–90. |
user_location.lngREQUIRED | number | Longitude in decimal degrees. -180–180. |
user_location.accuracy | number | null | Accuracy radius of the position in metres. |
search_id | string | null | Accepted for symmetry with search; not used as input. |
Example
curl -X POST 'https://api.vistalink.com/v2/chat' \
-H "Authorization: Bearer $VISTALINK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Somewhere quiet near the Pantheon for two nights in November",
"currency": "EUR",
"locale": "en"
}'{
"billing": {
"amount": "0.03",
"currency": "USD",
"sku": "chat.turn",
"units": 1
},
"hotels": [],
"message": "Here are three quiet options a short walk from the Pantheon.",
"request_id": "req_8f2c1a9b3d4e5f60",
"search_id": "srch_3f9c2a7e4b1d4c8a9e6f0b2d5a7c1e93",
"session_id": "9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"
}Response 200
Successful Response
| Field | Type | Description |
|---|---|---|
request_idREQUIRED | string | Opaque id of this request, also sent as the X-Request-Id header; quote it when contacting support. |
billing | Billing | null | What a billed call cost. Present on every billed response; billing is null on free ones. |
session_idREQUIRED | string | Conversation id; send it back to continue the conversation. |
messageREQUIRED | string | The assistant's reply in plain text. |
hotels | SearchHotel[] | Hotels the reply refers to, up to 20, in the search card shape. |
pois | object[] | A place the turn located, as {name, lat, lng, ...}; at most one per turn. |
routes | object[] | Travel routes computed in the turn; always empty today. |
references | object[] | Web sources cited in the turn as {url, title, domain, index}; always empty today. |
clarification_pending | object | null | A question the assistant needs answered, with clarification_id, question and options[]; null otherwise. Answer it with clarification_id and clarification_option_id. |
segments | object[] | The reply split for rendering, each {type, id} plus content for text, hotel_id for hotel_ref or hotel_ids for trip_suggestion. |
search_id | string | null | A search_id for the hotels in this turn, valid for 30 minutes with GET /v2/hotels/{hotel_id}?search_id=; null when the turn returned no hotels. |
warnings | Warning_[] | Things the turn could not fully do, such as rates_unavailable or channel_unavailable. |
Errors
| Status | Code | When |
|---|---|---|
| 400 | bad_request | Validation errors carry details.fields[]. |
| 401 | unauthorized | No key, or the key is unknown or revoked. |
| 402 | insufficient_credit | Not enough credit for the call. Checked before any work starts, so nothing was billed. |
| 403 | forbidden | Missing scope. |
| 429 | rate_limited | Over the per-minute limit for the tier. Wait Retry-After seconds. |
| 503 | unavailable | We're temporarily unable to serve the call. Retry with backoff. |
POST /v2/chat answers with the assistant's message, the hotels it talked about as the same cards search returns, and any pois, routes, references and segments the answer leans on. Send the session_id back on the next turn and the conversation carries on.
When the assistant needs an answer before it can search, clarification_pending holds the question; otherwise it's null. Reply with clarification_id and clarification_option_id, or in words. A turn that only asks a question is free.
A turn that searched returns a search_id, so hotel detail is warm for its cards. Put check_in and check_out in context to get cached prices on the cards, and send user_location (lat, lng, optional accuracy) for anything near the user.
Objects that appear in more than one place. Billing is on the Billing page and ErrorBody under Errors & limits.
StayDates and rooms of a stay, up to 30 nights and 9 rooms.
| Field | Type | Description |
|---|---|---|
check_inREQUIRED | string (date) | Arrival date, YYYY-MM-DD. |
check_outREQUIRED | string (date) | Departure date, YYYY-MM-DD, after check_in and at most 30 nights later. |
rooms | RoomOccupancy[] | One entry per room, 1 to 9; defaults to one room for two adults. At most 9. |
rooms[].adults | integer | Adults in this room, 1 to 16. Default 2. |
rooms[].children_ages | integer[] | Age of each child in this room, 0 to 17, one entry per child; empty for adults only. At most 8. |
SearchHotelOne hotel in search or chat results.
| Field | Type | Description |
|---|---|---|
hotel_idREQUIRED | string (uuid) | The hotel's id, for GET /v2/hotels/{hotel_id} and the other endpoints. |
rankREQUIRED | integer | Position in the full result list, starting at 1 and continuing across pages. |
nameREQUIRED | string | Hotel name. |
hotel_type | string | null | Kind of property as catalogued, free text such as hotel; null when unknown. |
thumbnail | ImageRef | null | An image on a search card, resized to 640 pixels wide. |
images | ImageRef[] | Up to images gallery images in gallery order, at 640 pixels wide. |
star_rating | number | null | Official star rating, 1 to 5; null when unrated. |
review_score | number | null | Average guest review score on a 0 to 10 scale; null when there are no reviews. |
review_count | integer | null | Number of guest reviews behind review_score; null when none. |
location | object | null | Where the hotel is. |
location.lat | number | null | Latitude in decimal degrees. |
location.lng | number | null | Longitude in decimal degrees. |
location.city | string | null | City the hotel is in. |
location.country | string | null | ISO 3166-1 alpha-2 country code, or the country name when no code is known. |
location.address | string | null | Street address on one line, from street and number to country. |
location.distance_m | number | null | Straight-line distance in metres from filters.near or the landmark named in the query; null when the search had neither. |
amenities | string[] | Up to 20 uppercase amenity codes, group codes such as POOL first. |
summary | string | null | The start of the hotel's description, at most 400 characters, cut at a sentence or word boundary; null when there is no description. |
rate | object | null | The cheapest stored price for the stay; null when rates is none or no stay was given. |
rate.statusREQUIRED | string | observed when seen recently (within 4 hours for stays in the next 14 days, else 24 hours), stale when older but within 7 days, unknown when there is no usable price and the other fields are null. One of observed, stale, unknown. |
rate.total | string | null | Price for the whole stay and all rooms, a decimal string in currency with taxes and fees included where known. |
rate.currency | string | null | ISO 4217 currency the price was observed in; never converted. |
rate.nights | integer | null | Number of nights the total covers. |
rate.includes_taxes_and_fees | boolean | null | True when total includes taxes and fees, false when some are charged on top, null when unknown. |
rate.source | string | null | Where the price was observed: direct for the hotel's own booking engine, third_party for the Enterprise third-party channel. One of direct, third_party. |
rate.observed_at | string (date-time) | null | When the price was observed, RFC 3339 UTC. |
rate.offer_id | string | null | The offer behind this price, bookable with POST /v2/bookings for 30 minutes. |
why | WhyItem[] | Evidence for the hotel on each criterion of the query, up to 6 items; empty unless ranking is semantic (chat fills it from its own reasoning). |
why[].criterionREQUIRED | string | The traveller's own word or requirement being checked, for example quiet or pool. |
why[].assessmentREQUIRED | string | supported when the evidence backs the criterion, contradicted when it goes against it (reviews only), unknown when it is inconclusive. One of supported, contradicted, unknown. |
why[].evidence | string | null | What was checked: review (guest review sentiment), image (photos), amenity (the amenity list) or description (chat only). One of review, image, amenity, description. |
WarningSomething the response could not fully do, without failing it.
| Field | Type | Description |
|---|---|---|
codeREQUIRED | string | Stable warning code: rates_unavailable (some hotels have no stored rate), rates_need_stay (rates asked for without a stay), channel_unavailable (the third-party channel was left out), constraints_relaxed (no exact match, so some constraints were loosened), semantic_unavailable, unresolved (with clarification policy never), search_id_unavailable (the search cannot be paged or referenced), on chat price_redacted (a price in the reply that is not a direct rate was replaced with "a rate on request"), and on rates currency_unavailable. |
message | string | null | Explanation in English. |
channel | string | null | The channel left out, third_party; set only on channel_unavailable. Always third_party. |
ImageRefAn image on a search card, resized to 640 pixels wide.
| Field | Type | Description |
|---|---|---|
image_id | string (uuid) | null | Image id; the same image keeps the same id across responses. |
urlREQUIRED | string (uri) | CDN URL of the image at 640 pixels wide. |
label | string | null | What the image shows, for example building, room, bathroom or swimming pool outdoor; null when unlabelled. |
width | integer | null | Width in pixels of the image at url; null on thumbnail and when unknown. |
height | integer | null | Height in pixels of the image at url; null on thumbnail and when unknown. |