TopLot API

v1 · Slice 1
Demo → | https://toplot.parsite.dev

TopLot REST API

Партнёрский API для подбора и анализа аукционных лотов Copart / IAAI. Возвращает рекомендации, расчёт landed cost для страны доставки, расшифровку VIN со статистикой продаж, и нормализованный каталог (марки → семейства → модели → body class / fuel / drive / transmission / damage).

Base URL
https://toplot.parsite.dev/v1
Версия
v1 · Slice 1
Формат
JSON · UTF-8
Авторизация
Bearer токен
Лимиты
не наложены

Авторизация

Все endpoint'ы (кроме /health) требуют Bearer-токена в заголовке Authorization. На Slice 1 токен один — общий internal-key для интеграции (multi-tenant и rotation придут в Slice 3).

Authorization: Bearer YOUR_API_KEY

Запрос без токена / с неверным → 401 unauthorized.

Формат ошибок

Любая ошибка приходит JSON-объектом с полями code, message и опциональным details:

{
  "code": "validation_error",
  "message": "invalid recommend payload",
  "details": { "issues": [
    { "path": "budget_max",
      "message": "Required" }
  ] }
}
code HTTP Когда
validation_error400тело не прошло Zod-валидацию
unauthorized401нет Bearer / неверный токен
not_found404ресурс не найден (например VIN/external_id)
rate_limited429апстрим-квота / RPS
internal_error500непредвиденная ошибка сервера

Quick start

Получить топ-5 рекомендованных лотов для квиза «Авто до $15k для Украины»:

curl -X POST https://toplot.parsite.dev/v1/recommend \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "budget_max": 15000,
    "country": "UA",
    "dest_country": "UA",
    "vehicle_kind": "car",
    "damage_appetite": "medium",
    "limit": 5
  }'
GET /v1/health

Liveness + dependency check. Не требует Bearer.

Ответ

{ "status": "ok", "db": "ok", "redis": "ok" }

Статус 200 — всё OK; 503 — один из бэкендов недоступен (`status: "degraded"`).

POST /v1/recommend

Главный endpoint — подбор лотов по профилю пользователя. Hard-filter + scoring + diversification + sell-tone copy. Если задан dest_country — каждая карточка возвращает landed_cost и фильтр бюджета применяется к landed-cost.

Тело запроса (Zod-валидация)

{
  // ── Бюджет (USD) ──
  "budget_max":          number   // ОБЯЗАТЕЛЬНО, max 500000 — верхняя планка
  "budget_min":          number?  // нижняя планка. Если НЕ задан → 0 (без нижнего
                                 //   порога — вся выдача до budget_max).
  "budget_includes_repair": bool  // default true. true → бюджет сверяется с
                                 //   total_to_drive (вкл. ремонт); false → total_landed
  "dest_country":        enum?    // EU 27 + UA + GE + AE/SA/LB/JO — для landed-cost
  "country":             enum     // "UA" | "PL" | "GE" | "KZ" (default "UA")
  "vehicle_kind":        enum     // car (default) | motorcycle | ... | any
  "limit":               number   // 1..100, default 20
  "offset":              number   // пагинация, default 0

  // ── Hard-фильтры марки / модели (заданы → только matching лоты) ──
  "make_ids":            number[]? // ★ ЖЁСТКИЙ фильтр марки — ТОЛЬКО эти make_id.
                                 //   id из GET /v1/catalog/makes. Для «только BMW»
                                 //   используйте ЭТО, а не preferred_makes (см. ниже).
  "preferred_families":  string[]? // жёсткий фильтр семейства, напр. ["3 Series","X5 Series"]
                                 //   (из GET /v1/catalog/families?make_id=…)
  "body_classes":        string[]? // sedan|suv|pickup|coupe|hatchback|wagon|van|convertible
  "body_class_ids":      number[]? // канонические id кузова
  "year_from":           number?
  "year_to":             number?

  // ── Hard-фильтры состояния ──
  "damage_appetite":     enum     // потолок severity: "minimal"≤2 | "medium"≤3 |
                                 //   "serious"≤4 | "flipper" (без потолка). default "medium"
  "damage_severity_min": number?  // НИЖНЯЯ граница severity 1..5 (отсекает почти целые)
  "title_statuses":      string[]? // clean | salvage | rebuilt | ...
  "run_drive_codes":     string[]? // runs_and_drives|engine_start|enhanced|stationary|untested
  "primary_damages":     string[]? // front | rear | side | hail | flood | ...
  "secondary_damages":   string[]?
  "fuels":               string[]? // gas | diesel | hybrid | electric | ...
  "drive_types":         (fwd|rwd|awd|4wd)[]?
  "transmissions":       (automatic|manual)[]?
  "mileage_max_km":      number?

  // ── Hard-фильтры источника ──
  "auctions":            ("copart"|"iaai")[]?
  "states":              string[]? // 2-буквенные коды штатов US

  // ── Soft-scoring (НЕ исключает, только ранжирование) ──
  "preferred_makes":     string[]? // +score boost. НЕ hard-filter — другие марки протекают!
  "excluded_makes":      string[]? // −score penalty

  // ── Квиз / legacy ──
  "salvage_attitude":    enum?    // "no" | "ok" | "undecided"
  "experience_level":    enum?    // "none" | "local" | "auction" | "pro"
  "red_flags":           string[]?
  "drive_pref":          enum?    // legacy single-select (drive_types предпочтительнее)
  "transmission_pref":   enum?    // legacy single-select
}
⚠️ Марка: make_ids vs preferred_makes
make_idsжёсткий фильтр: вернутся только эти марки. preferred_makesмягкий буст ранжирования: марка поднимается выше, но в выдачу попадают и другие. Для «только BMW» шлите "make_ids":[20] (id из /v1/catalog/makes). Аналогично preferred_families — жёсткий фильтр семейства.

