Skip to content
Scrappa Get API key
Otodom API 1 credit/request

Otodom Locations API Documentation

GET https://scrappa.co/api/otodom/locations?query=warszawa&limit=3

Endpoint documentation for resolving Polish place names to Otodom geo paths

How to call the Otodom locations endpoint and how to pick the right match.

Scrappa's GET /api/otodom/locations endpoint resolves a Polish place name into the geo paths that the Otodom search endpoint consumes.

What the response contains

Each match carries id, name, full_name and detailed_level. The id is the complete geo path — no slug synthesis is required on your side.

Choosing a match

The upstream operation is not prefix-scoped: a zoliborz query also returns villages in unrelated voivodeships. Use detailed_level to pick the granularity you want rather than taking the first result.

Related Otodom endpoints

  • GET /api/otodom/search — pass the id here as geo_path

Implementation playbook

What teams build with this endpoint

Location Picker UIs

Back a place autocomplete with real Otodom geo paths instead of guessing slugs.

Coverage Mapping

Enumerate districts and quarters per city to map supply coverage.

Otodom Locations API Documentation 1 credit/request

Endpoint

Request preview
GET
https://scrappa.co/api/otodom/locations?query=warszawa&limit=3
Auth header
x-api-key
Cost
1 credit/request
query = warszawa
Response preview
200 OK
{
    "success": true,
    "data": {
        "locations": [
            {
                "id": "mazowieckie/warszawa/warszawa/warszawa",
                "name": "Warszawa",
                "full_name": "Warszawa, mazowieckie",
                "detailed_level": "city"
            },
            {
                "id": "mazowieckie/warszawa/warszawa/warszawa/zoliborz",
                "name": "\u017boliborz",
                "full_name": "\u017boliborz, Warszawa, mazowieckie",
...

Parameters

Start with the required fields, then add optional filters only when your use case needs them.

Runnable path

1 required parameter needed before sending a request.

1 optional filter available.

query string Required

Place name to resolve. Polish diacritics are supported.

Example value warszawa
limit integer Optional

Maximum matches to return, up to 50.

Example value 3

Request Examples

PHP
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://scrappa.co/api/otodom/locations?query=warszawa&limit=3",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "x-api-key: YOUR_API_KEY_HERE"
    ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
    echo "cURL Error #:" . $err;
} else {
    echo $response;
}
PHP
<?php

use Illuminate\Support\Facades\Http;

$response = Http::timeout(30)
    ->withHeaders(['x-api-key' => 'YOUR_API_KEY_HERE'])
    ->get('https://scrappa.co/api/otodom/locations?query=warszawa&limit=3');

if ($response->successful()) {
    echo $response->body();
} else {
    echo "Error: " . $response->status();
}
JavaScript
const options = {
    method: 'GET',
    headers: {
        'x-api-key': 'YOUR_API_KEY_HERE'
    }
};

fetch('https://scrappa.co/api/otodom/locations?query=warszawa&limit=3', options)
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.text();
    })
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));
JavaScript
const axios = require('axios');

const options = {
    method: 'GET',
    url: 'https://scrappa.co/api/otodom/locations?query=warszawa&limit=3',
    headers: {
        x-api-key: 'YOUR_API_KEY_HERE',
    }
};

try {
    const response = await axios(options);
    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
Ruby
require 'net/http'
require 'uri'

uri = URI.parse("https://scrappa.co/api/otodom/locations?query=warszawa&limit=3")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'

request = Net::HTTP::Get.new(uri.request_uri)
request['x-api-key'] = 'YOUR_API_KEY_HERE'

begin
    response = http.request(request)
    puts response.body
rescue => e
    puts "Error: #{e.message}"
end
Python
import http.client
import json

conn = http.client.HTTPSConnection("scrappa.co")

headers = {
    'x-api-key': 'YOUR_API_KEY_HERE',
}

try:
    conn.request("GET", "/api/otodom/locations?query=warszawa&limit=3", headers=headers)
    res = conn.getresponse()
    data = res.read()
    print(data.decode("utf-8"))
except Exception as e:
    print(f"Error: {e}")
finally:
    conn.close()
Python
import requests

headers = {
    'x-api-key': 'YOUR_API_KEY_HERE',
}

try:
    response = requests.get('https://scrappa.co/api/otodom/locations?query=warszawa&limit=3', headers=headers)
    response.raise_for_status()
    print(response.text)
except requests.exceptions.RequestException as e:
    print(f"Error: {e}")
Java
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;

public class ApiExample {
    public static void main(String[] args) {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
            .url("https://scrappa.co/api/otodom/locations?query=warszawa&limit=3")
        .addHeader("x-api-key", "YOUR_API_KEY_HERE")
            .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            } else {
                System.out.println("Error: " + response.code());
            }
        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
Go
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {
    client := &http.Client{}
    req, err := http.NewRequest("GET", "https://scrappa.co/api/otodom/locations?query=warszawa&limit=3", nil)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }
    req.Header.Set("x-api-key", "YOUR_API_KEY_HERE")

    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error making request:", err)
        return
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Error reading response:", err)
        return
    }

    fmt.Println(string(body))
}
Terminal
#!/bin/bash

curl -X GET \
    -H "x-api-key: YOUR_API_KEY_HERE" \
    "https://scrappa.co/api/otodom/locations?query=warszawa&limit=3"
C#
using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY_HERE");

        try
        {
            var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://scrappa.co/api/otodom/locations?query=warszawa&limit=3"));
            var content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}
TypeScript
import axios from 'axios';

async function run(): Promise<void> {
    try {
        const response = await axios({
            method: 'GET',
            url: 'https://scrappa.co/api/otodom/locations?query=warszawa&limit=3',
            headers: {
        'x-api-key': 'YOUR_API_KEY_HERE',
            },
        });

        console.log(response.data);
    } catch (error) {
        console.error('Error:', error);
    }
}

void run();
RUST
use reqwest::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();

    let response = client
        .get("https://scrappa.co/api/otodom/locations?query=warszawa&limit=3")
        .header("x-api-key", "YOUR_API_KEY_HERE")
        .send()
        .await?;

    println!("{}", response.text().await?);

    Ok(())
}

Response Schema

Example response fields are illustrative; inspect the JSON before integrating.

Example response fields

Scan these fields before integrating.

success data
JSON Response
200 OK
{
    "success": true,
    "data": {
        "locations": [
            {
                "id": "mazowieckie/warszawa/warszawa/warszawa",
                "name": "Warszawa",
                "full_name": "Warszawa, mazowieckie",
                "detailed_level": "city"
            },
            {
                "id": "mazowieckie/warszawa/warszawa/warszawa/zoliborz",
                "name": "\u017boliborz",
                "full_name": "\u017boliborz, Warszawa, mazowieckie",
                "detailed_level": "district"
            }
        ],
        "query": "warszawa"
    }
}

Errors

Handle these documented responses before retrying or showing customer-facing failures.

INVALID_PARAMETERS

HTTP INVALID_PARAMETERS

The query returned no usable location matches.

UPSTREAM_ERROR

HTTP UPSTREAM_ERROR

Otodom could not be reached. This response is not billed.

Generate Code with AI

Copy a ready-made prompt with all the endpoint details, parameters, and example responses. Paste it into ChatGPT, Claude, or any AI assistant to instantly generate working code.

Otodom API FAQ

Do I need to build the geo path myself?

No. The id of each match is the complete geo path.

Why did I get matches from another region?

The upstream operation is not prefix-scoped. Filter on detailed_level and pick the match you want.

Does this cost a credit?

Only successful responses are billed.

Try It Live

Test this endpoint in our interactive playground with real data.