Hotel details gives you one score for the property. Reviews are the comments behind that score. You already have a hotel_id from search or from details. This call pages guest text, a score on each comment, and the category breakdown for the hotel. Filters narrow the page. They do not change which hotel you are reading.
👉 To access this endpoint, you must obtain an API key: https://steadyapi.com/register
Authentication
Every call uses a Bearer token from your SteadyAPI dashboard.
Documentation:
https://docs.steadyapi.com/#authenticating-requests
headers = {
'Authorization': 'Bearer YOUR_API_KEY'
}
Where this fits
Resolve a place with GET /v1/booking/hotels/autocomplete, search with GET /v1/booking/hotels/search-by-coordinates, then take hotel_id. Details, GET /v1/booking/hotels/details, is optional before reviews. You only need the id. The next page of comments is the same reviews endpoint with a larger skip. Rooms and availability are separate calls. They do not take a review id.
Reviews for a hotel
Endpoint: GET /v1/booking/hotels/reviews
Documentation:
https://docs.steadyapi.com/#bookingcom-GETapi-v1-booking-hotels-reviews
Parameters
hotel_id— required property idlanguage— optional, defaulten-ussort— optional:NEWEST_FIRST(default),MOST_RELEVANT,HIGHEST_SCORE_FIRST, orLOWEST_SCORE_FIRSTskip— optional offset, default 0limit— optional page size, default 10, max 50text— optional text filterscore— optional:1,2,3,4, or5topic— optional topic key, such asclean,room, orbreakfastguest_type— optional:FAMILY,COUPLE,SOLO,BUSINESS, orFRIENDS
sort changes the order. skip and limit change the page. score, topic, guest_type, and text drop comments that do not match. score is a filter from 1 to 5. It is not the same number as score.overall on a review, which is the guest’s rating on the comment itself. Send only the four sort values listed above. Other labels that appear inside a response are not accepted as the sort query parameter.
Python
import requests
url = "https://api.steadyapi.com/v1/booking/hotels/reviews"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
params = {"hotel_id": hotel["hotel_id"], "sort": "NEWEST_FIRST", "limit": 10}
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
payload = response.json()
body = payload.get("body", {})
print(body.get("stats", {}).get("average_score"))
for review in body.get("reviews", [])[:5]:
print(review.get("score", {}).get("overall"), review.get("text", {}).get("positive"))
Annotated sample
{
"guest": { "username": "Scott", "country": { "name": "United States" }, "guest_type": "Solo traveler" },
"text": {
"positive": "An Amazing bed, great shower, great bathroom, plenty of room.",
"negative": "The landscape needs a little help."
},
"score": { "overall": 9 },
"dates": { "reviewed": 1767242551 },
"booking": { "nights": 1, "stay_dates": { "checkin": "2025-11-08", "checkout": "2025-11-09" } }
}
Store the review id if you are paging into a database, plus text.positive, text.negative, and score.overall. guest.username and guest.country.name are the byline. booking.nights and booking.stay_dates say how long the guest stayed. dates.reviewed is a timestamp. body.summary is the category list for the hotel, with category, translation, and score. That summary is not one guest’s comment.
Practical use
Start at skip=0. When meta.pagination.has_more is true, call again with skip set to meta.pagination.next_skip. limit above 50 is rejected. meta.total_reviews is the count for the filter you sent, not a promise that every comment is in this page.
Do not treat query score=5 as “overall rating 5.” The filter is a 1–5 bucket. The number on the comment, score.overall, uses the hotel’s review scale. In the sample that overall value is 9.
A topic such as breakfast or room is a hint the API already knows. An unknown topic string is still accepted by validation, and it can return an empty page. If the page is empty, drop the topic and read body.summary for category names that exist on that hotel.
👉 Get your API key and read reviews: https://steadyapi.com/register