Ответ

{
  "request_id": "rec_abc123",
  "scanned":    500,    // сколько лотов прошло hard-filter
  "scored":     487,    // сколько прошли scoring
  "latency_ms": 124,
  "lots": [
    {
      "external_id":              "39281047",
      "auction":                  "COPART",
      "year":                     2020,
      "make":                     "TOYOTA",
      "model":                    "RAV4",
      "series":                   "LE",
      "mileage_km":               45000,
      "current_bid":              4500,
      "buy_now_price":            null,
      "est_retail_value_usd":     12000,
      "photos":                   ["https://…/1.jpg", …],
      "title_status":             "salvage",
      "title_state":              "TX",
      "primary_damage":           "front",
      "damage_severity_structural": 2,
      "flip_score":               0.18,
      "vehicle_kind":             "car",
      "condition_label":          "good",
      "headline":                 "Свежий RAV4 с лёгкой передней частью",
      "highlights":               ["Хорошие фото", "Низкая severity", …],
      "considerations":           ["Salvage-title"],
      "economy":                  "По оценке +18% upside если правильный ремонт",
      "ideal_for":                "Семейный безопасный SUV для UA",
      "ai_deep_dive_url":         "/v1/lots/39281047/analyze",
      "match_score":              87,
      "landed_cost": {            // present когда задан dest_country
        "lot_price_usd":      4500,
        "auction_fees_usd":   595,
        "us_inland_usd":      400,
        "ocean_freight_usd":  1200,
        "port_fees_usd":      250,
        "customs_duty_usd":   685,
        "vat_usd":            1565,
        "excise_usd":         0,
        "total_landed_usd":   9195,
        "repair_estimate_usd": 1850,
        "total_to_drive_usd": 11045,
        "assumed": [],
        "warnings": []
      }
    }
  ]
}

Поведение бюджет-фильтра

Бюджет — это полная стоимость владения, не ставка. Финальный гейт: budget_min ≤ стоимость ≤ budget_max, где:

  • budget_min по умолчанию = 0 (если не передан) — без нижнего порога, вся выдача до budget_max. Пришлите явный budget_min, если нужен диапазон снизу.
  • стоимость = landed_cost.total_to_drive_usd (вкл. ремонт) при budget_includes_repair=true, иначе total_landed_usd.
  • без dest_country стоимость оценивается как predicted_sale × 1.7 (или ×1.4 без ремонта).
POST /v1/vin/lookup

Полный VIN-аналитический пакет в одном запросе: расшифровка VIN (NHTSA, cache-first) + резолв в каталог + статистика продаж модели/года + история этого конкретного VIN + наш прогноз цены продажи именно этого лота с учётом его damage / title / run-drive / severity + резерв продавца.

Тело запроса

