Airbnb Search API — Listings and Prices by Location
Documentation menu
FetchLayer FetchLayer API

Search listings by location

Search Airbnb listings for a place. `location` is the only required field — a place name like "Lisbon, Portugal" or "Austin, TX" — and every result comes back with its price, rating, badges, coordinates and photos. **Dates are optional, and the two routes that take them behave differently on purpose.** `/search-listings` **always prices**: with no dates it prices every result for the source's own default stay window and reports that window back on `checkIn`/`checkOut` plus a note. `/listing-detail` **does not**: with no dates `listing.price` is **`null`** and a note says to pass `checkIn` and `checkOut` to price a stay. A search has to price to be a search; a detail read will not invent a stay you did not ask about. Read one route's behaviour onto the other and a `null` price looks like a broken listing when it is the documented answer. `price` is a structured object, not a number: `{total, perNight, nights, taxesAndFees, originalTotal, qualifier, note}`, where `total`, `perNight`, `taxesAndFees` and `originalTotal` are each `{amount, currency, formatted}`. `originalTotal` above `total` means a discount is applied — a measured example is `originalTotal: {amount: 1083.09}` against `total: {amount: 940.47}`. `taxesAndFees` is broken out rather than folded into the total, and `nights` is the stay length the figures cover. Any of the money fields can be `null` when the source did not publish it. **Dates here price a stay; they are not a calendar.** A stay that cannot be priced returns `price: null` with a note that it may be unavailable for those dates — which tells you about those dates and nothing else. For which nights are open, use [`/listing-availability`](/documentation/airbnb/endpoints/listing-availability), which returns the calendar night by night. Billing: 1 credit per page fetched, reported as `pagesFetched`. A page is up to 18 listings and costs the same whether it comes back full or half empty. Measured on 17 September 2026: `{"location":"Lisbon, Portugal"}` returned 200 in 1.6-1.9s across three runs, with 18 listings each time.

POST /search-listings Listings
https://api.fetchlayer.dev/airbnb/search-listings
OpenAPI JSON

Headers

Authorization string required

Bearer token — your FetchLayer API key.

Parameters

location string required

A place name, e.g. "Austin, TX" or "Lisbon, Portugal". The only required field.

checkIn string optional

Stay start date, YYYY-MM-DD. Optional — without it, results are priced for the source's own default stay window, which comes back on `checkIn` in the response. Must be given together with `checkOut`: one without the other is a 400 saying "checkIn and checkOut must be given together".

checkOut string optional

Stay end date, YYYY-MM-DD. Required if `checkIn` is given, and vice versa.

adults integer optional

Adult guests, up to 50. Omitted means the source's own default, and the response echoes null rather than pretending to a number.

children integer optional

Children, up to 50.

infants integer optional

Infants, up to 50.

pets integer optional

Pets, up to 50.

pages integer optional

How many pages of results to walk in one request, up to 15. Each page is up to 18 listings and 1 credit. Pass -1 for the maximum. (default: 1)

cursor string optional

Continue from a previous response's `nextCursor`.

format string optional

Envelope format: json or markdown. (default: json)

Response Fields

search-listings

Search listings by location

transport string

The source. "airbnb".

notes string[]

Caveats and completeness statements you can act on, in plain words. On /listing-reviews this is where the "10 of the 52" line lives; on the priced routes it is where the stay window used for pricing is stated; on /listing-availability it is where the booking-window warning lives — read it before reading a run of closed nights as a closure.

pagesFetched number

Pages read, and what the request is billed at: 1 credit per page. A page costs the same whether it comes back full or half empty. /resolve-url reports 0 and is free.

query string

The location that was searched, echoed back.

listingCount number

How many listings came back in this response.

hasMore boolean

Whether the source has further results beyond this page.

nextCursor string

Pass back as `cursor` to continue. Null when there is nothing more.

checkIn string

**The stay window the prices are actually for.** Your dates when you gave them; the source's own default window when you did not — so a price is never silently for dates you did not ask about. Read this before comparing prices across requests.

checkOut string

The other end of that window, on the same terms.

adults number

The guest count the prices are for, or null when you passed none and the source used its own default.

children number

As `adults`.

infants number

As `adults`.

pets number

As `adults`.

listings[].id string

The listing's numeric id. Hand it straight to /listing-detail or /listing-reviews as `listing`.

listings[].url string

The listing's airbnb.com/rooms/… address.

