A first call in five minutes.
Get a key, export it, run one search. The same call is shown as curl, the CLI, TypeScript and Python.
Until launch, v2 sits behind a server flag: the routes and MCP tools on these pages answer once we switch it on. v1 keeps working in the meantime.
Get a key.
Sign up and you get a free key with $5 of credit each month. It doesn't roll over. Free keys allow 10 requests a minute. Free covers search, hotel detail, cached rates for up to 100 hotels a call, and chat, all charged against the $5 monthly credit. Test keys hit the real catalogue and spend credit; they never create Stripe charges.
export VISTALINK_API_KEY=vl_test_…Make a first call.
A loose, semantic search: a sentence in, ranked hotels out, with cached prices for the dates you sent. It costs $0.012 / search. Base URL https://api.vistalink.com.
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."
}
]
}Every response has a request_id and a billingobject saying what the call cost. Pass the response's search_id to hotel detail and the profile is already warm.
The CLI.
Install @vistalink/cli and every endpoint is a command: vistalink <group> <verb> [id] [--flag value]. Flags are the JSON field names in kebab-case. Plain values go bare, lists are comma-separated, objects are JSON, and --data @file.json sends a whole body. It reads VISTALINK_API_KEY.
npm install -g @vistalink/cli
# A hotel website in, a hotel_id out
vistalink hotels resolve --website-url https://umilta36.com
# Cached direct rates for one stay
vistalink rates get \
--idempotency-key 4f1c2b8e-booking-ada-rossi \
--hotels '["43d0be71-5f3c-4c8e-9a52-1d7e2b6f0a19",{"website_url":"https://umilta36.com"}]' \
--stay '{"check_in":"2026-11-14","check_out":"2026-11-16","rooms":[{"adults":2,"children_ages":[]}]}' \
--channel direct \
--freshness cached \
--max-age-hours 24 \
--currency EURPick the family you need.
- Identifiers: Turn Booking.com and Expedia URLs, hotel websites or a name and city into hotel ids. Free.
- Search: Filters or free text in, ranked hotel cards out, with cached prices when you send dates.
- Hotels: The full profile: gallery, rooms and their listings, venues, policies, reviews and prices for a stay.
- Rates: Prices from each hotel's own booking engine, from cache now or read live as a job.
- Rooms: Match one hotel's rooms across Booking.com, its own site, Expedia and your own list, with a confidence each.
- Bookings: Book an offer on the hotel's own engine. The guest pays the property; booking is free.