Immobilienscout24 API: German Property Listings as JSON
To get ImmobilienScout24 listings as JSON, call GET /v1/immobilienscout24/search with a location and an optional type such as apartment-rent. It returns listings with price, rooms, size in square metres, address, coordinates and a link to the original exposé. Each call costs 1 credit, and a failed call costs nothing. Three more endpoints, Locations, Property and Price Insights, are listed below with their parameters and cost. Only search has a recorded response in this article.
Which ImmobilienScout24 endpoints are there?
The ImmobilienScout24 API has four endpoints, all GET, all 1 credit per successful call. The endpoints are Locations, Search, Property and Price Insights. This article has a recorded response for Search only, so it covers that endpoint in depth and the other three briefly. The API sits in the real estate area of the catalogue, which has 248 websites and 1,659 endpoints in total.
| Endpoint | Returns | Required | Optional | Credits |
|---|---|---|---|---|
/v1/immobilienscout24/locations |
Locations | query |
limit |
1 |
/v1/immobilienscout24/search |
Search | location |
type, price_min, price_max, rooms_min, rooms_max, size_min, size_max, page, per_page |
1 |
/v1/immobilienscout24/property |
Property | id |
none | 1 |
/v1/immobilienscout24/price-insights |
Price Insights | location |
none | 1 |
How do you search listings in a city?
Pass the city as location and pick a listing type. The request below asks for apartments to rent in Berlin. Authenticate with the X-API-Key header; keys start with sk_live_, and authentication covers the details. You can get a key at signup and try the same call in the playground on the API page.
curl "https://api.perceptlayer.com/v1/immobilienscout24/search?location=Berlin&type=apartment-rent" \
-H "X-API-Key: $API_KEY"
Here is an excerpt of the recorded response for exactly that request, trimmed with …:
{
"success": true,
"total_results": 11396,
"page": 1,
"total_pages": 570,
"results": [
{
"id": "168052908",
"title": "Naturverbunden wohnen in kompakter 2-Zimmer-Gartenwohnung mit WBS-140-Förderung",
"price": 362,
"is_tenant_network": false,
"price_formatted": "362 €",
"rooms": 2,
"size_m2": 52,
"address": "Hellersdorfer Straße 91, 12619 Berlin, Kaulsdorf (Hellersdorf)",
"lat": 52.52485,
"lon": 13.58695,
"url": "https://www.immobilienscout24.de/expose/168052908",
"is_private": false,
"published": "vor 16 Tagen"
},
…
]
}
Which search parameters can you set?
All filters other than location are optional. Combine them to narrow the result set before you pay for pages you don't need.
| Parameter | Type | Notes |
|---|---|---|
location |
string, required | Up to 255 characters |
type |
string | One of apartment-rent, apartment-buy, house-rent, house-buy |
price_min, price_max |
integer | Price range |
rooms_min, rooms_max |
number | Room range; a number, so half rooms are possible |
size_min, size_max |
integer | Size range |
page, per_page |
integer | Paging |
A filtered example: rentals in Berlin with at least two rooms and 50 square metres.
curl "https://api.perceptlayer.com/v1/immobilienscout24/search?location=Berlin&type=apartment-rent&rooms_min=2&size_min=50" \
-H "X-API-Key: $API_KEY"
What do the response fields mean?
Each item in results is one listing, and the response wraps them with total_results, page and total_pages. Read total_pages to know when to stop paging. The listing fields are plain: id is a string, price a number with price_formatted as display text, rooms and size_m2 numbers, and url links to the original exposé on the portal.
Three details from the recorded sample matter if you store this data:
publishedis relative German text. The sample has "vor 16 Tagen" (16 days ago) and "vor einem Monat" (a month ago). Convert it against the time of your call and keep both the raw string and your computed date. Month-level text gives you a rough date only.- Coordinates can be shared. The two sample listings have different house numbers but identical
latandlon. Treat them as approximate and useaddresswhen you need a precise match. priceis a number. In the sample it is 362 for one listing and 760 for another, both 52 square metres. Prices in raw listings vary widely, so check for outliers before you average.
For the rest of the fields, run the call in the playground. The recorded excerpt above is all this article quotes.
What about Locations, Property and Price Insights?
These three endpoints have no recorded response in this article, so it shows their requests and cost only. Each is GET, 1 credit per successful call. locations takes a query (up to 255 characters) and an optional limit. property takes an id. price-insights takes a location (up to 255 characters) and returns market context. For response fields, see the API pages: Locations, Property and Price Insights. Check the shape there before you build a parser.
curl "https://api.perceptlayer.com/v1/immobilienscout24/locations?query=Kaulsdorf&limit=5" \
-H "X-API-Key: $API_KEY"
curl "https://api.perceptlayer.com/v1/immobilienscout24/property?id=168052908" \
-H "X-API-Key: $API_KEY"
curl "https://api.perceptlayer.com/v1/immobilienscout24/price-insights?location=Berlin" \
-H "X-API-Key: $API_KEY"
How do you page through every result?
Loop on page until it reaches total_pages. The recorded Berlin rental search reported 570 pages, so a full walk is 570 calls × 1 credit = 570 credits. Narrow with price_max, rooms_min or size_min first and the loop shrinks. The same pattern is covered in paginating a web data API in Python.
import os
import requests
BASE = "https://api.perceptlayer.com/v1/immobilienscout24/search"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}
def search_all(location, listing_type, max_pages=5, **filters):
page = 1
while page <= max_pages:
params = {"location": location, "type": listing_type, "page": page, **filters}
resp = requests.get(BASE, headers=HEADERS, params=params, timeout=30)
resp.raise_for_status()
body = resp.json()
yield from body["results"]
if page >= body["total_pages"]:
break
page += 1
for item in search_all("Berlin", "apartment-rent", max_pages=2, rooms_min=2):
print(item["id"], item["price_formatted"], item["size_m2"], item["address"])
The max_pages cap is a budget guard, not a limit of the API. Handle failures with the status and code in the JSON error body; errors lists them, and handling API errors in Python shows retry logic. A 429 carries a Retry-After header with the seconds to wait.
What does it cost?
A successful call costs 1 credit on every ImmobilienScout24 endpoint, and failed calls cost nothing and return X-Credits-Used: 0. Free accounts get 1,000 credits a month after email verification, with no credit card. Every response carries X-Credits-Used and X-Credits-Remaining, so you can track spend per call. Credits explains the rules.
| Job | Calls | Credits |
|---|---|---|
20 locations calls |
20 × 1 | 20 |
| Walk the 570 pages of the Berlin rental search once | 570 × 1 | 570 |
| Same walk, every day for 30 days | 17,100 × 1 | 17,100 |
Add 50 property lookups and 5 price-insights calls a day for 30 days |
1,650 × 1 | 1,650 |
The daily Berlin walk plus the lookups comes to 18,750 credits a month, more than the Starter pack's 10,000 credits and within the Build pack's 50,000, unless you narrow the filters first. For what credits cost, see pricing. Purchased credits last 12 months, and there's no subscription.
When is the official ImmobilienScout24 API a better fit?
ImmobilienScout24 runs its own developer API, documented at the ImmobilienScout24 API docs. It is built for partners, mainly brokers and property software that publish and manage their own listings. If you're a broker syncing your own exposés into your website or CRM, the official route fits better: it's the sanctioned channel for your own objects, and it needs a registration with the portal.
Perceptlayer fits the other direction: reading public listings across a city or a market, for research, price monitoring, lead lists or an AI agent, with no partner agreement. Data is collected from publicly available sources and returned as found at the time of the call, so a listing can change or vanish after you pull it. Check the portal's own terms for how you may use listing content.
What's the next step?
Get a free key at signup, run the Berlin search above, and look at total_pages before you decide how much to pull. If you're building an agent, the same endpoints are available as tools through the MCP server; AI agents (MCP) shows how. For other markets, the same pattern works in the Rightmove API guide for UK listings, and deduplicating listings across sources covers matching the same flat across portals. All guides are in the API guides category.
APIs in this post
Frequently asked questions
Is there an official ImmobilienScout24 API?
Yes, but it is aimed at partners such as brokers who manage their own listings, and it requires registering with the portal. Perceptlayer's ImmobilienScout24 endpoints are for reading public listings by location. They need only an API key, and a successful call costs 1 credit.
How many credits does an ImmobilienScout24 search cost?
One credit per successful call, on all four endpoints. A search for one page is 1 credit. The recorded Berlin rental search reported 570 pages, so reading all of them is 570 credits. Failed calls cost nothing. You get 1,000 free credits a month after verifying an email address.
Which listing types can I search?
The type parameter accepts apartment-rent, apartment-buy, house-rent and house-buy. It is optional. You can also filter by price_min, price_max, rooms_min, rooms_max, size_min and size_max, and page with page and per_page.
Can the listing data go stale?
Yes. Data is returned as found at the time of the call, and listings on the portal change or get removed. The published field is relative German text such as "vor 16 Tagen", so store the date of your own call next to it and re-run the search before acting on an old record.
How fast can I call it?
Limits are per account and counted per minute. Free accounts get 1 request a second, and paying accounts run at least 5 a second. A 429 response includes a Retry-After header with the seconds to wait. See rate limits for pack rates.