Bring the URL you have. Get a hotel_id.
Turn Booking.com and Expedia URLs, hotel websites or a name and city into hotel ids. Free.
match exact · basis booking_slug
match verified · basis trusted_website_identity
match probable · basis name_city · 0.91
A kind of link we don’t read yet answers unsupported with a reason (expedia_not_ingested), and the rest of the batch still resolves.
Every v2 endpoint that takes hotels accepts a hotel_id or an inline identifier object. Inline identifiers are resolved exactly as POST /v2/hotels/resolve would, and an input we can't match comes back unresolved instead of failing the call.
Resolve in bulk first when you hold a list of URLs: up to 500 per call, no charge, and match tells you how far to trust each answer.
The identifier object
Send exactly one way of pointing at the hotel per object.
| Field | Type | Description |
|---|---|---|
booking_url | string (uri) | null | An OTA listing URL of the form https://www.booking.com/hotel/{cc}/{slug}.html; matched on the listing slug. |
website_url | string (uri) | null | The hotel's own website; only the host is matched, so a bare domain works too. |
expedia_url | string (uri) | null | An Expedia listing URL carrying .h{id}.; answered unsupported until Expedia listings are indexed. |
name | string | null | Hotel name, matched against indexed hotels in city; needs city. |
city | string | null | City of the hotel named in name; required with name, not allowed without it. |
country | string | null | ISO 3166-1 alpha-2 country of the hotel named in name; narrows the name match, and a wrong value makes it miss. |
Resolve hotel identifiers to hotel_id
/v2/hotels/resolveFree and synchronous; needs the search scope. Up to 500 identifiers (a listing URL in booking_url, the hotel's own website_url, an expedia_url, or name + city + country) come back as one result each, in request order. An input that does not resolve carries its status and reason instead of failing the call.
Request body
| Field | Type | Description |
|---|---|---|
identifiersREQUIRED | HotelIdentifier[] | Between 1 and 500 hotels to resolve, each in one identifier form; results come back in the same order. At most 500. |
Example
curl -X POST 'https://api.vistalink.com/v2/hotels/resolve' \
-H "Authorization: Bearer $VISTALINK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"identifiers": [
{
"booking_url": "https://www.booking.com/hotel/it/umilta-36.en-gb.html"
},
{
"website_url": "https://umilta36.com"
},
{
"expedia_url": "https://www.expedia.com/Rome-Hotels-Umilta-36.h12345.Hotel-Information"
},
{
"name": "Umiltà 36",
"city": "Rome",
"country": "IT"
}
]
}'{
"request_id": "req_8f2c1a9b3d4e5f60",
"results": [
{
"basis": "booking_slug",
"hotel_id": "43d0be71-5f3c-4c8e-9a52-1d7e2b6f0a19",
"input": 0,
"match": "exact",
"status": "resolved"
},
{
"basis": "trusted_website_identity",
"hotel_id": "43d0be71-5f3c-4c8e-9a52-1d7e2b6f0a19",
"input": 1,
"match": "verified",
"status": "resolved"
},
{
"input": 2,
"reason": "expedia_not_ingested",
"status": "unsupported"
},
{
"basis": "name_city",
"confidence": 0.91,
"hotel_id": "43d0be71-5f3c-4c8e-9a52-1d7e2b6f0a19",
"input": 3,
"match": "probable",
"status": "resolved"
}
]
}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. |
resultsREQUIRED | ResolveResult[] | One result per identifier, in request order. |
results[].inputREQUIRED | integer | Index of the identifier in the request's identifiers[] this result answers. |
results[].statusREQUIRED | string | resolved when a hotel was found, known_unindexed when the listing exists but the hotel is not indexed yet, unresolved when nothing matched, unsupported when that identifier kind is not served yet. One of resolved, known_unindexed, unresolved, unsupported. |
results[].hotel_id | string (uuid) | null | The matched hotel's id; present only when status is resolved. |
results[].match | string | null | How certain the match is, present only when resolved: exact for a listing slug or id, verified for a confirmed website identity, probable for a website host or name match. One of exact, verified, probable. |
results[].basis | string | null | What the match rests on, present only when resolved: booking_slug, trusted_website_identity, website_host, expedia_id, name_city, or hotel_id when a uuid was passed through. One of booking_slug, trusted_website_identity, website_host, expedia_id, name_city, hotel_id. |
results[].confidence | number | null | Score from 0 to 1 on probable matches: 0.8 for a website host, 0.5 to 0.95 for a name match by strength (lower when a second candidate is as strong); absent on exact and verified. |
results[].reason | string | null | Why the input did not resolve; absent when resolved. not_found, ambiguous_website (the host belongs to several hotels), unparseable_booking_url, unparseable_website_url, unparseable_expedia_url or invalid_hotel_id with unresolved; expedia_not_ingested with unsupported; not_indexed with known_unindexed. One of not_found, ambiguous_website, unparseable_booking_url, unparseable_website_url, unparseable_expedia_url, invalid_hotel_id, expedia_not_ingested, not_indexed. |
results[].booking_slug | string | null | The listing slug as {cc}/{slug} in lower case, for example it/umilta-36; present only on known_unindexed. |
Errors
| Status | Code | When |
|---|---|---|
| 400 | bad_request | Validation errors carry details.fields[]. |
| 401 | unauthorized | No key, or the key is unknown or revoked. |
| 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. |