8.2 KiB
Travel APIs — Airbnb, Booking, Google Flights
| Endpoint | Returns |
|---|---|
/scrape/airbnb/listing |
Airbnb search results |
/scrape/airbnb/property |
Single Airbnb listing |
/scrape/booking/search |
Booking.com search results (hotels, apartments) |
/scrape/booking/place |
Single Booking.com property with room/rate list |
/scrape/google/flights |
Google Flights prices and itineraries |
All synchronous GET. Airbnb is 5 credits; Booking is 10; Google Flights is 15.
For activities at the destination see /scrape/google/events (in search.md); for ground transport, scrape the operator's site with POST /scrape/web.
Airbnb
import requests
def airbnb_search(location, check_in, check_out, **kwargs):
return requests.get(
"https://api.hasdata.com/scrape/airbnb/listing",
headers={"x-api-key": API_KEY},
params={"location": location, "checkIn": check_in, "checkOut": check_out, **kwargs},
timeout=300,
).json()
| Param | Notes |
|---|---|
location |
Required. Free-form. |
checkIn |
Required. YYYY-MM-DD. |
checkOut, adults, children, infants, pets |
Optional. |
nextPageToken |
Pagination cursor. |
Token pagination
def airbnb_all(location, check_in, check_out):
out, token = [], None
while True:
page = airbnb_search(location, check_in, check_out,
**({"nextPageToken": token} if token else {}))
out.extend(page.get("listings", []))
token = page.get("nextPageToken")
if not token:
return out
Airbnb Property
requests.get(
"https://api.hasdata.com/scrape/airbnb/property",
headers={"x-api-key": API_KEY},
params={"url": "https://www.airbnb.com/rooms/12345678"},
timeout=300,
)
Booking Search
import json, requests
def booking_search(keyword, check_in, check_out, *, adults=2, children=0,
children_ages=None, rooms=1, **filters):
params = {
"keyword": keyword,
"checkInDate": check_in,
"checkOutDate": check_out,
"adults": adults,
"children": children,
"rooms": rooms,
**filters,
}
if children and children_ages:
params["childrenAgesJson"] = json.dumps(children_ages)
return requests.get(
"https://api.hasdata.com/scrape/booking/search",
headers={"x-api-key": API_KEY},
params=params, timeout=300,
).json()
| Param | Notes |
|---|---|
keyword |
Required. City, neighborhood, or property name. |
checkInDate / checkOutDate |
Required. YYYY-MM-DD. |
adults, children, rooms |
Required. Pass children=0 explicitly when none. |
childrenAgesJson |
Required iff children > 0 — JSON array of ages (0–17), one per child. |
price[min] / price[max] |
>= 10 / >= 20. Bracketed — requests/axios serialize nested dicts as price[min]=…. |
rating[], reviewScore[], propertyType[], facilities[], meals[], bedPreference[], roomFacilities[], propertyAccessibility[], roomAccessibility[], distanceFromCenter[], travelGroup[], onlinePayment[], reservationPolicy[] |
Multi-value filters (OR). |
bedrooms, bathrooms |
Minimum count. |
sort |
ourTopPicks, homesAndApartmentsFirst, priceLowestFirst, priceHighestFirst, bestReviewedAndLowestPrice, ratingHighToLow, ratingLowToHigh, ratingAndPrice, distanceFromDowntown, topReviewed. |
page |
1-indexed, 25 results per page. |
currency |
ISO code or hotelCurrency to keep native. |
language |
UI locale. |
Top-level response (verified live): requestMetadata, searchInformation, pagination, results. Per-result keys: hotelId, roomId, title, url, location, rating, reviews, price (object with total / nightly / currency), room, beds, bedTypes, policies, photo.
Booking Place
resp = requests.get(
"https://api.hasdata.com/scrape/booking/place",
headers={"x-api-key": API_KEY},
params={
"url": "https://www.booking.com/hotel/fr/le-bristol-paris.html",
"checkInDate": "2026-07-10",
"checkOutDate": "2026-07-13",
"adults": 2,
"children": 0,
"rooms": 1,
},
timeout=300,
).json()
url must be booking.com / www.booking.com. The remaining stay/guest parameters share the same rules as booking-search (including childrenAgesJson when children > 0).
Response top-level keys: requestMetadata, overview, bookingDetails, rooms, facilities, houseRules, ratings, reviews, restaurants, breadcrumbs, questionsAndAnswers.
overview→id,title,address,description,propertyType,photos,highlights,mostPopularFacilities.rooms[i]→roomId,name,bedTypes,beds,facilities,otherFacilities,variants[](per-rate price/availability). Variants are the actual buyable units;rooms[i]is the floor-plan.
Google Flights
resp = requests.get(
"https://api.hasdata.com/scrape/google/flights",
headers={"x-api-key": API_KEY},
params={
"departureId": "JFK",
"arrivalId": "LAX",
"outboundDate": "2026-06-15",
"returnDate": "2026-06-22", # omit for one-way
"currency": "USD",
},
timeout=300,
).json()
| Param | Notes |
|---|---|
departureId / arrivalId |
Required. IATA airport codes (JFK, LAX). |
outboundDate |
Required. YYYY-MM-DD. |
returnDate |
Optional — omit for one-way. |
currency |
ISO code. |
gl, hl |
Country / language. |
travelClass |
1 economy, 2 premium economy, 3 business, 4 first. |
stops |
0 any, 1 non-stop, 2 ≤1 stop, 3 ≤2 stops. |
adults, children, infantsInSeat, infantsOnLap |
Passenger counts. |
Patterns
STR yield estimate
rentals = airbnb_search(area, ci, co).get("listings", []) # Airbnb → "listings"
# pair with /scrape/zillow/listing (see real-estate.md) for purchase price
night = sum(r.get("price", 0) for r in rentals) / max(len(rentals), 1)
Hotel-vs-rental price diff
b = booking_search(city, ci, co, adults=2, children=0, rooms=1, sort="priceLowestFirst")
a = airbnb_search(city, ci, co, adults=2)
def median(xs): xs = sorted(xs); return xs[len(xs)//2] if xs else None
median_hotel = median([r["price"]["nightly"] for r in b.get("results", []) if r.get("price")])
median_str = median([r["price"] for r in a.get("listings", []) if r.get("price")])
Full trip cost
flight = requests.get(
"https://api.hasdata.com/scrape/google/flights",
headers={"x-api-key": API_KEY},
params={"departureId": origin, "arrivalId": dest_iata,
"outboundDate": dep, "returnDate": ret, "currency": "USD"},
timeout=300,
).json()
cheapest_flight = min((f["price"] for f in flight.get("best_flights", [])), default=None)
stay = booking_search(city, dep, ret, adults=2, children=0, rooms=1, sort="priceLowestFirst")
cheapest_stay = stay.get("results", [{}])[0].get("price", {}).get("total")
total = (cheapest_flight or 0) + (cheapest_stay or 0)
Gotchas
- Airbnb requires
checkInand uses token pagination — storenextPageToken, not page numbers. - Airbnb property endpoints take URLs, not IDs.
- Booking requires
childreneven when zero. Passchildren=0. Whenchildren > 0, also passchildrenAgesJsonwith exactly that many ages. - Booking
price[min]/price[max]are bracketed — use a nested dict withrequests/axios. - Booking
rooms[i].variants[]is where prices live — the parentrooms[i]describes the floor-plan, variants are the buyable rates withpriceBreakdown/cancellationPolicy/mealPlan. bookingDetailscarries the resolved stay context the response was priced for — echo it back when persisting results so future comparisons use the same dates / occupancy.- Google Flights uses IATA codes, not city names.
JFKnotNew York. - Round-trip vs one-way is determined by
returnDatepresence — pass it for round-trip, omit for one-way.