---
title: "Fields by source"
description: "What each of the seven auction sources actually publishes — the condition-data coverage matrix, the source-specific traps, and how to write code that survives the differences."
canonical: "https://thecarapi.com/docs/fields-by-source"
contract_version: "2026-08-19"
api_base: "https://api.thecarapi.com"
source: "https://thecarapi.com/docs/fields-by-source.md"
---

# Fields by source

What each of the seven auction sources actually publishes — the condition-data coverage matrix, the source-specific traps, and how to write code that survives the differences.

Seven auction sources feed one API, and they do not publish the same things. A German wholesale platform ships a full inspection report and a DAT equipment catalogue; a Japanese export lot ships an auction inspection sheet and a condition grade; a Korean listing ships neither but carries a deep specification block. This page is the honest map of who gives you what, so you can decide what your product can promise before you build it.

> **The one rule that saves you the most work** — Read `vehicle_details` and never branch on `site_name`. That block is the layer that already reconciled these differences for you. Drop to `car_identification` only for the handful of source-specific values listed below that have no cross-source equivalent.

## Three layers of data

Every vehicle in the API is described at three levels of normalization. Knowing which layer a field lives on tells you immediately how portable it is.

| Layer | Where | Consistency | Use it for |
| --- | --- | --- | --- |
| **The common core** | Search result cards and the top level of both detail endpoints | Identical across all seven sources | Listings, filters, sorting, price display, countdowns — anything that has to work uniformly. |
| **The normalized detail block** | `vehicle_details` on `/api/auction/{site}/{id}` and `/api/car-details` | Same key names everywhere; **presence varies** by source | Condition, damages, documents, service history, equipment. Check for the key, do not assume it. |
| **The raw source map** | `car_identification` | Source-specific. Key names change with each upstream | The last mile — a value the source publishes that has no cross-source equivalent yet. |

The common core is guaranteed in the sense that the *field* is always in the contract; an individual value can still be `null` when a particular source does not publish it. `fuel_group`, for example, is empty for most Japanese lots — and a lot with no recorded fuel matches **every** `fuel` filter rather than none, so filtering by fuel never makes those lots unreachable.

## What each source gives you

Read this table before you scope a feature. "Sparse" is not a bug to report — it is what the auction house publishes.

| Source | What it is | Depth | What only it gives you |
| --- | --- | --- | --- |
| `auto1` | Europe's largest digital B2B wholesale marketplace | **Deep** — full `vehicle_details` | The richest equipment data in the API (DAT catalogue), paint-thickness measurements, wheel condition, structured damages with a summary and prior-damage history. |
| `openlane` | Pan-European ex-lease and fleet auctions | **Deep** — full `vehicle_details` | Per-damage free-text comments, typed report PDFs (internal damage, external damage, maintenance, battery health) and its own report index in `car_reports`. |
| `ecarstrade` | Belgian online auction house — ex-lease, ex-rental, dealer trade | **Deep** — full `vehicle_details` | **The only source with per-visit service history rows.** Also the only source publishing `estimated_value_eur`, and the only one running blind auctions. |
| `schadeautos` | Netherlands and Benelux salvage and repairable stock | Moderate | Salvage-focused fields: engine capacity, transmission, VAT/margin status, net and gross export pricing, narrative damage text. |
| `copart` | Copart Germany salvage and run-and-drive lots | Moderate | Run-and-drive signal, build-sheet series and special equipment, live lot bid dynamics. |
| `encar` | South Korea's dominant vehicle marketplace | Moderate — deep specs, shallow condition | A large specification and options block, photo counts grouped by type, and registration data. Condition and accident detail is thinner than the EU sources. |
| `japanauction` | Japanese export inventory pooled from USS, ARAI, AUCNET, BAYAUC and CAA | **Shallow** — expect `vehicle_details` sparse or absent | The auction inspection sheet images, the originating auction house, the lot number, a condition grade, and a published steering side. |

## Condition data: the coverage matrix

This is the table people actually need. It says which keys of `vehicle_details` you can expect from which source. Blank means the auction house does not publish it — the field is simply omitted, which is the normal case and not an error.

|  | `auto1` | `openlane` | `ecarstrade` | Other four |
| --- | --- | --- | --- | --- |
| `damages` (per panel) | Structured, with summary, count and prior damages | Structured, with a comment per damage | **Free text + flags only** — no per-panel list exists upstream | Sparse or absent |
| `inspection_reports` | One URL | Typed PDFs by `type_id` | Appraisal PDF + third-party link | — |
| `documents` | Service book + service-detail images | **None** — `paperwork` booleans only | Service-history PDF + appraisal links | — |
| `service_history` | Summary only | Summary only | **Per-visit rows** — the only source with them | — |
| `equipment` | DAT catalogue (richest) | Option list + accessories | Option list | Varies |
| `paperwork` | Partial | `COCAvailable`, `RegistrationDocsAvailable`, `IsV5Present`, `LicensePlate` | Partial | — |
| `estimated_repair_costs` | Yes | Yes | Yes | — |

> **Reports are links, never files** — Every inspection report and document is returned as a URL to the auction house. We never proxy or store the PDF. Fetch them yourself if you need them, and expect upstream links to expire. Reports are also per-car and optional — most listings carry none, so an empty or absent `inspection_reports` array is the normal case, not a pending fetch.

