Otomoto API

Poland's car market as JSON, with every filter checked against the site's own echo

Otomoto API returns live Otomoto data as clean JSON for otomoto The primary endpoint, search, returns matching records including ad id, listing id, eg id6igtyl or olx id6iguof this is what listingdetail takes, title and subtitle.

no credit card1,000 free credits · instant API key · pay by card or crypto
Missing a Otomoto endpoint, or need a source we don't have yet?Contact us real people · same-day reply.
O
/otomoto/v1

3 active endpoints. Every call is 1 credit.

  • POST/otomoto/v1/search
  • POST/otomoto/v1/listing/detail
  • POST/otomoto/v1/makes

What Otomoto endpoints does ReefAPI ship?

3 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.

3 endpoints

search

1 cr

Search otomoto.pl the way its own visitors do.

required
—
optional
category, make, model, location, distance_km, page, sort, seller_type, condition, fuel_type, gearbox, body_type, damaged, price_from, price_to, year_from, year_to, mileage_from, mileage_to, engine_power_from, engine_power_to, engine_capacity_from, engine_capacity_to

listing/detail

1 cr

The full otomoto offer record from an offer URL or its ID token.

required
listing
optional
—

makes

1 cr

The makes otomoto itself lists on a section's landing page, ranked by how many live ads each…

required
—
optional
category, make

Every parameter, every allowed value →

Otomoto API

3 of 3 endpoints, ready to run

View docs ↗