{ "vin": "5UXKS4C57J0Z89920" }   // 17 символов, [A-Z0-9], I/O/Q не используются

Headers

Authorization: Bearer <INTERNAL_API_KEY>
Content-Type:  application/json

Структура ответа — основные блоки

Блок Что внутри
decodedРасшифровка VIN: year, make, model, trim, body_class, engine_l, fuel_primary, plant_country
canonicalРезолв в каталог: make_id, model_id, family
pricing.summaryГлавный блок для UI: median, min/max, p10/p90, predicted, reserve + готовые RU-строки
pricing.statisticalДетальная статистика модели/года (window, sample, percentiles + note_ru)
pricing.predictedПрогноз именно для активного лота этого VIN (если active): formula inputs + confidence
pricing.delta_pctРазница прогноза и медианы в % + RU-интерпретация
history.soldПрошлые продажи этого VIN (если есть)
history.activeТекущие активные лоты этого VIN
recommendationГотовое решение с narrative_ru + confidence + expected_range
debugcache_hit, upstream_fetched, decode_ms — для мониторинга

🎯 pricing.summary — для прямой вставки в UI

Самый часто используемый блок. Содержит 7 числовых полей + RU-лейблы + готовые formatted_ru строки (с долларами и форматированием).

"pricing": {
  "summary": {
    "median_usd":         6700,    // типичная цена продажи модели/года
    "range_min_usd":      1100,    // самая дешёвая продажа в окне
    "range_max_usd":     14800,    // самая дорогая
    "typical_low_usd":    3320,    // p10 — редко дешевле
    "typical_high_usd":  11100,    // p90 — редко дороже
    "predicted_sale_usd": 1424,    // наш прогноз для ЭТОГО лота (null если VIN не активен)
    "reserve_usd":        null,    // резерв продавца (null если не публикуется)
    "labels_ru": {
      "median":         "Медиана",
      "range":          "Диапазон (min — max)",
      "typical_range":  "Типовой диапазон (80% продаж)",
      "predicted_sale": "Наш прогноз цены продажи",
      "reserve":        "Резерв продавца"
    },
    "formatted_ru": {
      "median":         "Медиана: $6,700",
      "range":          "Диапазон: $1,100 … $14,800",
      "typical_range":  "Типовой диапазон: $3,320 … $11,100 (80% продаж)",
      "predicted_sale": "Наш прогноз: $1,424",
      "reserve":        null
    }
  }
}

📊 pricing.statistical — детальная разбивка по модели

"statistical": {
  "source":       "lots_sold_history",
  "year_band":    "2018",           // "2018" — per-year hit, или "all" — rollup
  "window_days":  30,                // 30 → 90 → 180 → 365 (narrowest with sample ≥ 10)
  "sample_size":  115,
  "fallback_used": false,           // true если использован year_band='all'
  "min_usd":      1100,
  "p10_usd":      3320,
  "median_usd":   6700,
  "mean_usd":     6909,
  "p90_usd":      11100,
  "max_usd":      14800,
  "note_ru":      "Средняя цена продажи 2018 года по 115 проданным лотам этой модели за последние 30 дней."
}

🎯 pricing.predicted — прогноз для конкретного лота

null когда этот VIN не присутствует в текущих active-лотах (используй statistical.median как ориентир).

"predicted": {
  "source":             "residual_value_model",
  "external_id":        "513240723",       // ID лота в нашей БД
  "lot_number":         "44869151",        // номер лота на аукционе
  "predicted_sale_usd": 1424,
  "confidence":         "high",            // high | medium | low
  "basis":              "upstream",        // 'upstream' или 'synthetic_price_stats'
  "inputs": {
    "title":             "parts_only",
    "primary_damage":    "front",
    "run_drive":         "stationary",
    "severity":          5,
    "est_retail_usd":    22042,
    "current_bid_usd":   6800,             // display-only, в скоринг не идёт
    "minimum_bid_usd":   null               // резерв продавца, null если не подтянут
  },
  "note_ru": "Наш прогноз цены продажи именно этого лота: 1424$. Считается из est_retail × мультипликаторов (title, damage, run_drive, severity)."
}

⚖ pricing.delta_pct / delta_note_ru

