API v2 · Identifiers

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.

POST /v2/hotels/resolveFree
A Booking.com page → hotel_idMatched on the listing’s own address, so the match is exact.

match exact · basis booking_slug

The hotel’s own site → verifiedA website we’ve tied to the property comes back verified.

match verified · basis trusted_website_identity

Name + city → probable 0.91With no link to go on, the name and the city still find it, with a confidence you can set a threshold on.

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.

Identifiers

The identifier object

Send exactly one way of pointing at the hotel per object.

FieldTypeDescription
booking_urlstring (uri) | nullAn OTA listing URL of the form https://www.booking.com/hotel/{cc}/{slug}.html; matched on the listing slug.
website_urlstring (uri) | nullThe hotel's own website; only the host is matched, so a bare domain works too.
expedia_urlstring (uri) | nullAn Expedia listing URL carrying .h{id}.; answered unsupported until Expedia listings are indexed.
namestring | nullHotel name, matched against indexed hotels in city; needs city.
citystring | nullCity of the hotel named in name; required with name, not allowed without it.
countrystring | nullISO 3166-1 alpha-2 country of the hotel named in name; narrows the name match, and a wrong value makes it miss.
Resolve

Resolve hotel identifiers to hotel_id

POST/v2/hotels/resolve
Mode
Sync · 200
Price
Free
Auth
Scope search

Free 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

FieldTypeDescription
identifiers
REQUIRED
HotelIdentifier[]Between 1 and 500 hotels to resolve, each in one identifier form; results come back in the same order. At most 500.

Example

Request
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"
    }
  ]
}'
Response
200
{
  "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

FieldTypeDescription
request_id
REQUIRED
stringOpaque id of this request, also sent as the X-Request-Id header; quote it when contacting support.
billingBilling | nullWhat a billed call cost. Present on every billed response; billing is null on free ones.
results
REQUIRED
ResolveResult[]One result per identifier, in request order.
results[].input
REQUIRED
integerIndex of the identifier in the request's identifiers[] this result answers.
results[].status
REQUIRED
stringresolved 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_idstring (uuid) | nullThe matched hotel's id; present only when status is resolved.
results[].matchstring | nullHow 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[].basisstring | nullWhat 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[].confidencenumber | nullScore 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[].reasonstring | nullWhy 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_slugstring | nullThe listing slug as {cc}/{slug} in lower case, for example it/umilta-36; present only on known_unindexed.

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.