Search otomoto.pl the way its own visitors do: pick a section (cars, vans, motorcycles), narrow by make and model, by voivodeship or by city with a radius, and apply otomoto's own price, year, mileage, engine power, engine capacity, fuel, gearbox, body, condition, damage and seller-type filters. Every ad comes back with the price in PLN cross-checked against otomoto's own price string, the published model year, the odometer reading with the site's own formatted string beside it, fuel and gearbox in both otomoto's code and its Polish label, engine power and capacity, the city and voivodeship, whether a private person or a dealer is selling (otomoto's own flag, never inferred), otomoto's below/at/above-market price indicator, the CEPiK history-check flag, and whether the ad is a paid promoted placement. Promoted ads are returned in the position otomoto gives them and flagged, never dropped. Sort by price, mileage, engine power or posting date, and page through the whole result set. The answer repeats every filter otomoto actually applied, with the canonical slug it resolved to, and lists every model otomoto publishes for the chosen make with its live ad count — so the next call can drill down without guessing a slug.

1 credit0 required · 23 optional
POST/otomoto/v1/search
oksample
{
  "action": "search",
  "params": {
    "make": "bmw"
  },
  "ok": true,
  "data": {
    "results": [
      {
        "ad_id": "6150884267",
        "listing_id": "ID6IgtYL",
        "title": "BMW X3",
        "subtitle": "pierwszy właściciel, stan idealny",
        "url": "https://www.otomoto.pl/osobowe/oferta/bmw-x3-ID6IgtYL.html",
        "created_at": "2026-09-30T11:23:18Z",
        "price": 75000,
        "price_raw": "75000",
        "currency": "PLN",
        "price_is_gross": true,
        "price_mismatch": null,
        "price_evaluation": "NONE",
        "price_drop": null,
        "make": "BMW",
        "make_slug": "bmw",
        "model": "X3",
        "model_slug": "x3",
        "version": null,
        "year": 2020,
        "mileage_km": 69349,
        "mileage_display": "69349 km",
        "fuel_type": {
          "value": "petrol",
          "label": "Benzyna"
        },
        "gearbox": {
          "value": "automatic",
          "label": "Automatyczna"
        },
        "engine_power_hp": 252,
        "engine_capacity_ccm": 1998,
        "field_mismatch": null,
        "location": {
          "city": "Warszawa",
          "region": "Mazowieckie",
          "country": "PL"
        },
        "is_promoted": true,
        "promotions": [
          "topads",
          "export_olx"
        ],
        "badges": null,
        "cepik_verified": false,
        "image": "https://ireland.apollo.olxcdn.com/v1/files/7axmipf4pmcu-OTOMOTOPL/image;s=640x480",
        "category_id": "29"
      },
      {
        "ad_id": "6150882397",
        "listing_id": "ID6IgtuB",
        "title": "BMW Seria 3 330i xDrive Edition M Sport Shadow",
        "subtitle": "pierwszy właściciel, idealny stan, gwarancja na silnik i skrzynię",
        "url": "https://www.otomoto.pl/osobowe/oferta/bmw-seria-3-ID6IgtuB.html",
        "created_at": "2026-09-30T09:33:31Z",
        "price": 45000,
        "price_raw": "45000",
        "currency": "PLN",
        "price_is_gross": true,
        "price_mismatch": null,
        "price_evaluation": "NONE",
        "price_drop": null,
        "make": "BMW",
        "make_slug": "bmw",
        "model": "Seria 3",
        "model_slug": "seria-3",
        "version": "330i xDrive Edition M Sport Shadow",
        "year": 2017,
        "mileage_km": 82523,
        "mileage_display": "82523 km",
        "fuel_type": {
          "value": "petrol",
          "label": "Benzyna"
        },
        "gearbox": {
          "value": "automatic",
          "label": "Automatyczna"
        },
        "engine_power_hp": 252,
        "engine_capacity_ccm": 1998,
        "field_mismatch": null,
        "location": {
          "city": "Warszawa",
          "region": "Mazowieckie",
          "country": "PL"
        },
        "is_promoted": true,
        "promotions": [
          "topads",
          "export_olx"
        ],
        "badges": null,
        "cepik_verified": false,
        "image": "https://ireland.apollo.olxcdn.com/v1/files/w0up4hmpgv24-OTOMOTOPL/image;s=640x480",
        "category_id": "29"
      },
      {
        "ad_id": "6150882222",
        "listing_id": "ID6IgtrM",
        "title": "BMW X5 xDrive25d",
        "subtitle": null,
        "url": "https://www.otomoto.pl/osobowe/oferta/bmw-x5-ID6IgtrM.html",
        "created_at": "2026-09-30T09:21:50Z",
        "price": 49900,
        "price_raw": "49900",
        "currency": "PLN",
        "price_is_gross": true,
        "price_mismatch": null,
        "price_evaluation": "NONE",
        "price_drop": null,
        "make": "BMW",
        "make_slug": "bmw",
        "model": "X5",
        "model_slug": "x5",
        "version": "xDrive25d",
        "year": 2014,
        "mileage_km": 145869,
        "mileage_display": "145869 km",
        "fuel_type": {
          "value": "diesel",
          "label": "Diesel"
        },
        "gearbox": {
          "value": "automatic",
          "label": "Automatyczna"
        },
        "engine_power_hp": 218,
        "engine_capacity_ccm": 1995,
        "field_mismatch": null,
        "location": {
          "city": "Blizne",
          "region": "Podkarpackie",
          "country": "PL"
        },
        "is_promoted": true,
        "promotions": [
          "topads",
          "bump_up",
          "export_olx"
        ],
        "badges": null,
        "cepik_verified": false,
        "image": "https://ireland.apollo.olxcdn.com/v1/files/7ploe8j0xseg-OTOMOTOPL/image;s=640x480",
        "category_id": "29"
      }
    ],
    "count": 3,
    "total_results": 21512,
    "page": 1,
    "page_size": 32,
    "sort": "relevance",
    "currency": "PLN"
  }
}
Real response, fetched from the live endpoint with the parameters on the left — trimmed to the first few rows, with seller names left out. Press Try it for the untrimmed response.

How the Otomoto API works

Otomoto is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.

01
Authenticate
x-api-key header

No OAuth app, no request signing, no per-site account. One key covers all 321 engines.

02
Call
POST /otomoto/v1/…

Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.

03
Pay
1 credit per call

Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.

04
Read
{ ok, data, meta, error }

One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.

Check the make list first, because a make Otomoto does not know is silently ignored

Otomoto builds its search from path segments, and a segment it does not recognise is dropped rather than refused. A search for a misspelled make returns the whole national inventory and a total that looks entirely plausible, which is the worst kind of wrong answer.

01makes
POST/otomoto/v1/makes
{}

1 credit. Otomoto's published shortlist of makes, and with a make supplied, its models. This is the spelling the search surface accepts.

02search
POST/otomoto/v1/search
{"make": "bmw", "location": "krakow"}

1 credit for thirty-two rows. Every filter sent is verified against Otomoto's own applied-filters echo before the results are returned, so a value the site quietly dropped comes back as an invalid parameter instead of as an unfiltered result set.

03search
POST/otomoto/v1/search
{"make": "bmw", "year_from": 2018, "mileage_to": 120000, "seller_type": "private"}

1 credit. Ranges and the seller type are echoed the same way. The seller filter was checked against the site's own split: thirty-two of thirty-two private and thirty-two of thirty-two business.

04detail
POST/otomoto/v1/listing/detail
{"listing": "<id or the offer URL>"}

1 credit. The full offer with the fields the results card does not carry. Cross-posted OLX offers keep their marker in the id, because dropping it turns a live listing into a not-found.

A make you know the site recognises, a filtered set you can trust because the site confirmed each filter, and the full record for the offers worth reading.

request
curl -X POST https://api.reefapi.com/otomoto/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"make":"bmw"}'
response envelope
{
  "ok": true,
  "data": { … },
  "meta": {
    "api": "otomoto",
    "endpoint": "search",
    "mode": "live",
    "latency_ms": …,
    "record_count": …
  },
  "error": null
}

Poland only, in zloty, and every filter proven against the site's own echo

Measured 2026-09-30 against the live gateway across three searches and ninety-six rows, with every number checked against the string Otomoto printed beside it. Three of these lines go against us.

Poland, in zloty, one storefront

Otomoto is a single national marketplace and every figure comes back in PLN. There is no country parameter because there is no second country. Prices carry a flag for whether the quoted figure is gross or net, because on a dealer offer in Poland that difference is the VAT and it is not small.

Against us: a path segment Otomoto does not recognise is silently dropped

Searching for a make that does not exist answers with HTTP 200 and 254,478 cars, as though that were the answer to the question asked. Every make, model, location and enumerated filter is now verified against Otomoto's own applied-filters echo, and a value the site ignored is refused as an invalid parameter. This is the single most important thing on this page: without that check, a typo returns the national inventory and a total that looks right.

There is no keyword search, because the site has none

A q parameter is accepted by the URL and ignored by the back end, so no keyword parameter is published at all rather than one that appears to work. Search is by make, model, geography and the numeric ranges.

Every number is checked against the string printed beside it

Across ninety-six live rows, the numeric price matched Otomoto's own price string on all ninety-six, and the numeric mileage matched its own mileage string on all ninety-six. Nothing is derived from a title: the year, mileage, fuel, gearbox and engine power are read from published fields, and a listing that publishes none of a field gets a null rather than a guess.

Promoted rows are the first rows, and they are complete

Sixty-eight of ninety-six measured rows were promoted placements. They carry the same fields as organic rows and were included in the sample deliberately, because promoted tiles sit at the top of every page and are what a caller reading results in order hits first.

A cross-posted OLX offer keeps its marker

Some offers reach Otomoto from OLX and their identifier carries a marker that is part of the id, not decoration. Stripping it produces a not-found on a listing that is very much alive, so the marker stays in listing_id.

A seller can be a third thing, and it is not private

Otomoto publishes a cross-listed seller type that is neither private nor a dealer, and it is returned under its own name rather than folded into private. The offer page resolves what it really is.

Against us: the make and model lists are shortlists

The makes endpoint returns Otomoto's own published top-twenty, not its full register. A make outside that list may still be searchable; the list is what the site puts in front of a visitor. The spec says so rather than implying the list is exhaustive.

Against us: only three sections are published

Otomoto lists more than cars. Only the three sections whose category ids were measured are offered, because a section id guessed rather than measured would silently return the wrong inventory - which is the same failure the applied-filters check exists to catch.

Price

1 credit for a search of thirty-two rows, 1 for a listing and 1 for the make list. Check the makes list once and cache it; the spelling does not change often and it is what stops the silent-drop failure.

What people build with Otomoto

The jobs this data is most often used for.

3

endpoints

1

credit per call

01

Pricing and assortment teams use Otomoto to search otomoto.pl the way its own visitors do.

02

Brand-protection teams use Otomoto to get the full otomoto offer record from an offer URL or its ID token.

03

Retail analysts use Otomoto to get the makes otomoto itself lists on a section's landing page, ranked by how many live ads each….

What Otomoto data costs

The cheapest call here is 1 credit, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.

Full pricing →
$0.67–$1.50 / 1,000 credits
  • 1,000 free credits on signup, no card
  • One key, all 321 APIs, one credit pool
  • Failed and blocked calls are never charged
  • Credits roll over and never expire

Call it in two lines

Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.

curl
curl -X POST https://api.reefapi.com/otomoto/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"make":"bmw"}'
python
import requests

r = requests.post(
    "https://api.reefapi.com/otomoto/v1/search",
    headers={"x-api-key": REEF_KEY},
    json={
  "make": "bmw"
},
)
print(r.json()["data"])
FAQ

Have a question? We got answers.

The questions people actually ask before wiring up Otomoto.

Get a free key →
What is the Otomoto API?▾

Otomoto API is a ReefAPI endpoint group for otomoto It returns live JSON through POST requests under /otomoto/v1.

Is the Otomoto API free to try?▾

Yes. ReefAPI starts with 1,000 free credits, no card required. Otomoto calls use the same shared credit balance as every other ReefAPI engine.

Do I need an Otomoto login or account?▾

No login to Otomoto is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.

How fresh is the Otomoto data?▾

The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.

How many credits does the Otomoto API use?▾

Otomoto actions currently cost 1 credit per successful call. Failed or blocked calls are free. All APIs draw from one credit pool.

Can I call Otomoto from an AI assistant or MCP client?▾

Yes. Connect ReefAPI once through MCP and your assistant can call otomoto actions with the same key, credit pool and JSON envelope used by normal REST requests.

Is the Otomoto API an Otomoto scraper?▾

It is the managed alternative to a DIY Otomoto scraper. Instead of building and maintaining your own scraper — proxies, headless browsers, captcha and constant breakage — you call one ReefAPI endpoint and get the same otomoto back as clean JSON.

Why does my Otomoto scraper keep getting blocked?▾

Most Otomoto scrapers break on anti-bot defenses, rate limits and IP bans that need rotating residential proxies and browser fingerprinting to clear. ReefAPI handles all of that for you — no proxies, no captchas, no maintenance — and returns live JSON. Blocked calls are free.

26 More APIs APIs on the same key

One key, one credit pool, one response envelope. If you are pulling Otomoto, you are one call away from the rest of the category — no second contract, no second integration.

Need something this API does not do?

Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.

0/4000

No account needed · we reply from [email protected]

Try it on your own data before you pay anything

The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 320 APIs, and the same envelope everywhere.

Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-09-30.