"delta_pct": -79,
"delta_note_ru": "Прогноз заметно НИЖЕ медианы — лот хуже типового (тотал / parts only / fire / etc)"
predicted / mediandelta_note_ru
> 1.3Прогноз заметно ВЫШЕ статистики — лот в лучшем состоянии чем типовой
1.1 – 1.3Прогноз слегка выше медианы — лот выше среднего
0.7 – 1.1Прогноз ≈ статистика — лот в типичном состоянии
0.5 – 0.7Прогноз ниже медианы — лот слабее среднего по модели
< 0.5Прогноз заметно НИЖЕ — лот хуже типового (тотал / parts only / fire)

📜 history — продажи и активные лоты этого VIN

"history": {
  "sold": [
    {
      "external_id": "513240723", "auction_name": "IAAI", "year": 2018,
      "make": "BMW", "model": "X5", "final_bid": 8700, "est_retail": 22042,
      "sold_at": "2026-05-05", "primary_damage": "Front End", "title_status": "parts_only"
    }
  ],
  "active": [
    {
      "external_id": "513...", "lot_number": "44869151", "status": "active",
      "auction_name": "IAAI", "current_bid": 6800, "buy_now_price": null,
      "minimum_bid": null, "est_retail": 22042,
      "predicted_sale_price_usd": 1424, "predicted_sale_source": "upstream",
      "predicted_sale_confidence": "high",
      "title_status": "parts_only", "primary_damage": "front",
      "run_drive": "stationary", "damage_severity_structural": 5
    }
  ]
}

🤖 recommendation — готовая рекомендация

"recommendation": {
  "expected_range_usd": [3320, 11100],     // p10 — p90 от статистики
  "most_likely_usd":    6700,              // median
  "confidence":         "high",            // high | medium | low | none
  "narrative_ru":       "BMW X5 2018 в среднем продаётся за $6700, диапазон…"
}

⚙ debug — телеметрия

"debug": {
  "cache_hit":       true,    // VIN был в нашем кэше декодинга
  "upstream_fetched": false,  // если true — мы дёрнули NHTSA upstream (медленнее)
  "decode_ms":       9        // время на расшифровку VIN
}

📐 Полный пример ответа

{
  "vin": "5UXKS4C57J0Z89920",
  "decoded": { "year": 2018, "make": "BMW", "model": "X5", "trim": "xDrive35d",
               "body_class": "SUV / MPV", "engine_l": 3.0, "fuel_primary": "Diesel" },
  "canonical": { "make_id": 20, "model_id": 138, "family": "X5 Series" },

  "pricing": {
    "summary": {  /* см. выше — главный блок для UI */ },
    "statistical": { /* медиана + percentiles + sample */ },
    "predicted": { /* per-lot прогноз с inputs */ },
    "delta_pct": -79,
    "delta_note_ru": "Прогноз заметно НИЖЕ медианы…"
  },

  "history": { "sold": [...], "active": [...] },
  "recommendation": { /* expected_range + narrative_ru */ },
  "debug": { "cache_hit": true, "upstream_fetched": false, "decode_ms": 9 }
}

❗ Ошибки

code HTTP Когда
validation_error400VIN не 17 символов или содержит I/O/Q
unauthorized401Нет / неправильный Bearer
vin_undecodable200decoded: null — NHTSA не вернул данных (всё остальное может быть пустым)
internal_error500ошибка нашей БД или upstream-таймаут

⚡ Latency

  • Cache-hit: ~50-150 мс (VIN был у нас в vin_decode_cache)
  • Cache-miss: ~300-1500 мс (нужно дёрнуть NHTSA upstream)
  • После первого запроса VIN навсегда в кэше — следующий вызов мгновенный

💡 Рекомендации по интеграции

  • Для простой страницы — биндись напрямую на pricing.summary.formatted_ru.*
  • Для богатого UI — рисуй gauge bar по summary.range_min_usd /range_max_usd с маркерами median_usd, predicted_sale_usd, reserve_usd
  • Если predicted_sale_usd = null — VIN не в active. Используй statistical.median_usd как ориентир.
  • Если reserve_usd > predicted_sale_usd — лот скорее всего не уйдёт на типовой ставке. Покажи предупреждение.
  • Cached VIN — можно вызывать в реальном времени на любой странице. Cache-miss — лучше показать loader.
GET /v1/analytics/model

