Browse documentation
GET

Hotel Rooms API

Extract comprehensive room details and bookable rates from Booking.com hotels by hotel ID.

Overview

Fast & Reliable

Returns normalized live room inventory and rate data. Typical response time: 2–4 seconds.

The Hotel Rooms endpoint returns static per-room information (descriptions, photos, bed configurations, facilities, highlights) alongside the bookable rates available for a specific date range (prices, refund policies, meal plans, availability). You can use the same endpoint for both a visual room catalogue and a booking-intent quote.

Endpoint URL

GET https://api.stayapi.com/v1/booking/hotel/rooms

Need a hotel ID?

Use /v1/booking/hotel/url-to-id to convert a Booking.com URL or slug to a numeric hotel ID.

Query Parameters

Parameter Type Required Description
hotel_id integer (> 0) Required Numeric Booking.com hotel ID (for example, 346648).
checkin string (YYYY-MM-DD) Optional Arrival date. Defaults to today + 14 days.
checkout string (YYYY-MM-DD) Optional Departure date. Defaults to today + 15 days.
adults integer Optional Number of adults (1–30, default: 2).
children integer Optional Number of children (0–10, default: 0).
rooms integer Optional Number of rooms (1–8, default: 1).
currency string (ISO 4217) Optional Display currency for rate prices (default: USD). Examples: EUR, GBP, THB.
country_market string (ISO-3166) Optional Two-letter market country (default: US). Booking.com prices by the visitor's country, so the same stay can cost different amounts per market. Use the same value across search, rooms, and prices for matching numbers; the value used is echoed in the response.

Response Structure

Top-level fields

  • success — boolean, always true for 2xx responses.
  • data.hotel_info — basic property info (id, currency_code).
  • data.rooms — array of room types with static data (see below).
  • data.rates — array of bookable blocks for the requested dates (see below).
  • data.availability_summary — deduplicated inventory totals across data.rates:
    • availability_status — available when at least one bookable rate was returned, otherwise no_inventory.
    • total_available_rooms — sum of the maximum room_count_available per room_id, so a room type sold under several rate plans is counted once. null when there are no bookable rates.
    • available_rate_blocks — number of entries in data.rates.
    • available_room_types_counted — number of distinct room_ids that contributed a count.
    • room_counts_by_room_id — the per-room-type counts that were summed.
    • rates_without_room_count_available — rate blocks returned without a usable count.
    • calculation_method — human-readable formula string.
  • data.search_config — echoes the guest/date configuration you requested.
  • data.metadata — hotel_id, total_rooms, total_blocks, arrival_date, departure_date, scraped_at.
  • retrieved_at — ISO-8601 UTC timestamp.

Per-room fields (data.rooms[])

  • id — stable room-type identifier.
  • name — human-readable room-type name (derived from the first associated rate).
  • description — full room description (may contain HTML formatting).
  • ai_description — short AI-generated comparative description (may contain <b> tags).
  • room_size_m2, room_size_ft2 — room size in metric and imperial units.
  • is_smoking, is_dormitory — booleans.
  • bathroom_count — number of bathrooms; null when Booking.com doesn't list a count (common for hotel rooms). private_bathroom — true for a private bathroom, false for a shared one, null when unknown.
  • photos[] — array with id, url_original, url_max300, url_square60, url_640x200, and ratio.
  • bed_configurations[] — each has a beds array with bed_type, name, name_with_count, count, description, description_imperial.
  • facilities[] — each has id, name, category, category_id.
  • highlights[] — each has id, name, icon.

Per-rate fields (data.rates[])

