> ## Documentation Index
> Fetch the complete documentation index at: https://lmn.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Vehicles

> Browse the live Korean inventory and fetch full vehicle detail.

Three endpoints power partner discovery: filter values for dropdowns, paginated list, and single-vehicle detail.

## GET /v1/vehicles/facets

Returns distinct filter values currently in catalog. Cached 5 minutes.

```bash theme={null}
curl -H "x-api-key: $KEY" https://api.lmnauto.com/v1/vehicles/facets
```

Response is flat unique-value arrays — **no per-value counts** (UIs surface plain "Kia", not "Kia (1,234)"):

```json theme={null}
{
  "makes": ["Hyundai", "Kia", "Genesis", "Toyota", "Honda"],
  "models": {
    "Toyota": ["Camry", "RAV4", "Corolla"],
    "Hyundai": ["Sonata", "Tucson", "Palisade"]
  },
  "fuels": ["gasoline", "diesel", "hybrid", "electric", "lpg", "hydrogen", "gasoline_hybrid", "plug_in_hybrid"],
  "transmissions": ["auto", "manual", "cvt", "dct"],
  "sources": ["glovis", "sk", "aj", "lotte", "kcar", "dealer"],
  "as_of": "2026-04-15T21:50:00+09:00"
}
```

Optional query: `source` (CSV) to scope facets to a specific source set.

## GET /v1/vehicles

Paginated, filterable inventory list. Returns `VehicleSummary[]`.

### Filters

| Param                                     | Type          | Notes                                                                                                                                                                                                        |
| ----------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `keyword`                                 | string        | Free-text search across make/model/trim tokens.                                                                                                                                                              |
| `make`                                    | string CSV    | e.g., `Kia,Hyundai`.                                                                                                                                                                                         |
| `model`                                   | string CSV    | Requires `make`.                                                                                                                                                                                             |
| `body_style`                              | enum          | `van` — heuristic trim/model text filter for 2-seat/cargo variants such as Kia Morning Van.                                                                                                                  |
| `year_min` / `year_max`                   | integer       | Inclusive bounds.                                                                                                                                                                                            |
| `mileage_max_km`                          | integer       | Inclusive upper bound. (There is no `mileage_min_km`.)                                                                                                                                                       |
| `price_min_usd` / `price_max_usd`         | integer       | On `pricing.listing_price`.                                                                                                                                                                                  |
| `source`                                  | enum CSV      | `dealer \| glovis \| sk \| aj \| lotte \| kcar`. `dealer` proxies to a third-party retail inventory and carries its own constraints — see "Dealer source constraints" below before using it.                 |
| `fuel`, `transmission`                    | enum CSV      | `transmission` is applied to dealer rows via a post-filter. Multi-value `fuel` is dealer-dropped.                                                                                                            |
| `color`                                   | enum CSV      | Single value honored (multi-value is dropped). Applies to dealer and auction.                                                                                                                                |
| `accident_grade`, `exterior_grade`        | enum CSV      | `A \| B \| C \| D \| F`. Excludes dealer rows (null grade).                                                                                                                                                  |
| `options_include`                         | string CSV    | AND semantics — vehicle must have **all** listed options. Applied to dealer (`encar_*`) rows too, except `panoramic_sunroof` and `dashcam`, which return `400` for dealer — see "Dealer source constraints". |
| `auction_status`                          | enum CSV      | Exact auction result filter. One or more of `upcoming`, `sold`, `negotiation_sold`, `no_bid`, `negotiation_requested`. Excludes dealer rows.                                                                 |
| `auction_date_from` / `auction_date_to`   | ISO 8601 date | Excludes dealer rows.                                                                                                                                                                                        |
| `auction_count_min` / `auction_count_max` | integer       | Number of auction appearances (counts the current/upcoming round + all prior rounds for the same physical car). Excludes dealer rows when set.                                                               |
| `sort`                                    | enum          | See sort table below. Default `auction_date_asc`.                                                                                                                                                            |
| `cursor`, `limit`                         | pagination    | Composite cursor; default 50, max 200.                                                                                                                                                                       |

