contract 2026-09-03
Endpoints

European classifieds

A retail price surface of 9.8M listings in the 2026-08-18 coverage snapshot gathered from 681 origin portals — national classifieds sites, dealer groups and manufacturer stock pages — across 39 European countries: mobile.de, kleinanzeigen.de, autoscout24, leboncoin.fr, lacentrale.fr, autosupermarket.it, njuskalo.hr and hundreds more. Every listing keeps its origin portal in source_site, so the same feed answers a national question and a portal-level one. These are retail listings, not auction inventory: no bidding, no auction end date, no detail payload and no gallery, just a single remote thumbnail per listing. They live in their own tables with their own vocabulary (seller type, origin portal), which is why they get their own query surface instead of a site slug on /api/search. Ended and paid-placement ("promoted") rows are excluded from every response, and all three endpoints return 503 while the dataset has not been built yet. Scope: classifieds. Legacy /api/theparking/* paths and theparking grants remain compatible aliases.

Calling it end to end

  1. 1Call GET /api/classifieds/facets once and cache it. Everything sits under a facets key: countries, brands, fuels, gearboxes, sellers, sources, value_counts and totals. It takes no filters — it always describes the whole feed. Never hard-code these values: brand, model, fuel, gearbox and seller are compared case-sensitively, so copy the spellings from here.
  2. 2When the user picks a brand, call GET /api/classifieds/models?brand=BMW,Audi to fill the model select. Models come back most common first, capped at 400.
  3. 3Query GET /api/classifieds/listings with the chosen filters. Multi-value filters are comma-separated: they OR within a parameter and AND across parameters. Page with limit/offset or page/page_size — limit caps at 100. If you do not need a match count, pass include_total=false: it is the fastest way to page this feed.
  4. 4Render each row directly. There is no detail endpoint and no gallery: the listing object you receive is the entire record, with one remote thumbnail in image_url and a deep link out in offer_url.
  5. 5To use it as a market reference, query the same brand, model, and year window you are about to bid on, read the price_eur spread by seller_type, and diff it against the auction lot’s public_price_eur.

Coverage by country

9,808,689 active listings as of 2026-08-18, across 39 countries and 681 origin portals. The figures move with every refresh — read them as proportions, and take live counts from /api/classifieds/facets.

Countrycountry=ListingsPortalsLargest origin portals
Germanyde2,218,902101mobile.de, kleinanzeigen.de, autoscout24.de, volkswagen.de, pkw.de, instamotion.com
Francefr1,328,466148leboncoin.fr, lacentrale.fr, zoomcar.fr, autocadre.com, spoticar.fr, paruvendu.fr
Italyit1,076,20661subito.it, autoscout24.it, quattroruote.it, autosupermarket.it, automobile.it, automoto.it
Spaines710,37068coches.net, milanuncios.com, autoscout24.es, autocasion.com, motorflash.com, coches.com
Netherlandsnl640,48263autowereld.nl, marktplaats.nl, autotrack.nl, autoscout24.nl, viabovag.nl, autokopen.nl
Polandpl548,62351otomoto.pl, olx.pl, sprzedajemy.pl, autoplac.pl, allegro.pl, motogratka.pl
Bulgariabg381,26524car24.bg, mobile.bg, cars.bg, auto.bg, bazar.bg, olx.bg
Austriaat280,20335willhaben.at, gebrauchtwagen.at, autoscout24.at, zweispurig.at, dasweltauto.at, kleinanzeigen.at
Belgiumbe264,93191autoscout24.be, 2ememain.be, gocar.be, vroom.be, carselect.touring.be, okasie.be
Albaniaal252,5115merrjep.al, albania.landrover.com, carandclassic.com, motorsportmarkt.de, oldcar24.com
Switzerlandch222,76633autoscout24.ch, autolina.ch, tutti.ch, ricardo.ch, emilfrey.ch, auto.amag.ch
Swedense187,86929blocket.se, bytbil.com, bilweb.se, volkswagen.se, riddermarkbil.se, hedinautomotive.se

A country figure is a mix of portals, not a single market — half of German inventory is one site. When that matters, narrow with source or widen with source_exclude. Only the largest portals are listed here; /api/classifieds/facets?limit=0 returns all 681.

GET

/api/classifieds/listings

Query retail classifieds aggregated from portals across Europe.

Requires the classifieds scope.

Parameters

page / page_sizeinteger · query string

1-based page and rows per page, as alternatives to offset and limit. Do not combine page with offset or page_size with limit.

Example 1 / 50·Where the value comes from Pagination state in your application.

countrystring · query string

Comma-separated country codes, case-insensitive.

Example de,at·Where the value comes from /api/classifieds/facets -> countries[].value

brandstring · query string

Comma-separated brands, exact as published. Compared as stored — case-sensitive. bmw matches nothing where BMW matches. Take the spelling from the facets endpoint.

Example BMW,Audi·Where the value comes from /api/classifieds/facets -> facets.brands[].value

modelstring · query string

Comma-separated models. Compared as stored — case-sensitive.

Example 3 Series·Where the value comes from /api/classifieds/models?brand=BMW -> models[].value

fuelstring · query string

Comma-separated normalized fuels. Exact, case-sensitive.

Example diesel·Where the value comes from /api/classifieds/facets -> facets.fuels[].value

gearboxstring · query string

Comma-separated normalized gearboxes. Exact, case-sensitive.

Example automatic·Where the value comes from /api/classifieds/facets -> facets.gearboxes[].value

sellerstring · query string

Comma-separated seller types, such as dealer or private. Exact, case-sensitive.

Example dealer·Where the value comes from /api/classifieds/facets -> facets.sellers[].value

sourcestring · query string

Comma-separated origin portals, case-insensitive. Unlike site on the auction side, an unrecognised portal is not an error — this vocabulary is drawn from the data itself rather than fixed, so an unknown value simply matches nothing.

Example mobile.de·Where the value comes from /api/classifieds/facets -> sources[].value

source_excludestring · query string

Comma-separated origin portals to leave out, case-insensitive. With ~681 portals in the vocabulary this is the only practical way to say “everything but”. A listing with no recorded portal survives an exclusion.

Example mobile.de·Where the value comes from /api/classifieds/facets -> sources[].value

price_from / price_tointeger · query string

EUR bounds.

Example 5000 / 15000·Where the value comes from EUR budget chosen by your user.

year_from / year_tointeger · query string

Year bounds.

Example 2016 / 2022·Where the value comes from Year bounds chosen by your user.

kilometers_from / kilometers_tointeger · query string

Mileage bounds.

Example 0 / 200000·Where the value comes from Mileage bounds chosen by your user.

qstring · query string

Case-insensitive substring match on the listing title or its description. The description itself is not returned, so a match can look unexplained — it is text you cannot see. Rare q values are also the usual cause of total_unavailable.

Example touring·Where the value comes from Free text entered by your user.

with_photoboolean · query string

Only listings that carry a thumbnail.

Example true·Where the value comes from Your filter choice.

sortenum · query string

Default newest.

Example price_low·Where the value comes from Choose newest, price_low, price_high, year_new, year_old, or mileage_low.

limit / offsetinteger · query string

Or page_size / page. Default 50, max 100, offset capped at 5000. This envelope carries total, limit, offset and total_pages only — no page, page_size or max_page. Page by offset.

Example 50 / 0·Where the value comes from Pagination state in your application.

include_totalboolean · query string

Default true. Pass false to skip the match count entirely — total comes back null and the request is markedly faster.

Example false·Where the value comes from Your pagination strategy.

Example requests

Request
GET https://api.thecarapi.com/api/classifieds/listings?country=de,at&brand=BMW&price_to=15000
GET https://api.thecarapi.com/api/classifieds/listings?seller=dealer&source=mobile.de&sort=price_low&with_photo=true
GET https://api.thecarapi.com/api/classifieds/listings?country=de&source_exclude=mobile.de,kleinanzeigen.de&include_total=false

Example response

json
{
  "success": true,
  "listings": [
    {
      "reference_id": "tp-91744022",
      "title": "BMW 320d Touring",
      "brand": "BMW",
      "model": "3 Series",
      "engine": "320d",
      "year": 2016,
      "price_eur": 12500.5,
      "mileage_km": 180000,
      "fuel_norm": "diesel",
      "gearbox_norm": "automatic",
      "colour": "black",
      "doors": "5",
      "country": "Germany",
      "country_code": "de",
      "region": "Bayern",
      "seller_type": "dealer",
      "source_site": "mobile.de",
      "photo_count": 12,
      "offer_url": "https://www.theparking.eu/...",
      "image_url": "https://img.leparking.fr/...",
      "published": "2026-07-30",
      "first_seen_at": "2026-07-30T04:11:02",
      "last_seen_at": "2026-08-05T04:09:55"
    }
  ],
  "total": 4412,
  "total_capped": false,
  "total_unavailable": false,
  "limit": 50,
  "offset": 0,
  "total_pages": 89
}

What you get back

reference_idstring

Stable identity for the listing, prefixed tp-. Use it to de-duplicate across polls.

titlestring

Listing headline as published by the origin portal.

brand / model / enginestring

Brand and model as published, plus the engine or trim string when the portal supplies one.

yearinteger

Registration year.

price_eurnumber

Retail asking price in EUR. This is an asking price, not a transaction price.

mileage_kminteger

Odometer reading in kilometres.

fuel_normstring

Normalized fuel, e.g. diesel, petrol, electric, hybrid. Matches the fuel filter vocabulary.

gearbox_normstring

Normalized gearbox, e.g. automatic, manual. Matches the gearbox filter vocabulary.

colourstring

Exterior colour as published.

doorsstring

Door count as published by the portal.

country / country_codestring

Country the car is listed in — display name and lower-case code. country_code is what the country filter accepts.

regionstring

Sub-national region or state when the portal publishes one.

seller_typestring

dealer or private. The single most useful axis for separating trade from retail asking prices.

source_sitestring

Origin portal the listing came from, e.g. mobile.de. Matches the source / source_exclude filter vocabulary, ~681 values wide. This is the attribution that makes a country figure readable — half of all German inventory is one portal.

photo_countinteger

How many photos the origin listing carries. Only one thumbnail is exposed here.

offer_urlstring

Deep link out to the listing, routed through the aggregator that indexes it — the URL is a theparking.eu one, not a direct link on the origin portal. Read source_site, not this URL, to know which portal the listing belongs to.

image_urlstring

Single remote thumbnail on the aggregator’s own CDN. Not copied into our image vault — treat it as a hotlink that disappears with the listing.

publisheddate

Date the origin portal published the listing.

first_seen_at / last_seen_attimestamp

When our sweep first and most recently observed the listing. Use last_seen_at to judge staleness.

total / limit / offset / total_pagesinteger

Standard pagination envelope for the matching set. total is exact for ordinary filters, and null when total_unavailable is true.

total_cappedboolean

True when counting stopped at 100,000. Read total as “100,000+” and page by offset rather than trusting total_pages. An unfiltered total is precomputed and never capped.

total_unavailableboolean

True when total is null because the count did not finish inside its budget — typically a q= search or a rare source. The listings themselves are complete and correct; only the count is missing, and the verdict is cached for 5 minutes.

GET

/api/classifieds/facets

Counted filter vocabulary for the classifieds dataset.

Requires the classifieds scope.

Parameters

limitinteger · query string

Values returned per dimension, default 50. 0 returns all of them — the only way to get the full 681-portal sources list.

Example 0·Where the value comes from How many values your picker can hold.

Example requests

Request
GET https://api.thecarapi.com/api/classifieds/facets
GET https://api.thecarapi.com/api/classifieds/facets?limit=0
curl -H "X-API-Key: $API_KEY" "https://api.thecarapi.com/api/classifieds/facets"

Example response

json
{
  "success": true,
  "facets": {
    "countries": [
      {
        "value": "de",
        "count": 1840221
      }
    ],
    "brands": [
      {
        "value": "BMW",
        "count": 402118
      }
    ],
    "fuels": [
      {
        "value": "diesel",
        "count": 4110882
      }
    ],
    "gearboxes": [
      {
        "value": "manual",
        "count": 5233901
      }
    ],
    "sellers": [
      {
        "value": "dealer",
        "count": 8901233
      }
    ],
    "sources": [
      {
        "value": "mobile.de",
        "count": 913442
      }
    ],
    "value_counts": {
      "countries": 41,
      "brands": 128,
      "fuels": 7,
      "gearboxes": 3,
      "sellers": 2,
      "sources": 683
    },
    "totals": {
      "total": 9714882,
      "total_capped": false,
      "price_min": 50,
      "price_max": 4500000,
      "year_min": 1920,
      "year_max": 2027
    }
  }
}

What you get back

facets.countries / brands / fuels / gearboxes / sellers / sources{value, count}[]

Each dimension is a list of {value, count}, most common first, nested under the facets key rather than at the top level. The values are exactly what the listings feed’s filters match on, so copy them verbatim: brands, fuels, gearboxes and sellers are compared case-sensitively downstream.

facets.value_counts.<dimension>integer

How many distinct values that dimension really has, before limit trimmed it. Check value_counts.sources against the length of sources to know whether you are looking at all of them.

facets.totals.totalinteger

Listings in the feed.

facets.totals.total_cappedboolean

True when counting stopped at 100,000 — read total as "100,000+".

facets.totals.price_min / price_max / year_min / year_maxnumber | integer

EUR and year bounds across the feed, for sizing sliders.

GET

/api/classifieds/models

List models available for one or more brands.

Requires the classifieds scope.

Parameters

brandstring · query stringrequired

Comma-separated brand list. Required. Matched exactly and case-sensitively, like the same parameter on the listings feed — pass the spellings from the brands facet.

Example BMW,Audi·Where the value comes from /api/classifieds/facets -> facets.brands[].value

Example requests

Request
GET https://api.thecarapi.com/api/classifieds/models?brand=BMW
GET https://api.thecarapi.com/api/classifieds/models?brand=BMW,Audi

Example response

json
{
  "success": true,
  "models": [
    {
      "value": "3 Series",
      "count": 8841
    },
    {
      "value": "5 Series",
      "count": 6002
    }
  ]
}

What you get back

models{value, count}[]

Model names available for the requested brands, most common first, capped at 400. value goes straight back into the model filter on /api/classifieds/listings.