Single-call аналитический пакет по модели: per-year статистика, монтхли-тренд за 12 месяцев, распределения damage / title / run-drive, аналоги в семействе И кросс-брендовые конкуренты (BMW X5 ↔ MB GLE ↔ Audi Q7).

Query параметры (один из):

GET /v1/analytics/model?vin=5UXKS4C57J0Z89920
GET /v1/analytics/model?model_id=138&year=2018

Структура ответа

Блок Что внутри
identitymake, model, family, year, canonical_model_id, make_id
statisticalprice_stats slice (min/p10/median/p90/max + sample_size + window)
current_lotТекущий активный лот этого VIN (если есть): predicted_sale, reserve, damage signals
monthly_trend12 месяцев продаж: median + count + by_auction split (copart vs iaai)
damageТоп-8 типов повреждений с % и median price
titleРаспределение title-статусов
run_driveРаспределение run-drive статусов
peersАналоги в том же семействе/марке
competitors_cross_makeКросс-брендовые конкуренты по курированной таксономии (18 сегментов рынка)

🏁 competitors_cross_make

Курированные группы конкурентов через брендов. Одна модель может быть в нескольких группах (Audi Q5 = премиум-средние ∩ премиум- компактные SUV). Поиск по year с fallback на ±1 год → all-year.

"competitors_cross_make": [
  {
    "group_id": 2,
    "slug": "premium-midsize-suv",
    "label_ru": "Премиум средние SUV",
    "label_en": "Premium midsize SUV",
    "segment": "luxury",               // luxury | premium | mainstream | economy | performance
    "description": "Средние премиум-кроссоверы, конкуренты BMW X5.",
    "models": [
      {
        "model_id": 245,
        "make": "INFINITI",
        "model": "QX60",
        "median_usd": 2750,
        "sample_size": 319,
        "is_this": false
      },
      {
        "model_id": 138,
        "make": "BMW",
        "model": "X5",
        "median_usd": 7800,
        "sample_size": 462,
        "is_this": true                // ← запрошенная модель
      },
      {
        "model_id": 312,
        "make": "MERCEDES-BENZ",
        "model": "GLE-CLASS",
        "median_usd": 9850,
        "sample_size": 286,
        "is_this": false
      }
      // ... остальные модели группы
    ]
  }
  // ... остальные группы (модель может быть в 1-3 группах)
]

Текущие сегменты (slug)

slugСегментlabel_ru
premium-large-suvluxuryПремиум большие SUV
premium-midsize-suvluxuryПремиум средние SUV
premium-compact-suvpremiumПремиум компактные SUV
premium-sedan-fullsizeluxuryПремиум большие седаны
premium-sedan-midsizeluxuryПремиум средние седаны
premium-sedan-compactpremiumПремиум компактные седаны
mainstream-midsize-sedanmainstreamCamry, Accord, Altima
mainstream-compact-sedaneconomyCivic, Corolla, Elantra
mainstream-compact-suvmainstreamCR-V, RAV4, Equinox
mainstream-midsize-suvmainstreamPilot, Highlander, Explorer
mainstream-large-suvmainstreamTahoe, Suburban, Expedition
pickup-full-1500mainstreamF-150, RAM 1500, Silverado
pickup-heavy-2500mainstreamF-250/350, RAM 2500/3500
pickup-midsizemainstreamTacoma, Colorado, Ranger
minivanmainstreamOdyssey, Sienna, Pacifica
sports-coupe-premiumperformance911, Corvette, R8, M-models
ev-mainstreammainstreamTesla 3/Y, Mach-E, Ioniq 5
ev-premiumluxuryTesla S/X, Taycan, e-tron

⚡ Latency / Кэширование

  • ~150-300 мс на запрос (7 параллельных SQL агрегатов + 1 lookup)
  • VIN → model_id resolve добавляет ~50 мс если VIN не в active
  • Идемпотентен — можно вызывать на каждый pageview

📊 Готовый iframe-виджет

<iframe
  src="https://toplot.parsite.dev/widget/sales?vin=5UXKS4C57J0Z89920&token=YOUR_TOKEN"
  width="800" height="700" frameborder="0">
</iframe>

Виджет рендерит 4 вкладки: 📈 Цена, 🔧 Состояние, 🚗 Аналоги, 🏁 Конкуренты.

POST /v1/cost/estimate

Расчёт landed cost для одного лота. Принимает либо external_id (lookup), либо inline-описание lot (what-if). Возвращает развёрнутый breakdown.