listings[].name string

The row's headline as published, e.g. "Apartment in Santa Maria Maior" or a hotel name.

listings[].roomName string

The specific room on a listing that has one, e.g. "Casa Teva Lisboa Hotel, Deluxe double room". Null on an ordinary whole-home listing.

listings[].coordinates object

`{latitude, longitude}` — approximate on search, as the source publishes them.

listings[].rating object

`{average, count}` — the aggregate score and how many reviews it rests on. The per-category breakdown is on /listing-detail.

listings[].badges string[]

The source's own labels on the row. Measured values include "Guest favorite", "Superhost" and "Featured hotel".

listings[].photos string[]

Photo URLs for the row — six per listing in the searches measured.

listings[].price object

`price` is a structured object, not a number: `{total, perNight, nights, taxesAndFees, originalTotal, qualifier, note}`, where `total`, `perNight`, `taxesAndFees` and `originalTotal` are each `{amount, currency, formatted}`. `originalTotal` above `total` means a discount is applied — a measured example is `originalTotal: {amount: 1083.09}` against `total: {amount: 940.47}`. `taxesAndFees` is broken out rather than folded into the total, and `nights` is the stay length the figures cover. Any of the money fields can be `null` when the source did not publish it.

listings[].price.total object

`{amount, currency, formatted}` — the whole stay, e.g. `{amount: 1245, currency: "USD", formatted: "$1,245"}`.

listings[].price.perNight object

`{amount, currency, formatted}` — the per-night figure, e.g. `{amount: 301.93, currency: "USD", formatted: "$301.93"}`.

listings[].price.nights number

How many nights the figures cover.

listings[].price.taxesAndFees object

`{amount, currency, formatted}`, broken out rather than folded into `total`. Null when the source published no separate figure.

listings[].price.originalTotal object

The pre-discount total when one is published, in the same money shape. Above `total` means a discount is applied; null means there is none to report. Measured: `{amount: 1083.09}` against a `total` of `{amount: 940.47}`.

listings[].price.qualifier string

What the figures are qualified as, in the source's own words — "total" or "for 4 nights".

listings[].price.note string

Whatever the source printed alongside the price, verbatim, e.g. "Pay $0 today with no extra fees." or the room name on a hotel row. Null when there was none.

Request

curl -X POST "https://api.fetchlayer.dev/airbnb/search-listings" \
  -H "Authorization: Bearer ss-your-key" \
  -H "Content-Type: application/json" \
  -d '{"location":"Lisbon, Portugal"}'

Response

{
  "transport": "airbnb",
  "notes": [
    "More results are available. Continue with nextCursor.",
    "No check-in/check-out was given, so each listing's price reflects the source's own default stay (2026-10-16 to 2026-10-21), not necessarily the dates you want. Pass checkIn and checkOut to price a specific stay."
  ],
  "pagesFetched": 1,
  "query": "Lisbon, Portugal",
  "listingCount": 18,
  "hasMore": true,
  "nextCursor": "eyJzZWN0aW9uX29mZnNldCI6MCwiaXRlbXNfb2Zmc2V0IjoxOCwidmVyc2lvbiI6MX0=",
  "checkIn": "2026-10-16",
  "checkOut": "2026-10-21",
  "adults": null,
  "children": null,
  "infants": null,
  "pets": null,
  "listings": [
    {
      "id": "33579922",
      "url": "https://www.airbnb.com/rooms/33579922",
      "name": "Apartment in Santa Maria Maior",
      "roomName": null,
      "coordinates": {
        "latitude": 38.7132,
        "longitude": -9.14376
      },
      "rating": {
        "average": 4.95,
        "count": 465
      },
      "badges": [
        "Guest favorite"
      ],
      "photos": [
        "https://a0.muscache.com/im/pictures/6ae6f001-a512-474b-96ce-bd7852242a3e.jpg"
      ],
      "price": {
        "total": {
          "amount": 1245,
          "currency": "USD",
          "formatted": "$1,245"
        },
        "originalTotal": null,
        "perNight": {
          "amount": 301.93,
          "currency": "USD",
          "formatted": "$301.93"
        },
        "nights": 4,
        "taxesAndFees": {
          "amount": 36.7,
          "currency": "USD",
          "formatted": "$36.70"
        },
        "qualifier": "total",
        "note": "Pay $0 today with no extra fees."
      }
    }
  ]
}