Otodom property search
Property in Poland on Otodom with the site's filters: sale or rent; flat, house, room, plot, commercial, warehouse, garage or new development; location; price, area, price per m², rooms, floors, build year, plot area, extras, building type, market, advertiser type, keywords, days since listed, radius and sort. Each result has id, link, title, price, currency, rent, price per m², area, rooms, floor, street, city, district and neighbourhood, dates, promoted and exclusive flags, advertiser type, agency (name, page, logo), development and photos. Pass next_page back as page; null on the last page.
Every response includes credits_used: the credits this call cost.
Parameters
| name | type | description |
|---|---|---|
transaction | sale | rent | Sale or rent. Example: sale |
estate | flat | house | room | plot | commercial | warehouse | garage | development | studio | Property kind. Example: flat |
location | string | Location path as in otodom.pl search links (voivodeship/county/commune/city[/district]), e.g. mazowieckie/warszawa/warszawa/warszawa or malopolskie/krakow/krakow/krakow. Default: all of Poland. Example: mazowieckie/warszawa/warszawa/warszawa |
url | string | Instead of the filters: an otodom.pl/pl/wyniki/... search link, used with all its filters. |
price_min | number | Minimum price (PLN). |
price_max | number | Maximum price (PLN). |
area_min | number | Minimum area (m²). |
area_max | number | Maximum area (m²). |
price_m2_min | number | Minimum price per m². |
price_m2_max | number | Maximum price per m². |
rooms | string | Rooms, comma-separated numbers (11 = more than 10). |
floors | string | Floors, comma-separated: CELLAR, GROUND, FIRST ... TENTH, ABOVE_TENTH, GARRET. |
build_year_min | integer | Built from (year). |
build_year_max | integer | Built until (year). |
plot_area_min | number | Minimum plot area (m², houses and plots). |
plot_area_max | number | Maximum plot area (m²). |
extras | string | Extras, comma-separated: BALCONY, TERRACE, GARDEN, GARAGE, LIFT, BASEMENT, SEPARATE_KITCHEN, AIR_CONDITIONING, TWO_STOREY, USABLE_ROOM, ... |
building_type | string | Building types, comma-separated: BLOCK, TENEMENT, HOUSE, INFILL, RIBBON, APARTMENT, LOFT. |
market | all | primary | secondary | Primary (new) or secondary market. |
owner_type | all | private | agency | developer | Advertiser type. |
keywords | string | Words in the description. |
days_since_created | integer | Listed within this many days (1, 3, 7, 14, 30). |
radius_km | integer | Extra radius around the location in km (0, 5, 10, 15, 25, 50, 75). |
sort | relevance | newest | price_asc | price_desc | area_asc | area_desc | price_m2_asc | price_m2_desc | Sort order. Example: relevance |
limit | integer | Results per page: 24, 36, 48 or 72. Example: 36 |
page | integer | Page number, starting at 1. Pass next_page back as page; it is null on the last page. Example: 1 |
Every endpoint also takes fresh, raw, fields (see lean responses and caching).
Example
curl "https://api.api.sh/otodom/v1/search?transaction=sale" \
-H "x-api-key: $APISH_KEY" import os, requests
res = requests.get(
"https://api.api.sh/otodom/v1/search",
params={"transaction": "sale"},
headers={"x-api-key": os.environ["APISH_KEY"]},
timeout=120,
)
res.raise_for_status()
data = res.json() const url = new URL("https://api.api.sh/otodom/v1/search");
url.searchParams.set("transaction", "sale");
const res = await fetch(url, { headers: { "x-api-key": process.env.APISH_KEY } });
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json(); Response
A JSON object with the fields described above, plus raw (the source's own data), cached, fetched_at and credits_used. Errors return {"success": false, "error": "…"} with the HTTP status (see errors). A lookup that ran but found nothing (404) costs the price above; refused calls and errors on our side are free (what's charged).