Airbnb Listings Data API: Search, Details and Reviews
You can get Airbnb listings as JSON with three GET endpoints: /v1/airbnb/search for a place and dates, /v1/airbnb/listing for one listing, and /v1/airbnb/reviews for its reviews. Each successful call costs 1 credit, and you authenticate with one X-API-Key header. This guide shows the search request, a recorded response, the parameters of all three endpoints and what a market snapshot costs.
Can you get Airbnb listings from the official API?
Usually not. Airbnb's API terms say participation in an API Program requires signing Airbnb's standard mutual nondisclosure agreement, agreeing to the API Terms and completing a data security review, and that Airbnb decides which Scopes (sets of access permissions) an organization gets (Airbnb Help Center, API Terms, 2026). Airbnb's developer portal is aimed at building and integrating with the Airbnb platform. If you manage listings through a connectivity partner, that route is the right one. If you want to search a market, compare prices or read reviews across listings you don't manage, you need a data API instead.
The Airbnb API on Perceptlayer covers that second case. Data is collected from publicly available sources and returned as found at the time of the call.
How do you search Airbnb listings by place and dates?
Call GET /v1/airbnb/search with a place and, for stay prices, checkin, checkout and adults. Only place is required. The request below searches Paris for two adults over four nights in November 2026 and asks for prices in euros. Get a key on the free sign-up page and export it as API_KEY; the authentication docs cover the query-parameter alternative.
curl "https://api.perceptlayer.com/v1/airbnb/search?place=Paris--France&checkin=2026-11-10&checkout=2026-11-14&adults=2¤cy=EUR" \
-H "X-API-Key: $API_KEY"
The place value in this request is Paris--France, and the response echoes it back as "place": "Paris, France". The same call can be run with your key in the playground on the Search endpoint page.
What does the search response contain?
The recorded response below is real output from this exact request, trimmed with …. Each item in data.results is one listing. The first carries a rating and review_count; the second has neither, so treat both as optional when you parse.
{
"success": true,
"data": {
"place": "Paris, France",
"results": [
{
"id": "1669612146929039736",
"url": "https://www.airbnb.com/rooms/1669612146929039736",
"title": "Apartment in Paris",
"name": "Stylish 1-Bedroom/2-Person Apartment – Beaugrenelle",
"subtitle": "Bright 6th-floor stay near the Eiffel Tower, with a balcony and a private entrance",
"rating": 5,
"review_count": 17,
"price": {
"amount": 714,
"currency": "EUR",
"nights": 4,
"qualifier": "for 4 nights"
},
"price_breakdown": [
{
"description": "4 nights x €178.34",
"amount": 713.37
}
],
"bedrooms": 1,
"beds": 1,
"bathrooms": 1,
"latitude": 48.84223,
"longitude": 2.29241,
"badges": [
"Guest favorite"
],
"images": [
"https://a0.muscache.com/im/pictures/hosting/Hosting-1669612146929039736/original/053b1768-c702-49bf-9b31-d0b00b51260b.jpeg",
…
]
},
…
],
"has_more": true,
"next_cursor": "eyJzZWN0aW9uX29mZnNldCI6MCwiaXRlbXNfb2Zmc2V0IjoxOCwidmVyc2lvbiI6MX0="
},
"meta": {
"endpoint_family": "stay_search",
"billable": true
}
}
The fields that matter for most jobs are in the table below. All of them appear in the recorded response above.
| Field | What it holds |
|---|---|
id, url |
The listing ID and its page URL |
name, title, subtitle |
Listing name, property type and city, and the short description |
rating, review_count |
Average rating and number of reviews; absent on the second listing in the sample |
price.amount, price.currency, price.nights |
The total for the stay in the currency you requested |
price_breakdown |
A list of lines, each with a description such as 4 nights x €178.34 and an amount (713.37 in the first listing) |
bedrooms, beds, bathrooms |
Counts as numbers |
latitude, longitude |
Coordinates for mapping or distance work |
badges, images |
Labels such as Guest favorite, and photo URLs |
Note that price.amount is the stay total, shown as 714 for 4 nights. In the first listing the price_breakdown amount is 713.37, also the stay total, and the nightly rate (€178.34) appears only inside the description string. Because price.amount is rounded, dividing it by price.nights gives 178.5, not 178.34. If you need the exact nightly rate, read it from the description text.
Which parameters does the search endpoint take?
Search takes one required parameter, place, and ten optional ones for dates, guests, currency, price ceiling and room type. Only the types, the 100-character limit on place, the 200-character limit on cursor and the three room_type values are documented, so test other values in the playground before relying on them.
| Parameter | Type | Required | Notes |
|---|---|---|---|
place |
string | yes | Up to 100 characters |
checkin, checkout |
string | no | The example uses 2026-11-10 style dates |
adults, children, infants, pets |
integer | no | Guest counts |
currency |
string | no | The example uses EUR |
price_max |
integer | no | Price ceiling |
room_type |
string | no | One of entire_home, private_room, hotel_room |
cursor |
string | no | Up to 200 characters; for continuing a search |
How do you fetch one listing and its reviews?
Pass the id from a search result as listing_id to GET /v1/airbnb/listing for the listing itself and to GET /v1/airbnb/reviews for its reviews. Each call is 1 credit. We have no recorded response for either endpoint, so this section shows the requests only and doesn't list their response fields. For the fields each one returns, and to run a real call with your key, open the Listing endpoint page and the Reviews endpoint page.
The listing endpoint accepts checkin, checkout and adults in addition to listing_id, so you can ask about a specific stay.
curl "https://api.perceptlayer.com/v1/airbnb/listing?listing_id=1669612146929039736&checkin=2026-11-10&checkout=2026-11-14&adults=2" \
-H "X-API-Key: $API_KEY"
The reviews endpoint takes limit and offset, which is how you page through a listing's reviews. Both are integers, and the documentation gives no default or maximum, so set limit explicitly.
curl "https://api.perceptlayer.com/v1/airbnb/reviews?listing_id=1669612146929039736&limit=20&offset=0" \
-H "X-API-Key: $API_KEY"
| Endpoint | Required | Optional | Credits |
|---|---|---|---|
/v1/airbnb/listing |
listing_id |
checkin, checkout, adults |
1 |
/v1/airbnb/reviews |
listing_id |
limit, offset |
1 |
/v1/airbnb/search |
place |
checkin, checkout, adults, children, infants, pets, currency, price_max, room_type, cursor |
1 |
How do you run the search from code?
The script below runs the search and prints name, price and rating for each result. It uses .get() for rating, price and name because the recorded excerpt shows only two listings, and one of them has no rating, so any field may be missing on others. We have no recorded run of this script, so try it on a single search before you build on it.
import os
import requests
resp = requests.get(
"https://api.perceptlayer.com/v1/airbnb/search",
params={
"place": "Paris--France",
"checkin": "2026-11-10",
"checkout": "2026-11-14",
"adults": 2,
"currency": "EUR",
},
headers={"X-API-Key": os.environ["API_KEY"]},
timeout=30,
)
resp.raise_for_status()
for item in resp.json()["data"]["results"]:
price = item.get("price") or {}
name = (item.get("name") or "").strip()
print(item.get("id"), name, price.get("amount"), price.get("currency"), item.get("rating"))
Errors come back as an HTTP status with a JSON body of {"error": {"code", "message", "request_id"}}. Handle rate_limited (429) by backing off, and insufficient_credits (402) by stopping, since nothing is debited and there is no automatic top-up. The errors docs list every code and the rate limit docs cover the rest.
What does a market snapshot cost in credits?
A snapshot costs one credit per call, so the total is search calls plus listing calls plus review calls. Failed calls return X-Credits-Used: 0 and cost nothing, and each successful response reports X-Credits-Remaining so your job can watch the balance. The credits docs explain both headers.
As an example, not a measured plan, say you want a neighbourhood snapshot: 20 search calls to collect candidates (each page's next_cursor goes back as cursor for the next one), then the listing detail and the first page of reviews for 300 of them.
| Step | Calls | Credits |
|---|---|---|
| Search | 20 | 20 |
| Listing detail | 300 | 300 |
| Reviews, one page each | 300 | 300 |
| Total | 620 | 620 |
620 credits fit inside the 1,000 free credits you get every month after verifying an email address, with no credit card. Beyond the free tier, credits come in prepaid packs starting at 10,000 credits (the Starter pack), so one 620-call snapshot is 620 × 1 credit = 620 credits, a small fraction of it. See pricing for what credits cost. The 20-search figure is an assumed budget, not a measured page count; run your own search and count data.results before you plan around it.
Price changes with dates, so rerun the same search on a schedule if you want a time series. Each rerun costs the same credits.
If an agent will make these calls, the MCP docs show how to expose them as tools, and the credits docs show how to track spend. For a comparable listings guide, see Zillow listings as JSON, or browse all API guides and the travel APIs.
Next step: get a free API key, then run the search above in the playground on the Airbnb API page.
APIs in this post
Frequently asked questions
Does Airbnb have a public API for listings and reviews?
Airbnb's API terms describe access through API Programs, which require signed agreements and a data security review, with Airbnb deciding which Scopes an organization receives (Airbnb Help Center, API Terms, 2026). That is built for partners managing their own listings. For searching and reading listings you don't manage, use a data API like the three endpoints above.
How much does one Airbnb API call cost?
Each successful call to search, listing or reviews costs 1 credit. Failed calls cost nothing and return X-Credits-Used: 0. Every account gets 1,000 free credits a month after email verification. Paid packs start at 10,000 credits, so 10,000 calls × 1 credit = 10,000 credits, and purchased credits last 12 months. See pricing for what credits cost.
How do I page through results and reviews?
For reviews, use limit and offset; both are integers. For search, the recorded response ends data with has_more and next_cursor: pass next_cursor back as the cursor parameter (a string of up to 200 characters) to get the next page, and stop when has_more is false. No defaults or page sizes are documented, so set limit explicitly for reviews.
What happens if my credits run out mid-job?
The next call returns insufficient_credits with HTTP status 402, and nothing is debited. The service is prepaid with no automatic top-up, so your job stops cleanly. Read X-Credits-Remaining on each response to stop early or alert before the balance reaches zero.
How fresh is the data?
Data is collected from publicly available sources and returned as found at the time of the call. Nothing here promises completeness or accuracy beyond that, so treat a stored snapshot as a record of one moment.
Should I build an Airbnb scraper instead?
An Airbnb scraper has to render JavaScript-heavy pages, keep up with markup changes and respect Airbnb's terms, and you maintain all of it. The search, listing and reviews endpoints return price, rating, beds and coordinates as JSON for 1 credit per successful call. Build your own only for fields these endpoints don't return.