Each entry represents one bookable "block" — a specific combination of a room type, a cancellation/refund policy, and a meal plan. A single room type can appear multiple times (for example, refundable vs non-refundable).

  • block_id — unique identifier for this bookable option.
  • room_id — links this rate to an entry in data.rooms[].
  • name — full rate name, e.g. "Laguna Twin Room - Non-refundable".
  • room_name — the room-type name without the policy suffix.
  • max_occupancy, nr_adults, nr_children.
  • refundable, refundable_until — cancellation policy.
  • breakfast_included, half_board, full_board, all_inclusive, mealplan — meal configuration.
  • room_count_available — how many rooms of this type Booking.com will sell for the requested dates. It is bounded by the property’s allotment on Booking.com, not its physical inventory, and is typically identical across rate blocks sharing the same room_id, so do not sum it across rate blocks. Use data.availability_summary.total_available_rooms for a deduplicated total, and compare values only within one property across dates.
  • genius_discount_percentage — Booking.com Genius loyalty discount if applicable.
  • price — object with total, per_night, currency, formatted, plus before_discount (Booking.com's struck-through price, e.g. "$642") and discount_name (e.g. "Bonus savings") when the property offers a discount, otherwise null. Booking.com occasionally returns a rate without the discount, so a higher price with a null before_discount is an undiscounted quote.

Usage Tips

Static vs. dynamic data

rooms[] changes rarely (new photos, re-categorisation) — safe to cache for hours or days. rates[] is dynamic (availability, pricing) — refresh per user query.

Best Practices

  • Join rates[].room_id back to rooms[].id to display photos and facilities next to each bookable rate.
  • The hotel name is not returned here — call /v1/booking/hotel/details if you need it.
  • Empty rooms and rates arrays with a 200 status mean the property has no availability for the requested dates — try different dates rather than retrying.
  • If you only have a URL, call /v1/booking/hotel/url-to-id once and cache the resulting hotel_id.
  • For a currency other than USD, always pass the currency parameter — hotel_info.currency_code reflects the hotel's native currency, not the price display currency.

Error handling and status codes

Status codes: 200 on success; errors use non-2xx responses with RFC 7807 Problem Details.

  • 422: Missing or invalid hotel_id (not a positive integer).
  • 404 NOT_FOUND: Upstream reports the hotel does not exist.
  • 502 UPSTREAM_ERROR: Upstream non-2xx or protocol error.
  • 503 SERVICE_UNAVAILABLE: Upstream WAF challenge or maintenance.
  • 504 GATEWAY_TIMEOUT: Upstream response timed out.
  • 500 INTERNAL_ERROR: Unexpected processing error.

Error responses (Problem Details)

All Booking.com hotel endpoints return errors using RFC 7807 Problem Details.

{
  "type": "https://api.stayapi.com/errors/invalid-url",
  "title": "Invalid URL",
  "status": 400,
  "detail": "Parameter 'url' must be a full Booking.com hotel URL of the form https://www.booking.com/hotel/{cc}/{slug}.html.",
  "error_code": "INVALID_URL",
  "provided": "baan-coconut"
}

Media type: application/problem+json

Standard fields: type, title, status, detail

Extensions: error_code and any endpoint-specific fields

2xx policy: 2xx is returned only when data extraction succeeds.

Request
curl -X GET "https://api.stayapi.com/v1/booking/hotel/rooms?hotel_id=346648&checkin=2026-05-05&checkout=2026-05-06&adults=2" \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "success": true,
  "url": "hotel_id:346648",
  "data": {
    "hotel_info": {
      "id": "346648",
      "currency_code": "THB"
    },
    "rooms": [
      {
        "id": "34664813",
        "name": "One-bedroom Loft Suite",
        "description": "Offering double-height ceilings, the split-level loft overlooks the lagoon. It features a coffee machine, safe and flat-screen TV.",
        "ai_description": "<b>Double the size</b> with <b>outdoor furniture</b>, <b>patio</b>, and a <b>walk-in shower</b>.",
        "room_size_m2": 88,
        "room_size_ft2": 947.22,
        "is_smoking": false,
        "is_dormitory": false,
        "bathroom_count": 1,
        "private_bathroom": true,
        "photos": [
          {
            "id": 263386204,
            "url_original": "https://cf.bstatic.com/xdata/images/hotel/max500/263386204.jpg?k=...",
            "url_max300":  "https://cf.bstatic.com/xdata/images/hotel/max300/263386204.jpg?k=...",
            "url_square60":"https://cf.bstatic.com/xdata/images/hotel/square60/263386204.jpg?k=...",
            "url_640x200": "https://cf.bstatic.com/xdata/images/hotel/640x200/263386204.jpg?k=...",
            "ratio": 1.5
          }
        ],
        "bed_configurations": [
          {
            "beds": [
              { "bed_type": 6, "name": "Queen bed(s)", "name_with_count": "1 queen bed", "count": 1, "description": "151-180 cm wide", "description_imperial": "60-70 inches wide" }
            ]
          }
        ],
        "facilities": [
          { "id": 19,  "name": "Bathrobe",       "category": "Bathroom", "category_id": 5 },
          { "id": 120, "name": "Coffee machine", "category": "Kitchen",  "category_id": 12 }
        ],
        "highlights": [
          { "id": null, "name": "Free WiFi",        "icon": "bui_wifi" },
          { "id": 11,   "name": "Air conditioning", "icon": "bui_weather_snowflake" }
        ]
      }
    ],
    "rates": [
      {
        "block_id": "34664883_88879319_2_2_0_600415",
        "room_id": "34664883",
        "name": "Laguna Twin Room - Non-refundable",
        "room_name": "Laguna Twin Room",
        "max_occupancy": 2,
        "nr_adults": 2,
        "nr_children": 0,
        "refundable": false,
        "refundable_until": null,
        "breakfast_included": false,
        "half_board": false,
        "full_board": false,
        "all_inclusive": false,
        "mealplan": "Continental breakfast costs US$28 per person per night.",
        "room_count_available": 20,
        "genius_discount_percentage": 0,
        "price": {
          "total": 137.56,
          "per_night": 137.56,
          "currency": "USD",
          "formatted": "US$138",
          "before_discount": null,
          "discount_name": null
        }
      }
    ],
    "availability_summary": {
      "availability_status": "available",
      "total_available_rooms": 20,
      "available_rate_blocks": 1,
      "available_room_types_counted": 1,
      "room_counts_by_room_id": { "34664883": 20 },
      "rates_without_room_count_available": 0,
      "calculation_method": "sum(max(room_count_available) grouped by room_id across bookable rate blocks)"
    },
    "search_config": {
      "nbRooms": 1,
      "nbAdults": 2,
      "nbChildren": 0,
      "childrenAges": [],
      "checkin": "2026-05-05",
      "checkout": "2026-05-06"
    },
    "metadata": {
      "hotel_id": "346648",
      "total_rooms": 6,
      "total_blocks": 24,
      "arrival_date": "2026-05-05",
      "departure_date": "2026-05-06",
      "scraped_at": "2026-04-21T11:06:59Z"
    }
  },
  "message": "Successfully retrieved room details",
  "retrieved_at": "2026-04-21T11:06:59Z"
}