Hotel rates API: every room price for one hotel by name
Published September 5, 2026 · Updated October 6, 2026
Short answer: FlightPowers' hotels API returns live Booking.com rates for one property
by the name a person would type. POST /v1/hotels/by-name gives the headline rate plus
matched_name, so you can check what the name resolved to; resolve then rooms lists
every room type with its own price. PRO is $10 for
2,000 searches. It is a hotel data API, not a
booking engine.
Most hotel APIs want an ID before they answer anything. So the first thing you build is not the feature, it is a mapping layer: a property catalogue, a sync job to keep it fresh, and a fuzzy matcher for the day someone types "the Hilton by the airport". That is a week of work between you and one price. This page skips it, twice: once for the headline rate, once for the whole room list. Every response below was fetched on 2026-10-06 for a three-night stay in Rome, 18 to 21 November 2026, two adults, in euros.
What is an API in hotels?
A hotel API is an endpoint your code calls to get hotel data back as JSON, usually room rates and availability for a property and a pair of dates; this one reads live Booking.com prices and does not take bookings.
How do you get the rate for one hotel by name?
curl -X POST "https://api.flightpowers.com/v1/hotels/by-name" \
-H "Content-Type: application/json" \
-H "x-api-key: $RAPIDAPI_KEY" \
-d '{
"hotel_name": "Suite della Pigna",
"area": "Rome",
"checkin_date": "2026-11-18",
"checkout_date": "2026-11-21",
"adults": 2,
"currency": "EUR"
}'
Required: hotel_name, checkin_date, checkout_date. Optional: adults, children,
currency, proxy_country, free_cancellation, and area when the name is generic. With
area set, the search runs as "name, area" while the matching still uses only the name you
gave. The same endpoint is POST /hotel_by_name on booking-live-api.p.rapidapi.com with
the usual x-rapidapi-key and x-rapidapi-host headers.
The answer, as it came back (the two long URLs are cut at the ? for width):
{
"name": "Suite della Pigna",
"matched_name": "Suite della Pigna",
"match_confidence": 1,
"matched_via": "name",
"available": true,
"price_string": "€497",
"price": 497,
"review_score": 9.1,
"review_count": 666,
"room_type": "Premium",
"image_url": "https://cf.bstatic.com/xdata/images/hotel/square240/275308633.webp",
"link": "https://www.booking.com/hotel/it/amazing-rooms-piazza-venezia.html",
"nights": 3,
"adults": 2,
"children": null,
"latitude": 41.897104,
"longitude": 12.482208,
"retrieved_at": "2026-10-06T19:50:07.901Z"
}
What to read, in order:
matched_nameis the property the text actually resolved to. Compare it with what you asked for before you trust the number. If a user types a name that lands on a hotel two streets away, you find out here instead of in a support ticket.priceis the total for the stay in the currency you asked for, not a nightly rate.nightsis there so you can divide: €497 over three nights is about €166 a night.price_stringis the same number formatted for display.room_typesays which room the headline belongs to. Here it is the Premium room, which turned out to be the cheapest room the property had for those dates (see the room list below).linkopens the property on Booking.com with your dates filled in;latitude/longitudeput it on a map;retrieved_atis when the rate was read, which is the timestamp to store next to the price.
What does a sold-out or unknown hotel look like?
Two more real answers from the same session, because they are the ones that break code.
A hotel that exists but has nothing for your dates. Duplo Charme Boutique Hotel in Lisbon,
same dates (image_url, link, adults and children left out for width; the last two were
null):
{
"name": "Duplo Charme Boutique Hotel",
"matched_name": "Duplo Charme Boutique Hotel",
"available": false,
"price_string": null,
"price": null,
"review_score": 8.2,
"review_count": 3877,
"room_type": null,
"nights": null,
"latitude": 38.728339,
"longitude": -9.137404,
"retrieved_at": "2026-10-06T19:49:34.501Z",
"match_confidence": 1,
"matched_via": "name"
}
And a name that did not resolve at all. I sent "Hotel Sant Angelo" with "area": "Rome"
and got matched_name: null, available: false, and every other field null except
name and retrieved_at.
The difference matters. Sold out has a matched_name, a review score and a position: the
hotel is real, it just has no room for you. Unresolved has none of them: the name is the
problem, so fix the name, add an area, or show the user what you searched for. Neither one
is an error, so neither belongs on your error path, and neither may be stored as a price of
zero.
How do you get every room rate for one hotel?
The headline rate is one room. That is the right answer to "what does this hotel cost". It is the wrong answer for a comp-set tracker or a rate check, where the interesting movement is a suite going on sale while the cheapest room sits still. For that you want the room list, and it is two calls the first time and one call after.
Step one, once per property: resolve the name.
curl -X POST "https://api.flightpowers.com/v1/hotels/resolve" \
-H "Content-Type: application/json" \
-H "x-api-key: $RAPIDAPI_KEY" \
-d '{"hotel_name": "Suite della Pigna Rome"}'
{
"hotel_name": "Suite della Pigna Rome",
"hotel_booking_id": "it/amazing-rooms-piazza-venezia",
"matched_name": "Suite della Pigna",
"retrieved_at": "2026-10-06T19:50:20.632Z"
}
Look at the ID: Booking.com files Suite della Pigna under amazing-rooms-piazza-venezia.
You would never guess that from the name, which is the whole case for resolving by name
instead of building the ID yourself.
Step two, on every check: the rooms. Send the ID with your dates. The optional fields are the same as above.
curl -X POST "https://api.flightpowers.com/v1/hotels/rooms" \
-H "Content-Type: application/json" \
-H "x-api-key: $RAPIDAPI_KEY" \
-d '{
"hotel_booking_id": "it/amazing-rooms-piazza-venezia",
"checkin_date": "2026-11-18",
"checkout_date": "2026-11-21",
"adults": 2,
"currency": "EUR"
}'
The answer carries the ID, your dates, a booking_url, and a rooms array. One entry looks
like this:
{
"room_type": "Premium",
"room_economy": "Non-refundable",
"guests": null,
"price_as_number": 497,
"price": "€ 497",
"retrieved_at": "2026-10-06T19:50:33.178Z"
}
All eight entries from that response, in the order they came back:
| Room | Rate plan (room_economy) | Total for 3 nights |
|---|---|---|
| Premium | Non-refundable | €497 |
| Deluxe Room | Non-refundable | €562 |
| Deluxe Room | Non-refundable | €621 |
| Deluxe Room | Free cancellation before November 13, 2026 | €685 |
| Loft - Separate Building | Non-refundable | €765 |
| Loft - Separate Building | Free cancellation before November 13, 2026 | €845 |
| Suite with Balcony | Non-refundable | €954 |
| Suite with Balcony | Free cancellation before November 13, 2026 | €1,055 |
Three things this table shows that the headline rate cannot. The same property sold stays from €497 to €1,055 on the same dates, so "the price of this hotel" is a range, not a number. Free cancellation cost €80 more on the Loft and €101 more on the Suite. And the headline from the by-name call, €497 for the Premium room, is the first row here: the two calls agreed.
price_as_number is the total for the whole stay, not a nightly rate. room_economy is the
free-text line Booking.com prints next to the room, which is where breakfast and
cancellation terms live, so treat it as a label, not a structured field. guests came back
null on every row in this run, so do not key anything on it. And note that price on this
endpoint is formatted € 497 with a non-breaking space while the by-name call printed
€497: compare the numbers, never the strings.
The rule that saves you a plan tier
Resolve once, cache the ID, then never resolve again. A tracker watching 50 properties a day that resolves each name on every run makes 50 avoidable requests a day. The ID is the Booking.com path for the property and it changes about as often as a hotel renames itself. Cache the ID, never the rate.
What should you handle?
available can be false, and a name can fail to resolve. Both are normal answers, as
shown above. Branch on them before you read price.
Generic names need an area. Read matched_name every time. If your product lets users
type free text, show them the matched name in the interface.
Rates are live, so they are perishable. Every call reads Booking.com at request time, which is why the number is real. It is also why caching it for a day turns a real price into a wrong one.
One stay per call. Both endpoints take one property and one date pair. There is no date range here, so pricing a week of check-in dates is a request per date.
Room lists move faster than properties. A property can be bookable while the room you track is not, so key your history on the room type and the rate plan, and expect gaps rather than reading a missing row as a price drop.
What does it cost?
Each call above is one request on your plan: a by-name lookup is one, a resolve is one, a rooms call is one. BASIC is 10 requests a month with no card, enough to resolve a property and pull its rooms a few times. PRO is $10 for 2,000, ULTRA $30 for 6,500. Keys come from the RapidAPI listing, and the current numbers always live on /pricing.
Type the name, get the rate
Live Booking.com rates with no property ID and no catalogue to sync, plus matched_name so you can verify the match. Free tier, no card.
Free tier: 10 requests/month. No card to try.
Docs: the Flights API and the MCP servers.
Related
- Hotel by Name API: the product page with the field reference
- Do hotel prices change by country?:
proxy_country, sampled three times per market on this same hotel - How to monitor hotel rate parity: the scheduled version
- Hotel comp-set tracking: what the room list is usually built for
- The best hotel data APIs in 2026: the wider field, prices quoted and dated