<Warning>
  **Unrecognized query params are silently ignored.** The server returns a 200 with default-filtered data instead of a 400. Common gotchas:

  * `page` / `perPage` — there is no offset pagination; use `cursor` + `limit`.
  * `fuel_type` — the param is `fuel` (singular). `fuel_type` is the BigQuery column name, not the API param.
  * `transmissions` (plural) — the FILTER param is `transmission` (singular). The plural form is the response field name in `GET /v1/vehicles/facets`.
  * `result` / `status` — use `auction_status` for auction result filtering.

  For a last-mile delivery use case, use:

  ```bash theme={null}
  GET /v1/vehicles?make=Kia&model=Morning&body_style=van&auction_status=upcoming
  ```

  `body_style=van` is currently a deterministic text heuristic over model/trim tokens (`van`, `cargo`, `2-seater`, Korean `밴`/`벤`) until upstream auction sources provide explicit seat/cargo metadata.

  If your client returns more rows than expected, double-check your param names against this table — the server isn't filtering by something it doesn't recognize.
</Warning>

### Sort

| Value                        | Meaning                                             |
| ---------------------------- | --------------------------------------------------- |
| `auction_date_asc` (default) | Closest auction first (decisions needing attention) |
| `price_asc` / `price_desc`   | Budget-driven browsing                              |
| `year_desc`                  | Newest first                                        |
| `mileage_asc`                | Lowest mileage first                                |

### Null-strict semantics

When you filter on a field that's null for dealer cars (`accident_grade`, `auction_date_*`, `auction_count_*`), dealer rows are silently excluded only when `source` is omitted entirely. Response includes `X-LMN-Filtered-Out: dealer=N` header so your UI can tell the dealer "42 dealer cars were hidden". When you explicitly request `source=dealer` together with one of these auction-only filters, the request returns `400 validation_error` instead (see Dealer source constraints below) — fail-fast rather than silent drop.

### Dealer source constraints

The `dealer` source is fulfilled by a live proxy to a third-party retail inventory (encar). Two design choices flow from that:

**Required:** `source=dealer` (alone or mixed with auction sources) requires `make`. `make` may be a CSV list, for example `Hyundai,Kia`; the API fans out to one upstream dealer request per manufacturer. `model` may also be CSV; for dealer rows the API fans out valid make/model pairs, for example `make=Hyundai,Kia&model=Avante,K5` becomes Hyundai Avante plus Kia K5 upstream searches. Without `make`, the request returns `400 validation_error` (`details.field: "make"`).

**Forbidden:** Combining `source=dealer` with any auction-only filter returns `400 validation_error`. The offending field is reported in `details.field`:

| Field                                     | Why forbidden with dealer                                          |
| ----------------------------------------- | ------------------------------------------------------------------ |
| `auction_status`                          | Dealer listings have no auction; the status concept doesn't apply. |
| `accident_grade` / `exterior_grade`       | Auction-house grading scale isn't published for dealer listings.   |
| `auction_date_from` / `auction_date_to`   | Dealer listings have no auction date.                              |
| `auction_count_min` / `auction_count_max` | Auction appearance count is auction-only.                          |

**Filter parity gaps (dealer-only):** A few filters supported on the auction side are silently dropped when applied to the dealer query because the upstream DSL doesn't support them: multi-value `fuel`, `keyword`, `body_style`. The auction half of a mixed request still honors these. (Note: `transmission` **is** applied to dealer rows via a post-filter, `color` is honored as a single value, and `options_include` is applied natively — see below.)

