contract 2026-08-19
Endpoints

Vehicle details

Fetch a full source payload from cache or, when needed, from the upstream source.

GET | POST

/api/car-details

Fetch full vehicle detail by source and listing identifier.

Requires the details scope.

Parameters

sitestring · query string or JSON bodyrequired

schadeautos, auto1, openlane, copart, encar, ecarstrade, or japanauction.

Example encar·Where the value comes from /api/sites -> sites[].name

id / link / identifierstring · query string or JSON bodyrequired

Provide any one source id or listing URL. For auto1 and japanauction this is the offer id/UUID, not the numeric auction id.

Example 38112900·Where the value comes from /api/search -> results[].auction_id, or the source listing URL

search_idstring · query string or JSON body

Optional correlation id.

Example vehicle-page-42·Where the value comes from Optional correlation id generated by your application.

Example requests

Request
GET | POST https://api.thecarapi.com/api/car-details?site=encar&id=38112900
POST https://api.thecarapi.com/api/car-details
{
  "site": "openlane",
  "identifier": "11125938",
  "search_id": "vehicle-page-42"
}

Example response

json
{
  "success": true,
  "site": "openlane",
  "auction_id": 11409652,
  "current_price": 25900,
  "current_final": 33566,
  "public_price_eur": 33926,
  "vehicle_details": {},
  "auction": {
    "extracted_fields": {
      "images": []
    }
  },
  "live_price": {
    "price": 25900,
    "currency": "EUR",
    "source": "openlane",
    "fetched_at": 1786659750
  }
}

What you get back

vehicle_detailsobject | null

The same normalized block /api/auction/{site}/{id} returns, so the two detail endpoints agree. Null when the listing has no fetched details yet. This is the only part of the response with a stable cross-source contract — the remaining keys are source-shaped (data, auction, images, details depending on the source).

details_pendingboolean

True while the upstream fetch is still running. Poll rather than retrying in a tight loop; X-Details-Fetch carries the same signal in the headers.

current_price / current_final / public_price_eurnumber

The same price fields as /api/auction/{site}/{id}, under the same names and with the same JSON types — but at the top level here, because this body is source-shaped and has no auction wrapper. The two detail endpoints therefore cannot disagree about what a car costs.

live_price / live_price_pendingobject | boolean

Identical contract to /api/auction/{site}/{id}, and attached the same way when this response is served from stored auction data — the normal case. A first-ever fetch of a listing we hold no row for returns the source’s own fresh payload anyway.

auctionobject

Not the vehicle record. For openlane this is { extracted_fields: { images: […] } }, an image container that shares a name and nothing else. Read prices from the top level on this endpoint, and from inside auction on /api/auction/{site}/{id}.

estimated_value_eurnumber | null

Same field and same meaning as on /api/auction/{site}/{id}, at the top level here. The auction house own valuation — not a price you can pay, ecarstrade only, null everywhere else.

steeringenum | null

Same derivation and spelling as the search cards and /api/auction/{site}/{id}. Null only when the vehicle is not in our inventory at all, because there is then no registration country to derive a side from. On the paths that fetch straight from the source, deriving it is advisory — a failure to compute it is swallowed rather than turning a working detail response into an error, so its absence there does not mean the lookup failed.

GET | POST

/api/listVehicles

Catalog-shaped listing feed — a compatibility alias for search.

Requires the details scope.

Parameters

manufacturer_slug / manufacturer / brandstring · query string or JSON body

Brand, under any of the three accepted spellings.

Example bmw·Where the value comes from /api/catalog/manufacturers -> results[].slug

model_group_slug / model_group / modelstring · query string or JSON body

Model group, under any of the three accepted spellings.

Example 320d·Where the value comes from /api/catalog/model-groups?manufacturer__slug=bmw -> results[].slug

fuel_type / fuelstring · query string or JSON body

Canonical fuel group.

Example Diesel·Where the value comes from /api/fuels -> fuels[]

steeringenum · query string or JSON body

Left- or right-hand drive.

Example left·Where the value comes from left | lhd | right | rhd — any other value is a 400.

min_year / max_yearinteger · query string or JSON body

Registration-year range.

Example 2018 / 2024·Where the value comes from Year bounds chosen by your user.

max_mileageinteger · query string or JSON body

Mileage ceiling.

Example 120000·Where the value comes from Mileage ceiling chosen by your user.

orderingstring · query string or JSON body

Sort order. A leading minus reverses it.

Example -created_at·Where the value comes from One of -created_at, price, -price, year, -year.

limit / offsetinteger · query string or JSON body

Or page_size / page. Default limit 50.

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

Example requests

Request
GET | POST https://api.thecarapi.com/api/listVehicles?manufacturer_slug=bmw&model_group_slug=320d&max_mileage=120000
GET | POST https://api.thecarapi.com/api/listVehicles?brand=audi&min_year=2019&ordering=price&limit=50

Example response

json
{
  "success": true,
  "vehicles": [],
  "results": [],
  "total": 210,
  "limit": 50,
  "offset": 0,
  "total_pages": 5,
  "max_page": 5
}

What you get back

vehicles / resultsobject[]

The same array under two keys, so either spelling works. Cards are augmented search result cards.

total / limit / offset / total_pages / max_pageinteger | null

Standard pagination fields, exactly as on /api/search.