Тело запроса (один из двух вариантов)

// Вариант 1 — по external_id
{ "external_id": "513069925", "country": "UA" }

// Вариант 2 — inline lot
{
  "lot": {
    "price_usd":            8000,
    "auction_family":       "copart",         // "copart" | "iaai"
    "state_us":             "TX",
    "engine_displacement_l": 2.5,
    "year":                 2020,
    "fuel_code":            "ice",
    "vehicle_kind":         "car",
    "damage_severity_structural": 2,
    "damage_code":          "front",
    "make":                 "TOYOTA"
  },
  "country": "PL"
}

Поддерживаемые страны (country)

EU 27: AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE
Прочее: UA, GE, AE, SA, LB, JO

Ответ

{
  "country": "UA",
  "breakdown": {
    "lot_price_usd":      8000,
    "auction_fees_usd":   845,
    "us_inland_usd":      400,
    "ocean_freight_usd":  1200,
    "port_fees_usd":      250,
    "customs_duty_usd":   945,
    "vat_usd":            2140,
    "excise_usd":         304,
    "total_landed_usd":   14084,
    "repair_estimate_usd": 1425,
    "total_to_drive_usd": 15509,
    "assumed":  [],
    "warnings": [ "UA: 6-летний автомобиль…" ]
  }
}
POST /v1/lots/:externalId/analyze

AI deep-dive по лоту: Vision-анализ фото (Haiku) + verdict v2 (Sonnet) на русском. Cache-first: если у лота уже есть свежий verdict под текущий primary photo — возвращается без новой LLM-затраты.

Тело запроса

Пустое — всё нужное берётся из URL.

Ответ (сокращённо)

{
  "externalId": "39281047",
  "cached":     true,
  "vision": {
    "severity": 2,
    "affectedParts":      ["передний бампер","решётка радиатора"],
    "hiddenRiskFlags":    [],
    "structuralConcern":  false,
    "notes":              "…",
    "costUsd":            0.0012
  },
  "verdict": {
    "conditionLabel":   "good",
    "headline":         "…",
    "whatIsGood":       [ … ],
    "whatNeedsWork":    [ … ],
    "economySummary":   "…",
    "idealFor":         "…",
    "alternativesHint": "…",
    "costUsd":          0.018
  }
}

Каталог

Восемь endpoint'ов для построения квиза с каскадными фильтрами: kind → make → family → model, плюс body class / fuel / drive / transmission / damage с per-country statistics.

GET /v1/catalog/makes

Список марок, отфильтрованный по типу транспорта.

Query params

kind        car | truck_heavy | motorcycle | boat | trailer | recreational | industrial | any
            default "car"
min_share   0..1, default 0.5    // минимальная доля dominant_kind у марки
limit       1..500, default 200

Ответ

{
  "kind":  "car",
  "count": 84,
  "makes": [
    { "id": 11, "name": "FORD",   "dominant_kind": "car", "dominant_kind_share": 0.89, "active_lots": 19750 },
    { "id":  5, "name": "TOYOTA", "dominant_kind": "car", "dominant_kind_share": 0.99, "active_lots": 18058 },
    …
  ]
}
GET /v1/catalog/families

Семейства моделей внутри марки (например, BMW X1 / X3 / X5 / 3 Series / …). Inner-join на lots_normalized — пустых семейств не возвращаем.

Query params

make_id     int, обязательно
kind        как в /makes; default "any" (фильтрует на уровне лотов)

Ответ

{
  "make_id": 20, "kind": "car", "count": 13,
  "families": [
    { "family": "X5 Series", "model_count": 1,  "active_lots": 585 },
    { "family": "3 Series",  "model_count": 22, "active_lots": 953 },
    …
  ]
}
GET /v1/catalog/models

Конкретные модели (trim-level) внутри марки и/или семейства.

Query params

make_id     int, обязательно
family      string, опционально (e.g. "3 Series")
kind        как выше; default "any"

Ответ

{
  "make_id": 20, "family": "3 Series", "kind": "car", "count": 35,
  "models": [
    { "id":  64, "name": "328I",  "model_family": "3 Series", "active_lots": 412 },
    { "id": 143, "name": "330I",  "model_family": "3 Series", "active_lots": 168 },
    …
  ]
}
GET /v1/catalog/body-classes