**`options_include` for dealer:** `options_include` **is applied** to dealer rows — it's translated to Encar's native `Options.` search DSL, with the same AND semantics as auction (a car must have **all** listed options). Two tokens are the exception: **`panoramic_sunroof`** and **`dashcam`** have no Encar filter equivalent, so a dealer request containing either returns `400 validation_error` (`details.field: "options_include"`, with the offending token named) rather than silently dropping it. This `400` is dealer-scoped — auction-only requests still accept every documented token — and is raised at validation time, so a **mixed** `source=glovis,dealer` request carrying one of these tokens returns `400` (not a degraded auction-only `200` with `X-LMN-Partial-Dealer-Unavailable`). Every other documented `options_include` token filters dealer rows normally. The full catalog of the 62 dealer-filterable tokens (and the 2 dealer-unsupported ones) is in [`options_include` for dealer (full catalog)](#options_include-for-dealer-full-catalog) below.

### `options_include` for dealer (full catalog)

<Note>Use the table below as the `options_include` token reference for dealer inventory filtering.</Note>

`options_include` is applied to `source=dealer` results **server-side** — each token is translated to Encar's native option facet, so dealer rows are filtered at the source rather than after the fact. Multiple values are **AND-combined**: a vehicle must have **all** requested options to match.

Tokens are **case-insensitive snake\_case** (`Sunroof`, `sunroof`, and `SUNROOF` are equivalent).

<Note>
  Two documented option tokens are **not available for dealer** and return `400 validation_error` (`details.field: "options_include"`, with the offending token named): **`panoramic_sunroof`** and **`dashcam`**. Encar's search filter exposes no facet for them. These two tokens still work for auction sources — the `400` is dealer-scoped (and applies to a mixed `source=glovis,dealer` request, since validation runs before the query fans out).
</Note>

The **62** tokens below are all filterable for dealer, grouped by category. Column `Token` is the value you pass in `options_include`; `Option` is the human-readable equipment name.

<Accordion title="Exterior & Interior (17)">
  | Token                       | Option                    |
  | --------------------------- | ------------------------- |
  | `sunroof`                   | Sunroof                   |
  | `hid_headlamps`             | HID Headlamps             |
  | `led_headlamps`             | LED Headlamps             |
  | `power_tailgate`            | Power Tailgate            |
  | `soft_close_doors`          | Soft-Close Doors          |
  | `folding_side_mirrors`      | Folding Side Mirrors      |
  | `alloy_wheels`              | Alloy Wheels              |
  | `roof_rack`                 | Roof Rack                 |
  | `heated_steering_wheel`     | Heated Steering Wheel     |
  | `power_adjustable_steering` | Power-Adjustable Steering |
  | `paddle_shifters`           | Paddle Shifters           |
  | `steering_wheel_controls`   | Steering Wheel Controls   |
  | `auto_dimming_mirror`       | Auto-Dimming Mirror       |
  | `hi_pass`                   | Hi-Pass (toll)            |
  | `power_door_lock`           | Power Door Lock           |
  | `power_steering`            | Power Steering            |
  | `power_windows`             | Power Windows             |
</Accordion>

<Accordion title="Safety (15)">
  | Token                    | Option                        |
  | ------------------------ | ----------------------------- |
  | `driver_airbag`          | Driver Airbag                 |
  | `passenger_airbag`       | Passenger Airbag              |
  | `side_airbags`           | Side Airbags                  |
  | `curtain_airbags`        | Curtain Airbags               |
  | `abs`                    | ABS                           |
  | `traction_control`       | Traction Control (TCS)        |
  | `stability_control`      | Stability Control (ESC)       |
  | `tire_pressure_monitor`  | Tire Pressure Monitor (TPMS)  |
  | `lane_departure_warning` | Lane Departure Warning (LDWS) |
  | `electronic_suspension`  | Electronic Suspension (ECS)   |
  | `parking_sensors_front`  | Front Parking Sensors         |
  | `parking_sensors`        | Rear Parking Sensors          |
  | `blind_spot_monitor`     | Blind Spot Monitor            |
  | `rear_camera`            | Rear Camera                   |
  | `around_view_monitor`    | 360° Around-View Monitor      |
</Accordion>

<Accordion title="Convenience & Multimedia (18)">
  | Token                      | Option                         |
  | -------------------------- | ------------------------------ |
  | `cruise_control`           | Cruise Control                 |
  | `adaptive_cruise`          | Adaptive Cruise Control        |
  | `hud`                      | Head-Up Display (HUD)          |
  | `electronic_parking_brake` | Electronic Parking Brake (EPB) |
  | `auto_ac`                  | Automatic Climate Control      |
  | `smart_key`                | Smart Key                      |
  | `keyless_entry`            | Keyless Entry                  |
  | `rain_sensor`              | Rain Sensor                    |
  | `auto_headlights`          | Auto Headlights                |
  | `rear_seat_curtain`        | Rear-Seat Sunshade             |
  | `rear_window_curtain`      | Rear-Window Sunshade           |
  | `navigation`               | Navigation                     |
  | `front_av_monitor`         | Front AV Monitor               |
  | `rear_av_monitor`          | Rear AV Monitor                |
  | `bluetooth`                | Bluetooth                      |
  | `cd_player`                | CD Player                      |
  | `usb_port`                 | USB Port                       |
  | `aux_port`                 | AUX Port                       |
</Accordion>

<Accordion title="Seats (12)">
  | Token                        | Option                      |
  | ---------------------------- | --------------------------- |
  | `leather_seats`              | Leather Seats               |
  | `power_seat_driver`          | Power Seat (Driver)         |
  | `power_seat_passenger`       | Power Seat (Passenger)      |
  | `power_seat_rear`            | Power Seats (Rear)          |
  | `heated_seats`               | Heated Seats (Front)        |
  | `heated_seats_rear`          | Heated Seats (Rear)         |
  | `memory_seats_driver`        | Memory Seat (Driver)        |
  | `memory_seats_passenger`     | Memory Seat (Passenger)     |
  | `ventilated_seats`           | Ventilated Seats (Front)    |
  | `ventilated_seats_passenger` | Ventilated Seat (Passenger) |
  | `ventilated_seats_rear`      | Ventilated Seats (Rear)     |
  | `massage_seats`              | Massage Seats               |
</Accordion>

**Not available for dealer (→ `400`):** `panoramic_sunroof`, `dashcam`.

<Note>
  Auction sources currently support the original option set. Full parity for the newly-added dealer tokens on the auction side is a separate follow-up — for the auction half of a query, treat the tokens above as best-effort until parity ships.
</Note>

**Example — AND semantics across two options:**

```bash theme={null}
# Only BMW dealer cars that have BOTH a sunroof AND ventilated front seats
curl -H "x-api-key: $KEY" \
  "https://api.lmnauto.com/v1/vehicles?source=dealer&make=BMW&options_include=sunroof,ventilated_seats"
```

A car must carry **every** requested token to appear in the result — adding more tokens narrows the set, never widens it.

### Mixed source — first page only

A mixed query like `source=glovis,dealer&make=Hyundai` works on the first page. Passing `cursor` together with mixed `source` returns `400 mixed_source_pagination_unsupported` — paginate each source separately when iterating deeper than one page.

When `sort=auction_date_asc` (the default), the response budget is split: half the `limit` is allocated to auction rows (sorted by date ascending) and half to dealer rows (sorted by `year` descending, since dealer listings have no auction date). Other sort options (`price_asc`, `price_desc`, `year_desc`, `mileage_asc`) sort across the merged result set directly.

### Dealer page limit

The dealer upstream caps page size at 48 regardless of the `limit` you request. When `limit > 48` and dealer is in scope, the dealer half is internally capped and the response includes `X-LMN-Dealer-Page-Max: 48`. Paginate dealer separately via `cursor` to retrieve more dealer rows.

### Dealer upstream unavailability

The dealer half depends on external upstreams (Encar and Danawa). Two failure modes:

* **Pure dealer request fails** (`source=dealer` only) → `503 dealer_upstream_unavailable` **only when every dealer source is down**. If just one source fails, you still get a `200 OK` with the surviving source's rows plus the `X-LMN-Partial-Dealer-Unavailable` header below.
* **Mixed request degrades** (`source=glovis,dealer`) → `200 OK` with the auction rows (and any surviving dealer rows) and an `X-LMN-Partial-Dealer-Unavailable: <csv>` header. The value is a comma-separated list of the failed dealer source names (`encar`, `danawa`, or `encar,danawa`) — **not** a flag. The auction half is still authoritative; retry the named dealer source(s) via a separate `source=dealer` query when you need them.

The detail endpoint maps the same way: `GET /v1/vehicles/encar_<id>` returns `503 dealer_upstream_unavailable` when the detail upstream is unreachable. `404 vehicle_not_found` means the dealer listing is no longer available to buy: either the upstream explicitly returned 404 for that ID, or the upstream detail page was still readable but marked the advertisement as `SOLD` or `WAIT` (both mean the listing is dead — Encar shows its own "sold or deleted" page for either) — **unless you have already created an order for that car**, in which case the detail keeps resolving from your stored order-time snapshot (`200`) instead of returning 404, so a vehicle you've purchased survives delisting. The snapshot is scoped to your partner account and the key's environment, so this recovery applies only to cars *you* ordered. Dealer detail also attempts Encar inspection enrichment. When the inspection page is reachable, `inspection_report` is populated — `dealer_inspection` carries frame/exterior damage counts, `body_condition.panels[]` carries any damaged panels, and `checklist[]` carries the EN-translated mechanical inspection. A **clean** car returns a populated report with zero damage and a populated checklist (not `null`). `inspection_report` and `body_condition` are `null` only when Encar has no inspection record for the car (upstream 404) or the secondary fetch fails transiently; the rest of the detail still returns.

### Response

```json theme={null}
{
  "data": [
    {
      "id": "01HXYZ111",
      "source": "glovis",
      "make": "Toyota",
      "model": "Camry",
      "trim": "LE Hybrid",
      "year": 2023,
      "mileage_km": 18500,
      "fuel": "hybrid",
      "auction_date": "2026-04-18T13:00:00+09:00",
      "order_cutoff_at": "2026-04-18T12:00:00+09:00",
      "thumbnail_url": "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260418/1064_2345/01.jpg",
      "pricing": {
        "listing_price": 14500,
        "sold_price": null,
        "discount_config": {
          "bid_threshold": 25000,
          "rate_below": 1.5,
          "rate_at_or_above": 2,
          "fixed_discount_amount": 0
        },
        "breakdown": {
          "auction_fee": 320,
          "dealer_fee": 0,
          "lmn_commission": 300,
          "ocean_freight": 1500,
          "estimated_landed": 16403
        }
      },
      "auction_result": "upcoming",
      "auction_count": 2
    }
  ],
  "next_cursor": "eyJpZCI6InZlaF8wMUhYWVoyMjIifQ=="
}
```

Full Vehicle schema in [Schemas](/schemas).

<Note>
  `id` / `vehicle_id` values are auction listing IDs. They can change when the same physical car is re-listed in a later auction round. LMN matches same-car history internally by Korean license plate; use `license_plate` from the detail response when you need to identify the physical car.
</Note>

## GET /v1/vehicles/\{id} — Detail

Returns the full Vehicle Detail — Summary fields plus VIN, photos, body condition diagram, full inspection report, and price breakdown.

### ID format

The `{id}` path parameter is either:

* An auction listing ID with one of the source prefixes: `glovis_…`, `sk_…`, `aj_…`, `lotte_…`, `kcar_…`. These are pulled from `GET /v1/vehicles` (the `id` field on each row).
* A dealer (encar) listing ID with the prefix `encar_<numeric>`. Detail for dealer IDs is served via a live proxy to the upstream; expect modestly higher latency than auction detail.

The `id` you pass back must match exactly what `GET /v1/vehicles` returned. The auction-prefix IDs are not permanent physical-car identifiers — the same car may receive a different ID when re-listed in another auction round. Use `license_plate` on detail responses when you need the physical-car identifier.

### Dealer detail caveats

Dealer detail responses differ from auction in three ways:

* `pricing.breakdown.auction_fee` is `0`; `pricing.breakdown.dealer_fee` is `300` (flat USD, not KRW-derived). `pricing.discount_config.fixed_discount_amount` is `300`, which offsets the dealer fee so net economic impact on `estimated_landed` is zero — `estimated_landed = listing_price + lmn_commission + ocean_freight`.
* `pricing.auction_fee_config`, `pricing.market_assessment`, `comparables.past_sales`, `comparables.upcoming_sales`, and `pricing.history` are all `null` or empty — these are auction-only concepts. (`body_condition` / `inspection_report` **are** populated for dealer when Encar has an inspection record — see the dealer-inspection note above; they are not auction-only.) `pricing.discount_config` is populated but the bid-based fields (`bid_threshold`, `rate_below`, `rate_at_or_above`) are all `0`.
* `404 vehicle_not_found` is returned when the dealer listing is no longer available to buy: the upstream either explicitly returns 404, or still serves a parseable detail page but marks the advertisement as `SOLD` or `WAIT`. **Exception:** if you have already created an order for that car, detail instead returns your stored order-time snapshot (`200`) and does not 404 — purchased vehicles survive delisting (snapshot scoped to your account + environment). Other failure modes (timeout, 5xx, unexpected response shape) surface as `503 dealer_upstream_unavailable` so callers can distinguish "removed/sold listing" from "transient upstream issue."

```bash theme={null}
# Auction detail
curl -H "x-api-key: $KEY" https://api.lmnauto.com/v1/vehicles/glovis_20260428_1069_2126

# Dealer detail
curl -H "x-api-key: $KEY" https://api.lmnauto.com/v1/vehicles/encar_41985016
```

### Response

```json theme={null}
{
  "id": "glovis_20260428_1069_2126",
  "source": "glovis",
  "make": "Hyundai",
  "model": "Palisade",
  "trim": "Calligraphy",
  "year": 2022,
  "mileage_km": 42180,
  "fuel": "gasoline",
  "transmission": "auto",
  "color": "White",
  "engine_cc": 3778,
  "drivetrain": "AWD",
  "options": ["sunroof", "leather_seats", "heated_seats", "360_camera"],
  "accident_grade": "A",
  "exterior_grade": "A",
  "auction_date": "2026-04-24T09:00:00+09:00",
  "order_cutoff_at": "2026-04-24T08:00:00+09:00",
  "thumbnail_url": "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260428/1069_2126/01.jpg",
  "pricing": {
    "listing_price": 14684,
    "sold_price": null,
    "auction_fee_config": {
      "percentage": 2.2,
      "minimum": 122,
      "maximum": 326
    },
    "discount_config": {
      "bid_threshold": 25000,
      "rate_below": 1.5,
      "rate_at_or_above": 2,
      "fixed_discount_amount": 0
    },
    "breakdown": {
      "auction_fee": 320,
      "dealer_fee": 0,
      "lmn_commission": 300,
      "ocean_freight": 1500,
      "estimated_landed": 16583
    },
    "history": [
      {
        "vehicle_id": "glovis_20260428_1069_2126",
        "auction_date": "2026-04-28",
        "price": 14684,
        "result": "upcoming"
      },
      {
        "vehicle_id": "lotte_20260421_9981_4412",
        "auction_date": "2026-04-21",
        "price": 14818,
        "result": "no_bid"
      }
    ],
    "market_assessment": {
      "label": "good",
      "comp_count": 7,
      "market_median": 16400,
      "diff_percent": 10.5,
      "explanation": "10.5% below market median ($16.4k, 7 comps over the past 4 weeks) · 0.9% drop over 2 rounds",
      "price_drop": { "rounds": 2, "drop_percent": 0.9 }
    }
  },
  "comparables": {
    "past_sales": [
      {
        "vehicle_id": "glovis_20260410_1063_2345",
        "vin": "KMHRXDXE8NU543210",
        "license_plate": "34나 5678",
        "trim": "Calligraphy",
        "year": 2022,
        "mileage_km": 39820,
        "accident_grade": "A",
        "exterior_grade": "A",
        "starting_price": 14200,
        "sold_price": 14850,
        "auction_date": "2026-04-10T09:00:00+09:00",
        "auction_result": "sold"
      }
    ],
    "upcoming_sales": [
      {
        "vehicle_id": "glovis_20260502_1063_9999",
        "vin": "KMHRXDXE8NU987654",
        "license_plate": "56다 9012",
        "trim": "Calligraphy",
        "year": 2022,
        "mileage_km": 41000,
        "accident_grade": "A",
        "exterior_grade": "A",
        "starting_price": 15100,
        "auction_date": "2026-05-02T09:00:00+09:00",
        "auction_result": "upcoming"
      }
    ]
  },
  "auction_result": "upcoming",
  "auction_count": 2,
  "vin": "KMHRXDXE8NU012345",
  "license_plate": "12가 3456",
  "photos": [
    "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260428/1069_2126/01.jpg",
    "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260428/1069_2126/02.jpg",
    "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260428/1069_2126/12.jpg"
  ],
  "photo_tags": [
    {
      "url": "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260428/1069_2126/01.jpg",
      "tag": "front"
    },
    {
      "url": "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260428/1069_2126/02.jpg",
      "tag": "side_l"
    },
    {
      "url": "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260428/1069_2126/12.jpg",
      "tag": "vin"
    }
  ],
  "body_condition": {
    "image_url": "https://storage.googleapis.com/lmnauto-auction-data/images/glovis/20260428/1069_2126/inspection.jpg",
    "panels": [
      {
        "panel_id": "rear-fender-l",
        "panel_type": "exterior",
        "damage_code": "w",
        "damage_codes": ["w"],
        "label": "Rear Fender (L)",
        "description": "Sheet Metal/Welding",
        "severity": "medium"
      }
    ]
  },
  "inspection_report": {
    "source": "glovis",
    "overall_grade": "A/8",
    "grade_description": "Accident grade / condition score",
    "accident_summary": "No structural damage",
    "has_accident": false,
    "has_frame_damage": false,
    "exterior_summary": "Minor sheet-metal repair on rear fender (L)",
    "accident_reason": null,
    "category_grades": [
      { "category": "engine", "status": "good" },
      { "category": "transmission", "status": "good" },
      { "category": "brake", "status": "good" }
    ],
    "checklist": [
      { "group": "engine", "item": "oil_leak", "result": "none" },
      { "group": "transmission", "item": "shift_quality", "result": "ok" }
    ],
    "accident_history": [],
    "accident_cost_summary": {
      "total_incidents": 1,
      "total_repair_cost": 420,
      "breakdown": { "parts": 180, "labor": 200, "paint": 40 },
      "insurance_paid": 420,
      "incidents": [
        { "date": "2019.06.12", "insurance_paid": 420, "repair_cost": 420 }
      ]
    },
    "issues": [
      {
        "category": "exterior",
        "status": "minor",
        "detail": "Rear Fender (L) — sheet metal/welding",
        "faults": ["w"],
        "type": "panel_damage"
      }
    ],
    "inspector_notes": "Clean overall; minor cosmetic wear consistent with mileage.",
    "inspection_sheet_url": null
  }
}
```

Key nullables:

* Unless explicitly documented otherwise, vehicle response monetary values are whole USD integers. This includes `pricing`, `comparables`, and `inspection_report.accident_cost_summary`.
* `pricing.breakdown.*` fields may be `null` individually when a cost component isn't yet finalized.
* `pricing.auction_fee_config` exposes the source/category fee percentage plus min/max caps converted to whole USD with the response FX snapshot. `percentage` is a percent value (`2.2` means 2.2%, not `0.022`). LMN calculates `pricing.breakdown.auction_fee` internally from source/category KRW rules, applies KRW caps, then converts to USD.
* `pricing.market_assessment` is `null` for dealer-source vehicles (no auction market to compare against).
* `comparables.past_sales` is sold-only and empty for dealer vehicles or when no matching sold comps exist in the past 4 weeks.
* `comparables.upcoming_sales` contains comparable future auction options and is empty when none exist. It does not include `sold_price`.
* `pricing.history` contains auction appearances for the same physical car, matched internally by Korean license plate across supported auction sources. Each `pricing.history[].vehicle_id` is the listing ID for that auction round and may differ from the current response `id`. It is empty when the car has no known prior/current auction appearances with a usable listed price.
* `body_condition` / `inspection_report` are populated for dealer-source vehicles when Encar has an inspection record; `null` only when the upstream inspection is missing (404) or the secondary fetch fails transiently.
* `body_condition.image_url` is returned only when LMN has a mirrored HTTPS image. Upstream auction-site image URLs are not exposed; use `panels[]` when `image_url` is `null`.
* `vin` and `license_plate` may be `null` for pre-auction listings.
* `fuel`, `transmission`, `color` may be `null` for rare upstream data gaps.

Auction grade and condition-tag descriptions are published at [Auction guide — Grades](https://lmnauto.com/en/auction/guide#grades).

### Pricing

Field-level reference for the `pricing` object — including `listing_price`, `sold_price`, `auction_fee_config`, `discount_config`, `breakdown` (with symmetric `auction_fee`/`dealer_fee` integers and post-discount `estimated_landed` notes), `history`, and `market_assessment` — lives in the Vehicle schema: [Schemas → Vehicle → `pricing`](/schemas#pricing). All monetary values inside `pricing` are whole USD integers.

`pricing.breakdown.estimated_landed` is the only field that's already post-discount; everything else (`listing_price`, `sold_price`, the line-item costs in `breakdown`) is gross. To get an exact landed total for your specific bid (rather than LMN's illustrative number against an internal basis price), use the recompute formula below.

### Recomputing landed cost for your bid

`estimated_landed` is a comparison aid, not a quote. For exact bid planning, recompute using your intended bid (all amounts in USD):

```
// 1. Auction fee — auction_fee_config.minimum / .maximum are already USD,
//    so the calculation stays in USD throughout.
fee_uncapped_usd     = your_bid_usd × auction_fee_config.percentage / 100
your_auction_fee_usd = clamp(fee_uncapped_usd,
                              auction_fee_config.minimum,
                              auction_fee_config.maximum)
your_auction_fee_usd = round(your_auction_fee_usd)    // half-up to whole USD

// 2. Vehicle discount (partner-specific; 0 for most partners)
//    When discount_config.vehicle_discount_pct > 0, discount the basis FIRST,
//    before adding fees. The bid-rate fields are 0 in this case — the vehicle
//    discount replaces them entirely (do not apply both).
discounted_basis = your_bid_usd × (1 − discount_config.vehicle_discount_pct / 100)

// 3. Bid-rate discount — only when vehicle_discount_pct is 0
//    (bid-rate fields are 0 when vehicle_discount_pct > 0, so this is a no-op then)
your_rate              = discounted_basis < discount_config.bid_threshold
                           ? discount_config.rate_below
                           : discount_config.rate_at_or_above
your_bid_rate_discount = ceil(discounted_basis × your_rate / 100)  // round up to whole USD
your_total_discount    = your_bid_rate_discount
                       + discount_config.fixed_discount_amount  // 0 when vehicle_discount_pct > 0

// 4. Landed total
your_landed_usd = discounted_basis
                + your_auction_fee_usd
                + lmn_commission     // 300
                + ocean_freight      // varies by body type + maker — read it from the
                                     // response; e.g. 1500 sedan-class, 1800 SUV-class/Benz
                − your_total_discount
```

<Note>
  `ocean_freight` is **not** a fixed constant. It is resolved per vehicle: Mercedes-Benz is 1800 for any body type; other makers are 1800 for SUV-class (SUV, minivan, van, truck) and 1500 for sedan-class (sedan, compact, wagon, coupe, convertible); an unknown body type uses 1500. Always read `pricing.breakdown.ocean_freight` from the response instead of hardcoding a value.
</Note>

**Rounding rules**

| Quantity                 | Rule                  |
| ------------------------ | --------------------- |
| `your_auction_fee_usd`   | Half-up to whole USD  |
| `your_bid_rate_discount` | Ceiling to whole USD  |
| `fixed_discount_amount`  | Already whole USD     |
| All other amounts        | Whole USD as returned |

**Caveats**

* \*\*FX rounding (±$1).** LMN internally computes the auction fee in KRW against the KRW source-of-truth fee schedule, then converts to USD at the response edge. Partners recomputing entirely in USD may see a ≤$1 difference vs. LMN's KRW-side math. The invoice is authoritative.
* **Planned bid vs. actual purchase price.** `your_bid_usd` is the partner's intended bid — typically a ceiling. At settlement, LMN recomputes auction fee and discount against the **actual hammer price** (`purchase_price_usd` on the order), which may be lower than `max_bid_amount_usd`. The invoice reflects what was actually won at, not the ceiling.
* **`listing_price` vs. internal basis.** The basis used for `estimated_landed` is `sold_price` if available, otherwise LMN's market-derived final-price estimate, otherwise the auction starting price. For unsold cars with no estimate this happens to equal `listing_price`, but `listing_price` itself does not drive the calculation in all cases.

### Similar-sales definition

The `comparables.past_sales` array surfaces up to **20** comparable cars that sold in the past **4 weeks**. The `comparables.upcoming_sales` array uses the same match rules but only includes future `upcoming` auction options.

| Dimension             | Match rule                                                                                                                                                                                                                        |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Make / model          | Exact (base model name)                                                                                                                                                                                                           |
| Trim                  | Not required to match — trim strings vary too much (e.g. BMW X1 carries long generation-qualified trims) and strict matching empties the comp set. Same make + model + year/mileage bounds already yield tightly comparable cars. |
| Model year            | ±1 year                                                                                                                                                                                                                           |
| Mileage               | ±20,000 km (≈ ±12,500 miles)                                                                                                                                                                                                      |
| Same physical vehicle | Excluded by license plate — a car re-listed across auctions is not counted twice                                                                                                                                                  |

Sort order is by auction date descending (most recent first). `past_sales` never includes `upcoming`; future alternatives are returned only in `upcoming_sales`.

These defaults match LMN's internal "Market Comparison" logic shown in the web UI, so the partner API returns the same comp set an LMN operator would see for the same vehicle.

### Market assessment (`pricing.market_assessment`)

A derived server-side summary so you don't have to compute comp medians client-side. Runs on the `comparables.past_sales` set (sold comps only) and compares their **starting-price** median to your current listed/estimated price.

| `label`   | Rule                       | What it means                             |
| --------- | -------------------------- | ----------------------------------------- |
| `great`   | Listing ≥ 15% below median | Strong buy signal                         |
| `good`    | 5–15% below median         | Reasonable buy                            |
| `fair`    | Within ±5% of median       | At market                                 |
| `wait`    | > 5% above median          | Priced high; consider waiting             |
| `limited` | Fewer than 3 valid comps   | Assessment unreliable; decide on your own |

`diff_percent` is the % the current listed/estimated price is **below** (positive) or **above** (negative) the comp median. `price_drop`, when present, reports how the same vehicle's starting price has moved across prior auction rounds — useful in combination with the label (a `good` + 2-round drop is a different signal than `good` + first appearance).

<Note>
  This is an **advisory** signal, not a valuation guarantee. It reflects starting prices of comps in the `past_sales` window, not expected auction-day outcomes. Always apply your own deal logic on top.
</Note>

### Errors

| Error                   | When                                                                                                                                           |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `404 vehicle_not_found` | Unknown ID, wrong environment, or a dealer (`encar_*`) detail page whose upstream advertisement is no longer active / marked `SOLD` or `WAIT`. |

Full `Vehicle` schema in [Schemas](/schemas).