## Source-specific notes worth knowing

### eCarsTrade — blind auctions and the estimate

Most eCarsTrade auctions are **blind**: every bid is private, so no price is published anywhere and none is inferred. On such a lot `current_price`, `start_price` and `buy_now_price` are all `null` — and that is the correct, final answer, not a missing value to retry for.

What a blind lot often *does* carry is `estimated_value_eur`, the auction house's own valuation (its "eCT Estimation Price"). It is frequently the only number on the lot, which makes it tempting to render in a price slot. **Do not.** No bid is settled against it and no car is sold at it — a client that shows it as a price quotes customers a figure the auction will not honour. Label it explicitly as an estimate, and never sort or filter on it: it is `null` for every other source and for roughly 86% of eCarsTrade lots, so any ordering that uses it silently drops them.

```json
{
  "auction_id": 7479712,
  "site_name": "ecarstrade",
  "current_price": null,
  "start_price": null,
  "buy_now_price": null,
  "estimated_value_eur": 12000.0
}
```

_A blind lot. Every price field is null and that is final — the estimate is not a substitute._

### Japanese auctions — the price is an opening bid

A live Japanese lot has no hammer price until it closes, so `current_price` on `japanauction` is the **opening bid**, not a cost. Roughly a quarter of lots publish no opener at all, and a minority of the rest are nominal starters set far below what the car will fetch. Read it as a floor. `buy_now_price` is never set on this source, and best-value ranking will flag some of these lots optimistically as a result.

Two more differences: every lot carries the `JP` origin country, so `country=europe` excludes them by design — pass `country=JP` or `site=japanauction` to target them — and `/api/car-details?site=japanauction` takes the offer id/UUID rather than the numeric auction id, the same as `auto1`.

### OpenLane — report types

OpenLane classifies each report it publishes. `type` is the readable name and `type_id` the source's raw code.

| `type_id` | `type` | Appears in |
| --- | --- | --- |
| 1 | `internal_damage_report` | `inspection_reports` |
| 2 | `external_damage_report` | `inspection_reports` |
| 3 | `maintenance_records` | `inspection_reports` |
| 4 | `option_report` | `option_reports` |
| 5 | `battery_health_report` | `inspection_reports` |
| other | `report` | `inspection_reports` |

Auto1's single inspection report is normalized into the same list with type `inspection_report` and no `type_id`. eCarsTrade's appraisal links arrive under `documents` rather than here, because the source itself presents them as documents.

### Naming collisions to be aware of

The same word means different things upstream, which is precisely why the normalized block exists. A downloadable file is `Documents[]` on Auto1 but `ECarsTradeDocuments[]` on eCarsTrade — while `Documents` on OpenLane is a dictionary of paperwork **booleans** and not a file list at all. If you read `car_identification` directly, you own that problem. If you read `vehicle_details.documents`, you do not.

## Steering side

`steering` is `left` or `right` on every result card and both detail endpoints, and it is never `null` for a vehicle in our inventory. `japanauction` is the only source that publishes a steering field of its own; for every other source the side is read off the car's registration market — a car registered where traffic drives on the left (GB, IE, JP, CY, MT, AU, NZ, ZA, IN, TH, HK, SG) is `right`, everything else `left`.

Because every listing resolves to one side or the other, the two values partition the inventory: their counts sum to the unfiltered total. As a filter, `left`/`lhd` and `right`/`rhd` are equivalent spellings and anything else is a `400`. It is accepted by `/api/search`, `/api/top-offers`, `/api/listVehicles` and every facet endpoint — though on a facet endpoint it is computed live rather than read from the precomputed table, so it is slower than an unfiltered facet call.

## Writing code that survives the differences

```javascript
// Right: ask for the key, accept its absence, never branch on the source.
function conditionSummary(auction) {
  const d = auction.vehicle_details ?? {};

  return {
    // Present on auto1 and openlane; free text on ecarstrade; absent elsewhere.
    damages: d.damages ?? [],
    damageNotes: d.damage_comment ?? d.technical_issues ?? null,

    // ecarstrade is the only source with per-visit rows. Everyone else has a summary.
    serviceVisits: d.service_history ?? null,
    serviceSummary: d.service_history_summary ?? null,

    // Most listings carry no reports at all. Empty is normal, not an error.
    reports: d.inspection_reports ?? [],

    repairCost: d.estimated_repair_costs ?? null,
  };
}

// Wrong: this breaks the day a source is added, and hides data today.
if (auction.site_name === "auto1") { /* ... */ }
```

_The absence of a key is information about the auction house, not a failure of the request._

- **Never hardcode the source list.** Read it from `/api/sites` at startup. An unknown slug is a `400` naming the offender, so a stale hardcoded list turns a new source into a broken deploy.
- **Design for the shallowest source you serve.** If your product promises "full service history on every car", only eCarsTrade can keep that promise. Promise it where it exists and degrade gracefully where it does not.
- **Treat `car_identification` as unversioned.** Its keys follow each upstream's own naming and change when the upstream changes. Anything you depend on long-term should come from the common core or `vehicle_details`.
- **`details_pending: true` is not an error.** It means the detail payload has not been assembled yet. Poll rather than retrying in a tight loop, and render the card data you already have.