NHTSA body classes (SUV / Sedan / Pickup / Hatchback / …) с UI-friendly короткими лейблами.

Query params

kind        default "car"
make_id     int, опционально
family      string, опционально

Ответ

{
  "kind": "car", "count": 12,
  "body_classes": [
    { "id":  3, "name": "SPORT UTILITY VEHICLE (SUV)/MULTI-PURPOSE VEHICLE (MPV)",
      "short_label": "SUV / MPV", "active_lots": 56356 },
    { "id":  2, "name": "SEDAN/SALOON",
      "short_label": "Sedan",     "active_lots": 50424 },
    …
  ]
}
GET /v1/catalog/fuel-types

5 канонических бакетов: ДВС / Гибрид / Электро / Газ / Гидроген (+ Неизв.).

Query params

kind          default "car"
make_id       опционально
family        опционально
body_class_id опционально

Ответ

{
  "kind": "car", "count": 6,
  "fuel_types": [
    { "code": "ice",      "label": "ДВС",     "active_lots": 137233 },
    { "code": "hybrid",   "label": "Гибрид",  "active_lots":   6610 },
    { "code": "electric", "label": "Электро", "active_lots":   2219 },
    …
  ]
}
GET /v1/catalog/drive-types

FWD / RWD / AWD / 4WD (+ unknown).

Query params

kind, make_id, family, body_class_id  — то же что выше

Ответ

{
  "kind": "car", "count": 5,
  "drive_types": [
    { "code": "rwd", "label": "RWD (задний)", "active_lots": 49373 },
    { "code": "fwd", "label": "FWD (передний)", "active_lots": 41780 },
    { "code": "4wd", "label": "4WD (полный с понижайкой)", "active_lots": 33450 },
    { "code": "awd", "label": "AWD (полный)", "active_lots": 20336 }
  ]
}
GET /v1/catalog/transmissions

Автомат / Механика (+ unknown).

{
  "kind": "car", "count": 3,
  "transmissions": [
    { "code": "automatic", "label": "Автомат",  "active_lots": 142399 },
    { "code": "manual",    "label": "Механика", "active_lots":   3222 }
  ]
}
GET /v1/catalog/damage-types

17 канонических кодов повреждения (см. справочник).

Query params

side          "primary" (default) | "secondary"
kind, make_id, family, body_class_id  — каскадно

Ответ

{
  "side": "primary", "kind": "car", "count": 17,
  "damages": [
    { "code": "front",   "label": "Перед", "active_lots": 62477 },
    { "code": "minor",   "label": "Мелкие / wear", "active_lots": 26493 },
    { "code": "side",    "label": "Бок",   "active_lots": 18705 },
    …
  ]
}

Справочники значений

vehicle_kind

Верхнеуровневый тип транспорта.

car | truck_heavy | motorcycle | boat | trailer | recreational | industrial | any | unknown

fuel_code

codeRU labelЧто включает
iceДВСGasoline + Diesel + Flex + "Other"
hybridГибридHEV / PHEV / Gasoline+Electric
electricЭлектроBEV (pure)
gasГазCNG / LPG / Natural Gas
hydrogenГидрогенFCEV
unknownNULL / Other

drive_type

fwd  (передний) | rwd (задний) | awd (полный) | 4wd (полный с понижайкой) | unknown

transmission

automatic (включая CVT/DCT/ECVT) | manual | unknown

damage_code

17 канонических бакетов повреждения:

front — Перед
rear — Зад
side — Бок
front_rear — Перёд + зад
all_over — Со всех сторон
rollover — Опрокидывание
undercarriage — Днище / рама
roof — Крыша
minor — Мелкие / wear
hail — Град
flood — Вода / потоп
fire — Огонь / выгорание
mechanical — Механика
theft — Кража / угон
vandalism — Вандализм
biohazard — Биоопасность
other — Прочее
unknown — Не указано

dest_country

38 поддерживаемых стран доставки:

РегионКоды (ISO 3166-1 alpha-2)
EU 27AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE
Восточная Европа / КавказUA, GE
Middle EastAE (ОАЭ), SA (Саудовская Аравия), LB (Ливан), JO (Иордания)

Heavy registration-tax: DK, FI, GR, MT, NL — отдельная строка excise_usd в landed-cost breakdown.