Irmu
Guides11 minIrmu Engineering

Booking.com API Alternative: Get Hotel Data Without Partner Approval

The official Booking.com API is only open to approved partners. Here's how to get search results, hotel details, room prices and ratings as JSON anyway — with curl, Python and Node examples.

Why most developers can't use the Booking.com API

Booking.com does have APIs, but they're built for its business partners — connectivity providers, affiliates and accommodation managers — and access goes through an application and approval process. If you're a developer building a price tracker, a market study or a travel side project, you'll usually find the door closed, or open only to endpoints that don't return what you need.

So people search for "Booking.com API" and end up scraping. Scraping Booking yourself means a JavaScript-rendered results page, lazy-loaded cards, frequently changing markup and bot protection that turns away datacenter IPs. It works until it doesn't, usually on the day you need the data.

What you actually need from Booking.com

Most projects need two things: the list of properties in a destination for a stay, and the details of a single property. Irmu has a ready-made endpoint for each, so you don't write or maintain selectors.

  • `GET /booking/search` — a destination plus optional `checkin`, `checkout`, `adults`, `rooms`, `currency`. Returns the first page of results, one row per property card.
  • `GET /booking/hotel` — a `booking.com/hotel/...` URL plus optional dates. Returns one object: price and room prices, rating, facilities, points of interest, review subscores, featured reviews and questions.
  • Both cost a flat 30 credits. `premium`, `country` and `city` change where the request comes from, not the price.

Search a destination

Pass the destination the way you'd type it into Booking's search box. Add dates if you want prices — without dates, many cards show no price. Every field comes back as text, exactly as Booking prints it, and a field the card doesn't show is left out of that row.

search.sh
curl -G "https://app.irmu.com/api/booking/search" \
  -H "Authorization: Bearer $IRMU_API_KEY" \
  --data-urlencode "destination=Lisbon" \
  -d checkin=2026-12-04 -d checkout=2026-12-06 \
  -d adults=2 -d rooms=1 -d currency=EUR
search-response.json
{
  "destination": "Lisbon",
  "checkin": "2026-12-04",
  "checkout": "2026-12-06",
  "adults": 2,
  "rooms": 1,
  "hotels": [
    {
      "name": "…",
      "url": "https://www.booking.com/hotel/pt/….en-gb.html",
      "price": "€ 318",
      "priceInfo": "2 nights, 2 adults",
      "address": "Baixa, Lisbon",
      "reviewScore": "8.9",
      "reviewWord": "Fabulous",
      "reviewCount": "2,105 reviews"
    }
  ],
  "credits_charged": 30,
  "status": "done"
}

A search that returns no properties is still a served request and is still charged. Check your destination spelling before running a big batch.

Read a single hotel

Feed any property URL from the search into `/booking/hotel`. Here the data is structured: price and each room price as `{ amount, currency, original, discount }`, rating as `{ score, word, count }`, and facilities grouped the way the page groups them.

If the page can't be read, `hotel` comes back `null` and the request is refunded (`credits_charged: 0`) — queue it for a retry instead of treating it as an empty hotel.

hotel.py
import os, time, requests

API = "https://app.irmu.com/api"
HEADERS = {"Authorization": f"Bearer {os.environ['IRMU_API_KEY']}"}

def get_hotel(url, checkin=None, checkout=None, adults=2, currency="EUR"):
    params = {"url": url, "adults": adults, "currency": currency}
    if checkin: params |= {"checkin": checkin, "checkout": checkout}
    res = requests.get(f"{API}/booking/hotel", headers=HEADERS, params=params, timeout=200)
    body = res.json()
    while res.status_code == 202:          # paid, still running — collecting is free
        time.sleep(5)
        res = requests.get(f"{API}/crawl/{body['job_id']}", headers=HEADERS, timeout=60)
        body = res.json()
    return body

h = get_hotel("https://www.booking.com/hotel/pt/example.en-gb.html", "2026-12-04", "2026-12-06")
if h.get("hotel") is None:
    print("unreadable, refunded — retry later")
else:
    print(h["hotel"]["rating"], h["hotel"]["price"])

From search to dataset in Node

The usual pipeline: search a destination for a stay, deduplicate the property URLs, then read each hotel. Keep concurrency within your plan's limit and back off on `429`.

pipeline.mjs
const API = "https://app.irmu.com/api";
const headers = { Authorization: `Bearer ${process.env.IRMU_API_KEY}` };
const stay = { checkin: "2026-12-04", checkout: "2026-12-06", adults: "2", currency: "EUR" };

async function call(path, params, tries = 0) {
  const res = await fetch(`${API}${path}?${new URLSearchParams(params)}`, { headers });
  if (res.status === 429 && tries < 5) {
    await new Promise((r) => setTimeout(r, 2 ** tries * 1000));
    return call(path, params, tries + 1);
  }
  return res.json();
}

const search = await call("/booking/search", { destination: "Lisbon", ...stay });
const urls = [...new Set(search.hotels.map((h) => h.url.split("?")[0]))];

for (const url of urls) {
  const { hotel } = await call("/booking/hotel", { url, ...stay });
  if (!hotel) continue; // refunded; retry later
  console.log(hotel.name, hotel.price?.amount, hotel.rating?.score);
}

Seeing prices like a local

Booking shows different prices, taxes and sometimes availability depending on where the visitor appears to be. Use `country` (and optionally `city`) to pin the request to the market you care about, and set `currency` explicitly so your numbers are comparable. If the standard pool gets turned away, `premium=true` uses residential IPs at no extra cost on these endpoints.

Cost and billing

Every search and every hotel read is 30 credits. A destination search plus 25 hotel reads is 780 credits. Tracking that set daily for a month is about 23,400 credits — within the Lite plan's monthly volume.

  • Charged: any served request, including a search with no results.
  • Refunded: a hotel page that couldn't be read (`hotel: null`, `credits_charged: 0`).
  • Free: collecting a `202` job from `GET /crawl/{job}`.

Official API or Irmu?

If you're an approved Booking.com partner and the partner API returns what you need, use it — it's the supported route. If you're not, or you need what the public site shows a traveller (the displayed price, reviews, facilities, the ranking in search), the endpoints above get you there in a few lines without maintaining a scraper.

For a full walkthrough of building a hotel database and storing rate history over time, read our guide on scraping hotel prices.

Start building with Irmu today

200 free credits every month, no card required. Every API, every integration, one key.