{
  "openapi": "3.1.0",
  "info": {
    "title": "TheCarApi — Public API",
    "version": "2026-08-19",
    "summary": "Multi-source vehicle auction inventory API",
    "description": "Normalized vehicle auction inventory from Auto1, OpenLane, Schadeautos, Copart Germany,\neCarsTrade, Encar and the Japanese auction houses, plus a European retail classifieds network.\n\nA vehicle is addressed by the pair site_name + auction_id, for example encar/38112900.\nEvery response carries contract_version, request_id, server_time and data_updated_at.\nPrice fields are JSON numbers, never strings.\n\nFull documentation: https://thecarapi.com/docs",
    "contact": {
      "name": "TheCarApi API support",
      "email": "api@thecarapi.com",
      "url": "https://thecarapi.com/contact"
    },
    "termsOfService": "https://thecarapi.com/terms"
  },
  "servers": [
    {
      "url": "https://api.thecarapi.com",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "API reference",
    "url": "https://thecarapi.com/docs"
  },
  "tags": [
    {
      "name": "Search & discovery",
      "description": "Search live and archived auction inventory, then resolve lightweight full-text matches.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/search"
      }
    },
    {
      "name": "Filter facets",
      "description": "Discover live filter values and counts. Facet responses cache for about 600 seconds. A filter sidebar can read every flat dimension in one call with /api/facets.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/facets"
      }
    },
    {
      "name": "Catalog",
      "description": "Build slug-addressable manufacturer and model-group navigation.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/catalog"
      }
    },
    {
      "name": "SEO helpers",
      "description": "Build popular landing pages and resolve brand/model URL slugs.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/seo"
      }
    },
    {
      "name": "Auctions & history",
      "description": "Retrieve source-aware listing detail, galleries, price changes, and VIN history. A running openlane or ecarstrade auction has its bid refreshed from the auction house while the request is served — nothing needs to be passed to enable it.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/auctions"
      }
    },
    {
      "name": "Vehicle details",
      "description": "Fetch a full source payload from cache or, when needed, from the upstream source.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/car-details"
      }
    },
    {
      "name": "Top offers",
      "description": "Live auctions our pipeline judged to be priced below their market reference. Same deals as /api/search?sort=top_offers, but each card additionally carries the reference the verdict was made against.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/top-offers"
      }
    },
    {
      "name": "European classifieds",
      "description": "A retail price surface of roughly 9.8M live listings 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: theparking — that is the scope name in the path, not the name of a source.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/theparking"
      }
    },
    {
      "name": "Market intelligence",
      "description": "Precomputed price snapshots for a brand, model, and year window.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/market"
      }
    },
    {
      "name": "Import calculator",
      "description": "Estimate the landed cost of importing a vehicle. These are estimates, not a binding quote.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/calculator"
      }
    },
    {
      "name": "Health & contract",
      "description": "Check service dependencies and inspect the API index.",
      "externalDocs": {
        "url": "https://thecarapi.com/docs/ops"
      }
    }
  ],
  "paths": {
    "/api/search": {
      "get": {
        "operationId": "get_api_search",
        "summary": "Primary filtered search over live auction inventory.",
        "description": "Primary filtered search over live auction inventory.\n\nReuse random_seed through seed to keep randomized pagination stable. site accepts auto1, japanauction (the Japanese auction houses), copart, ecarstrade, encar, openlane or schadeautos — the European classifieds network is not a site value. Both site and site_exclude take a comma-separated, case-insensitive list; an unknown slug on either is a 400 naming the offender, and passing both narrows the include list by the exclusion. An unfiltered search can page to any depth; a filtered search is bounded by a per-query timeout rather than a hard offset.\n\nResponse fields — results[] (object[]): Search result cards. The full allowlisted field set is in the data dictionary; fields are present when the source provides them. total (integer | null): Total matching rows. Null when include_total=false or totals are suppressed. limit / offset (integer): The window that was actually applied, echoed back. total_pages / max_page (integer | null): Total pages, and the deepest page reachable under the depth policy. random_seed (string | null): Non-null only when the effective sort is random. Pass it back as seed= to page through the same ordering. contract_version (string): Schema contract the response was built against. request_id / server_time / data_updated_at (string): Correlation id (also X-Request-ID), response time, and when the underlying data was last refreshed.",
        "tags": [
          "Search & discovery"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/search?brand=bmw&fuel=Diesel&year_from=2018&sort=price_low&limit=24",
          "GET https://api.thecarapi.com/api/search?site=encar&country=KR&buy_now=true&page=2&page_size=20"
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Free-text brand, model, or keyword query. Value comes from: Free text entered by your user.",
            "schema": {
              "type": "string"
            },
            "example": "BMW 320d"
          },
          {
            "name": "site",
            "in": "query",
            "required": false,
            "description": "Comma-separated source slugs, OR within the parameter. Case-insensitive. An unknown slug is a 400 naming the offender — one bad member rejects the whole list. Value comes from: /api/sites -> sites[].name",
            "schema": {
              "type": "string"
            },
            "example": "encar"
          },
          {
            "name": "site_exclude",
            "in": "query",
            "required": false,
            "description": "Comma-separated source slugs to leave out. Sent alongside site, it narrows the include list; excluding everything you included is a 400, not an empty page. Value comes from: /api/sites -> sites[].name",
            "schema": {
              "type": "string"
            },
            "example": "copart"
          },
          {
            "name": "brand",
            "in": "query",
            "required": false,
            "description": "Brand display name, slug, or brand_id. Value comes from: /api/brands -> brands[].slug (or id/name)",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "description": "Model name or slug. Value comes from: /api/models?brand=bmw -> models[].slug",
            "schema": {
              "type": "string"
            },
            "example": "320d"
          },
          {
            "name": "year_from",
            "in": "query",
            "required": false,
            "description": "Registration-year range. Value comes from: /api/years -> years[]",
            "schema": {
              "type": "integer"
            },
            "example": "2018"
          },
          {
            "name": "year_to",
            "in": "query",
            "required": false,
            "description": "Registration-year range. Value comes from: /api/years -> years[]",
            "schema": {
              "type": "integer"
            },
            "example": "2018"
          },
          {
            "name": "fuel",
            "in": "query",
            "required": false,
            "description": "Canonical fuel group, matched whole. Hybrid, Mild Hybrid and Plug-in Hybrid are three separate groups — fuel=Hybrid returns full hybrids only. A lot with no recorded fuel matches every fuel filter rather than none, so it stays reachable. Value comes from: /api/fuels -> fuels[]",
            "schema": {
              "type": "string"
            },
            "example": "Diesel"
          },
          {
            "name": "gearbox",
            "in": "query",
            "required": false,
            "description": "Canonical gearbox group. Value comes from: /api/gearboxes -> gearboxes[]",
            "schema": {
              "type": "string"
            },
            "example": "Automatic"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "vehicle_type",
            "in": "query",
            "required": false,
            "description": "cars or suvs & trucks. Value comes from: Choose from the documented vehicle_type enum.",
            "schema": {
              "type": "string"
            },
            "example": "cars"
          },
          {
            "name": "body_style",
            "in": "query",
            "required": false,
            "description": "Body-style filter. Value comes from: Your application's normalized body-style value.",
            "schema": {
              "type": "string"
            },
            "example": "sedan"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Left- or right-hand drive. left/lhd and right/rhd are equivalent spellings. Every listing resolves to one side or the other, so the two values partition the inventory and their counts sum to the unfiltered total. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          },
          {
            "name": "kilometers_from",
            "in": "query",
            "required": false,
            "description": "Mileage range. Value comes from: Mileage range chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "0"
          },
          {
            "name": "kilometers_to",
            "in": "query",
            "required": false,
            "description": "Mileage range. Value comes from: Mileage range chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "0"
          },
          {
            "name": "horsepower_from",
            "in": "query",
            "required": false,
            "description": "Horsepower range. Value comes from: Horsepower range chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "150"
          },
          {
            "name": "horsepower_to",
            "in": "query",
            "required": false,
            "description": "Horsepower range. Value comes from: Horsepower range chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "150"
          },
          {
            "name": "price_from",
            "in": "query",
            "required": false,
            "description": "Public EUR price range. Value comes from: EUR budget chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "10000"
          },
          {
            "name": "price_to",
            "in": "query",
            "required": false,
            "description": "Public EUR price range. Value comes from: EUR budget chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "10000"
          },
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Return damaged or broken vehicles only. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Return Buy-Now listings only. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "ending_soon",
            "in": "query",
            "required": false,
            "description": "Return auctions ending within about two hours. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "smart_filter",
            "in": "query",
            "required": false,
            "description": "top_offers, low_mileage, or best_value. Value comes from: Choose from the documented smart_filter enum.",
            "schema": {
              "type": "string"
            },
            "example": "best_value"
          },
          {
            "name": "is_active",
            "in": "query",
            "required": false,
            "description": "Default true: lots whose auction has closed are hidden. false shows closed lots in addition to live ones — it does not return only ended lots, and it is not a filter on the is_active response field. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "false"
          },
          {
            "name": "include_ended",
            "in": "query",
            "required": false,
            "description": "The same switch inverted: include_ended=true equals is_active=false. Default false. If both are sent, include_ended wins. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "false"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort value from the conventions section. Value comes from: Choose from the documented Sort enum.",
            "schema": {
              "type": "string"
            },
            "example": "price_low"
          },
          {
            "name": "seed",
            "in": "query",
            "required": false,
            "description": "Stable random seed, up to 64 URL-safe characters. Value comes from: Previous search response -> random_seed",
            "schema": {
              "type": "string"
            },
            "example": "k9f2ab"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, maximum 100. Default 100. Value comes from: Page size chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "24"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "description": "Page size, maximum 100. Default 100. Value comes from: Page size chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "24"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Offset-based or page-based pagination. Value comes from: Current page state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "24"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Offset-based or page-based pagination. Value comes from: Current page state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "24"
          },
          {
            "name": "include_total",
            "in": "query",
            "required": false,
            "description": "Set false to skip the count. Default true. Value comes from: Your performance/display choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "false"
          },
          {
            "name": "count_only",
            "in": "query",
            "required": false,
            "description": "Return counts without result rows. Value comes from: Your response-mode choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "results": [
                    {
                      "auction_id": 38112900,
                      "site_name": "encar",
                      "clean_make": "BMW",
                      "clean_model": "320d",
                      "registration_year": 2020,
                      "mileage": 45000,
                      "public_price_eur": 21500,
                      "thumbnail_url": "https://cdn.example/photo.webp"
                    }
                  ],
                  "total": 18342,
                  "limit": 24,
                  "offset": 0,
                  "total_pages": 764,
                  "max_page": 764,
                  "random_seed": "k9f2ab",
                  "contract_version": "2026-08-19"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/search/auction-ids": {
      "get": {
        "operationId": "get_api_search_auction_ids",
        "summary": "Resolve a free-text query to matching auction ids only.",
        "description": "Resolve a free-text query to matching auction ids only.\n\nUse this to pre-filter, then hydrate each id through the auction detail routes. Returns an empty list when full-text search is disabled server-side.",
        "tags": [
          "Search & discovery"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/search/auction-ids?q=bmw%20320d",
          "GET https://api.thecarapi.com/api/search/auction-ids?q=kia%20ev6"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text query. An empty query returns an empty list. Value comes from: Free text entered by your user.",
            "schema": {
              "type": "string"
            },
            "example": "bmw 320d touring"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "auction_ids": [
                    "encar:38112900",
                    "auto1:AB12CD"
                  ],
                  "found": 2
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/facets": {
      "get": {
        "operationId": "get_api_facets",
        "summary": "Every flat facet dimension in one request instead of six.",
        "description": "Every flat facet dimension in one request instead of six.\n\nEvery filter accepted by the individual facet endpoints applies here, per field, exactly as its own endpoint would apply it. The per-dimension endpoints below are unchanged and stay fully supported — this is an additional way to read the same data. Scope search, the same scope that already grants them, and the fan-out bills one quota unit rather than six.\n\nResponse fields — brands / years / fuels / countries / gearboxes / sites (array): Each field is its own endpoint’s payload merged verbatim — countries still ships country_details alongside it, and no field gains or loses counts by being requested here. errors (object): Present only when a dimension could not be served: { field: reason }. Every other field is still returned, so one slow dimension cannot blank a filter sidebar.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/facets?fields=brands,fuels,gearboxes&country=DE",
          "GET https://api.thecarapi.com/api/facets?fields=brands,years,sites&damaged=true"
        ],
        "parameters": [
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated subset of brands, years, fuels, countries, gearboxes, sites. Defaults to all of them. models is not available here — it is brand-scoped and stays at /api/models. Value comes from: The dimensions your sidebar actually renders.",
            "schema": {
              "type": "string"
            },
            "example": "brands,fuels,gearboxes"
          },
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Restrict to left- or right-hand-drive vehicles. Slower than an unfiltered facet call, because it is computed live rather than read from the precomputed facet table. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "brands": [
                    {
                      "id": 12,
                      "name": "BMW",
                      "slug": "bmw",
                      "count": 3266
                    }
                  ],
                  "fuels": [
                    "Diesel",
                    "Petrol"
                  ],
                  "gearboxes": [
                    "Automatic",
                    "Manual"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/brands": {
      "get": {
        "operationId": "get_api_brands",
        "summary": "List brands with round-trippable slugs and live inventory counts.",
        "description": "List brands with round-trippable slugs and live inventory counts.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/brands?search=bm&ordering=-count&limit=20",
          "GET https://api.thecarapi.com/api/brands?country=DE&damaged=true"
        ],
        "parameters": [
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Restrict to left- or right-hand-drive vehicles. Slower than an unfiltered facet call, because it is computed live rather than read from the precomputed facet table. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Substring filter on brand name. Value comes from: Free text entered by your user.",
            "schema": {
              "type": "string"
            },
            "example": "bm"
          },
          {
            "name": "ordering",
            "in": "query",
            "required": false,
            "description": "name, -name, count, or -count. Value comes from: Choose name, -name, count, or -count.",
            "schema": {
              "type": "string"
            },
            "example": "-count"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of values. Value comes from: Result count chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "brands": [
                    {
                      "id": 12,
                      "name": "BMW",
                      "slug": "bmw",
                      "count": 1543
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/models": {
      "get": {
        "operationId": "get_api_models",
        "summary": "List models for one brand with live inventory counts.",
        "description": "List models for one brand with live inventory counts.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/models?brand=bmw&ordering=-count",
          "GET https://api.thecarapi.com/api/models?brand=12&search=x&country=DE"
        ],
        "parameters": [
          {
            "name": "brand",
            "in": "query",
            "required": true,
            "description": "Brand name, slug, or brand_id. Value comes from: /api/brands -> brands[].slug (or id/name)",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Restrict to left- or right-hand-drive vehicles. Slower than an unfiltered facet call, because it is computed live rather than read from the precomputed facet table. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Substring filter on model name. Value comes from: Free text entered by your user.",
            "schema": {
              "type": "string"
            },
            "example": "x"
          },
          {
            "name": "ordering",
            "in": "query",
            "required": false,
            "description": "name, -name, count, or -count. Value comes from: Choose name, -name, count, or -count.",
            "schema": {
              "type": "string"
            },
            "example": "-count"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "models": [
                    {
                      "name": "320d",
                      "slug": "320d",
                      "count": 210
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/years": {
      "get": {
        "operationId": "get_api_years",
        "summary": "List registration years available in current inventory.",
        "description": "List registration years available in current inventory.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/years?country=DE",
          "GET https://api.thecarapi.com/api/years?damaged=true&buy_now=true"
        ],
        "parameters": [
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Restrict to left- or right-hand-drive vehicles. Slower than an unfiltered facet call, because it is computed live rather than read from the precomputed facet table. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "years": [
                    2024,
                    2023,
                    2022,
                    2021
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/fuels": {
      "get": {
        "operationId": "get_api_fuels",
        "summary": "List canonical fuel groups available in current inventory.",
        "description": "List canonical fuel groups available in current inventory.\n\nSix groups, and the three hybrid kinds are distinct: Hybrid (full hybrid), Mild Hybrid (48V assist, cannot drive on the motor alone) and Plug-in Hybrid. The fuel filter matches a group whole, so fuel=Hybrid returns full hybrids only. To catch every electrified car, send all three.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/fuels?country=DE",
          "GET https://api.thecarapi.com/api/fuels?buy_now=true"
        ],
        "parameters": [
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Restrict to left- or right-hand-drive vehicles. Slower than an unfiltered facet call, because it is computed live rather than read from the precomputed facet table. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "fuels": [
                    "Diesel",
                    "Electric",
                    "Hybrid",
                    "Mild Hybrid",
                    "Petrol",
                    "Plug-in Hybrid"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/gearboxes": {
      "get": {
        "operationId": "get_api_gearboxes",
        "summary": "List canonical gearbox groups available in current inventory.",
        "description": "List canonical gearbox groups available in current inventory.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/gearboxes?country=KR",
          "GET https://api.thecarapi.com/api/gearboxes?damaged=true"
        ],
        "parameters": [
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Restrict to left- or right-hand-drive vehicles. Slower than an unfiltered facet call, because it is computed live rather than read from the precomputed facet table. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "gearboxes": [
                    "Automatic",
                    "Manual"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/countries": {
      "get": {
        "operationId": "get_api_countries",
        "summary": "List vehicle-location countries and display names.",
        "description": "List vehicle-location countries and display names.\n\ncountry=europe means \"every origin that is not overseas\" and is implemented as an exclusion, not a list: it currently excludes KR (Encar) and JP (the Japanese auction houses), and rows with no recorded country are treated as European and included. If you need strict membership, pass explicit ISO codes instead.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/countries?buy_now=true",
          "GET https://api.thecarapi.com/api/countries?damaged=true"
        ],
        "parameters": [
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Restrict to left- or right-hand-drive vehicles. Slower than an unfiltered facet call, because it is computed live rather than read from the precomputed facet table. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "countries": [
                    "DE",
                    "JP",
                    "KR",
                    "NL"
                  ],
                  "country_details": [
                    {
                      "code": "DE",
                      "name": "Germany"
                    },
                    {
                      "code": "JP",
                      "name": "Japan"
                    },
                    {
                      "code": "KR",
                      "name": "South Korea"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/sites": {
      "get": {
        "operationId": "get_api_sites",
        "summary": "List auction source slugs with live inventory counts.",
        "description": "List auction source slugs with live inventory counts.\n\nThis is the discovery endpoint for both /api/search?site= and /api/auction/{site}/{id}. Counts here respect every other filter on the request but ignore site / site_exclude themselves — a facet that filtered by its own dimension could only ever return the sources you already named. The European classifieds network is retail data, not auction inventory, so it never appears here; it has its own endpoint group.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/api/sites?buy_now=true",
          "GET https://api.thecarapi.com/api/sites?damaged=true"
        ],
        "parameters": [
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict counts to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict counts to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "sites": [
                    {
                      "id": 1,
                      "name": "encar",
                      "count": 9021
                    },
                    {
                      "id": 2,
                      "name": "openlane",
                      "count": 4110
                    },
                    {
                      "id": 3,
                      "name": "ecarstrade",
                      "count": 3187
                    },
                    {
                      "id": 4,
                      "name": "japanauction",
                      "count": 1642
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/load-models": {
      "get": {
        "operationId": "get_load_models",
        "summary": "Return the complete model catalog grouped by brand.",
        "description": "Return the complete model catalog grouped by brand.\n\nThis response is shaped differently from every other endpoint in the API: the body IS the map. Every key is a brand name and every value is that brand list of models — there is no wrapper object, no success flag and no contract metadata, because the keys are data and nothing else may share that namespace. Read the correlation id from the X-Request-ID header instead. An error response IS wrapped and does carry success: false, so test for the error shape rather than for a success flag that never appears. If you write a generic client wrapper that asserts body.success, special-case this one route. Model entries are objects, not bare strings, and each list is sorted by name. Heavy — cache it, and prefer /api/models for interactive brand-specific dropdowns.",
        "tags": [
          "Filter facets"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "search",
        "x-examples": [
          "GET https://api.thecarapi.com/load-models?country=DE",
          "GET https://api.thecarapi.com/load-models?buy_now=true&damaged=false"
        ],
        "parameters": [
          {
            "name": "damaged",
            "in": "query",
            "required": false,
            "description": "Restrict to damaged or broken vehicles. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "buy_now",
            "in": "query",
            "required": false,
            "description": "Restrict to Buy-Now inventory. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Restrict to left- or right-hand-drive vehicles. Slower than an unfiltered facet call, because it is computed live rather than read from the precomputed facet table. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "BMW": [
                    {
                      "text": "320d"
                    },
                    {
                      "text": "X5"
                    }
                  ],
                  "Volvo": [
                    {
                      "text": "XC60"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/catalog/manufacturers": {
      "get": {
        "operationId": "get_api_catalog_manufacturers",
        "summary": "Paginated manufacturer catalog with inventory counts.",
        "description": "Paginated manufacturer catalog with inventory counts.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "catalog",
        "x-examples": [
          "GET https://api.thecarapi.com/api/catalog/manufacturers?country=DE&limit=20",
          "GET https://api.thecarapi.com/api/catalog/manufacturers?page=2&page_size=25"
        ],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Restrict to a country or europe. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Standard pagination. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Standard pagination. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Standard pagination. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "description": "Standard pagination. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "results": [
                    {
                      "slug": "bmw",
                      "name": "BMW",
                      "inventory_count": 1543,
                      "brand_id": 12
                    }
                  ],
                  "total": 96,
                  "limit": 50,
                  "offset": 0,
                  "total_pages": 2,
                  "max_page": 2
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/catalog/manufacturers/{slug}": {
      "get": {
        "operationId": "get_api_catalog_manufacturers_slug",
        "summary": "Resolve one manufacturer by slug.",
        "description": "Resolve one manufacturer by slug.\n\nReturns 404 when the slug is unknown.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "catalog",
        "x-examples": [
          "GET https://api.thecarapi.com/api/catalog/manufacturers/bmw",
          "GET https://api.thecarapi.com/api/catalog/manufacturers/bmw?country=DE"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Manufacturer slug. Value comes from: /api/catalog/manufacturers -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Optional country restriction. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "manufacturer": {
                    "slug": "bmw",
                    "name": "BMW",
                    "inventory_count": 1543,
                    "brand_id": 12
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/catalog/manufacturers/stats": {
      "get": {
        "operationId": "get_api_catalog_manufacturers_stats",
        "summary": "Return aggregate manufacturer statistics.",
        "description": "Return aggregate manufacturer statistics.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "catalog",
        "x-examples": [
          "GET https://api.thecarapi.com/api/catalog/manufacturers/stats",
          "GET https://api.thecarapi.com/api/catalog/manufacturers/stats?country=DE"
        ],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Optional country restriction. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "total_manufacturers": 96,
                  "active_manufacturers": 84
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/catalog/model-groups": {
      "get": {
        "operationId": "get_api_catalog_model_groups",
        "summary": "Paginated model groups for one manufacturer.",
        "description": "Paginated model groups for one manufacturer.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "catalog",
        "x-examples": [
          "GET https://api.thecarapi.com/api/catalog/model-groups?manufacturer__slug=bmw&search=320",
          "GET https://api.thecarapi.com/api/catalog/model-groups?manufacturer__slug=bmw&country=DE&page=2&page_size=20"
        ],
        "parameters": [
          {
            "name": "manufacturer__slug",
            "in": "query",
            "required": true,
            "description": "Parent manufacturer slug. Value comes from: /api/catalog/manufacturers -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Substring filter on model name. Value comes from: Free text entered by your user.",
            "schema": {
              "type": "string"
            },
            "example": "320"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Optional country restriction. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Standard pagination. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Standard pagination. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Standard pagination. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "description": "Standard pagination. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "results": [
                    {
                      "slug": "320d",
                      "name": "320d",
                      "inventory_count": 210,
                      "manufacturer_slug": "bmw"
                    }
                  ],
                  "total": 34,
                  "limit": 50,
                  "offset": 0,
                  "total_pages": 1,
                  "max_page": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/catalog/model-groups/{slug}": {
      "get": {
        "operationId": "get_api_catalog_model_groups_slug",
        "summary": "Resolve one model group by slug.",
        "description": "Resolve one model group by slug.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "catalog",
        "x-examples": [
          "GET https://api.thecarapi.com/api/catalog/model-groups/320d?manufacturer__slug=bmw",
          "GET https://api.thecarapi.com/api/catalog/model-groups/320d?manufacturer__slug=bmw&country=DE"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Model-group slug. Value comes from: /api/catalog/model-groups -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "320d"
          },
          {
            "name": "manufacturer__slug",
            "in": "query",
            "required": false,
            "description": "Manufacturer slug for disambiguation. Value comes from: /api/catalog/manufacturers -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Optional country restriction. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "model_group": {
                    "slug": "320d",
                    "name": "320d",
                    "inventory_count": 210,
                    "manufacturer_slug": "bmw"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/seo/popular-searches": {
      "get": {
        "operationId": "get_api_seo_popular_searches",
        "summary": "List the most common live brand/model searches.",
        "description": "List the most common live brand/model searches.",
        "tags": [
          "SEO helpers"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "seo",
        "x-examples": [
          "GET https://api.thecarapi.com/api/seo/popular-searches",
          "GET https://api.thecarapi.com/api/seo/popular-searches?limit=50"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of results from 1 to 200. Default 20. Value comes from: Result count chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "results": [
                    {
                      "brand": "BMW",
                      "model": "320d",
                      "brand_slug": "bmw",
                      "model_slug": "320d",
                      "count": 210
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/seo/brand-model-from-slug": {
      "get": {
        "operationId": "get_api_seo_brand_model_from_slug",
        "summary": "Resolve brand and model slugs to their canonical display names.",
        "description": "Resolve brand and model slugs to their canonical display names.\n\nReturns 404 unless the slug pair identifies exactly one live brand/model combination.",
        "tags": [
          "SEO helpers"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "seo",
        "x-examples": [
          "GET https://api.thecarapi.com/api/seo/brand-model-from-slug?brand_slug=bmw&model_slug=320d",
          "GET https://api.thecarapi.com/api/seo/brand-model-from-slug?brand_slug=volvo&model_slug=xc60"
        ],
        "parameters": [
          {
            "name": "brand_slug",
            "in": "query",
            "required": true,
            "description": "Brand slug, such as bmw. Value comes from: /api/seo/popular-searches -> results[].brand_slug",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "model_slug",
            "in": "query",
            "required": true,
            "description": "Model slug, such as 320d. Value comes from: /api/seo/popular-searches -> results[].model_slug",
            "schema": {
              "type": "string"
            },
            "example": "320d"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "brand": "BMW",
                  "model": "320d"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/auction/{site_slug}/{auction_id}": {
      "get": {
        "operationId": "get_api_auction_site_slug_auction_id",
        "summary": "Canonical auction detail with private and bidder fields removed.",
        "description": "Canonical auction detail with private and bidder fields removed.\n\nLive prices: for a running openlane or ecarstrade auction the bid is refreshed from the source while this request is served, the price fields are rewritten and a live_price block is attached. Nothing enables it and there is no separate real-time endpoint. Every other listing is still live-priced from the continuous feed — it simply carries no separate bid to re-read. A refreshed price is reused for ttl_seconds (default 120) and Cache-Control: max-age drops to match, so polling faster gains nothing. Read live_prices from /api/contract rather than hardcoding which sources qualify. This API only observes auction prices — it never places, raises or withdraws a bid. Returns 404 when the source-aware listing does not exist. Auction fees, bid history, transport and every delivery*/selfpickup* key are removed at the response boundary — they are quoted to our buyer account and our delivery address, not yours. Published asking prices, VAT scheme, estimated repair cost and seller location are unaffected; for landed cost use the import calculator, which prices your own route.\n\nResponse fields — vault_gallery (object): The image vault’s authoritative photo set, embedded verbatim: the exact body of /api/auction-images/{site}/{id} ({ images, count, pending }). Read it and a detail page is one request instead of two. Both routes build it from one cache entry, so they can never disagree; while pending is non-zero this response is served with max-age=10 so a polling client sees photos as they land. A client that ignores it behaves exactly as before. vehicle_details (object): Cross-source normalized condition and paperwork: documents, inspection_reports, option_reports, service_history, technical_inspection, paperwork, condition, damages, equipment, warranty, specs, location, seller. Every key is omitted when the source has nothing for it, and the whole block is omitted while details_pending is true. car_identification (object): Raw source-specific spec map. Prefer vehicle_details where it covers what you need — its keys are stable across sources, these are not. images / gallery_images (object[]): What the source record itself carried — untouched by this release. For the vault’s photo set with served URLs and dimensions, read vault_gallery above. live_price (object): Present only when the bid was refreshed from the auction house during this request: { price, currency, source, fetched_at }. price is the raw bid and equals current_price; fetched_at is a Unix timestamp in seconds — use it, not your own clock, to render “as of”. Its absence never means the price is stale — every listing is live-priced from the continuous feed regardless. The block only reports the additional at-request bid re-read, which most listings do not qualify for. live_price_pending (boolean): True when the upstream refresh missed the request budget and is still running. Read the car once more after ~2s and then stop — the second read is served from cache. These responses carry Cache-Control: no-store and X-Live-Price: pending. current_price / current_final / current_tax / current_tax_delivery / public_price_eur (number): Recomputed from the refreshed bid when a live price happened, so a client that ignores live_price entirely still shows the right number. buy_now_price and buynow_final are never touched — a buy-now figure does not move with bidding. auction_end_at (timestamp | null): Absolute UTC instant the lot closes, or null for stock with no deadline. Drive countdowns from this — not from batch_end_date, whose timezone differs per auction house, nor auction_sec_left, which is a snapshot taken at the last refresh rather than seconds from now. estimated_value_eur (number | null): The auction house own valuation of the vehicle, in EUR — and NOT a price you can pay. No bid is settled against it and no car is sold at it. Only ecarstrade publishes one (its \"eCT Estimation Price\"); it is null for every other source and null for roughly 86% of eCarsTrade lots. Where it does appear it is often the only number on the lot, because a blind auction hides the bid: current_price, start_price and buy_now_price are all null while this carries the estimate. Label it as an estimate wherever you show it, and never sort or filter on it — it is absent on most cars, so any ordering that uses it silently drops them. steering (enum): left or right, never null. japanauction is the only source that publishes a steering field; for every other source the side is read off the car registration market — a car registered in a country that drives on the left (GB, IE, JP, CY, MT, AU, NZ, ZA, IN, TH, HK, SG) is right, everything else left. Also present on every search result card and on /api/car-details. co2 (integer | null): CO2 in g/km as the auction house measured and published it. Null on roughly half of lots, which publish none. It carries no standard tag and mixes both EU test cycles by registration year — see the CO2 & emissions page. co2_estimated (integer | null): A derived CO2 figure for lots that publish none, inferred from other lots of the same specification. NEVER a measured value, and null wherever the specification does not decide it. It is a separate field from co2 on purpose, so an estimate can never be mistaken for a measurement. co2_estimated_standard (enum | null): NEDC or WLTP — which EU test cycle co2_estimated is expressed on. Always read the estimate together with this: the same physical car reads 12-25% higher under WLTP, so a figure without its standard is not comparable.",
        "tags": [
          "Auctions & history"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "auctions",
        "x-examples": [
          "GET https://api.thecarapi.com/api/auction/encar/38112900",
          "GET https://api.thecarapi.com/api/auction/openlane/11125938"
        ],
        "parameters": [
          {
            "name": "site_slug",
            "in": "path",
            "required": true,
            "description": "Source name returned by /api/sites. Value comes from: /api/search -> results[].site_name",
            "schema": {
              "type": "string"
            },
            "example": "encar"
          },
          {
            "name": "auction_id",
            "in": "path",
            "required": true,
            "description": "Integer auction database id. Value comes from: /api/search -> results[].auction_id",
            "schema": {
              "type": "integer"
            },
            "example": "38112900"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "auction": {
                    "auction_id": 11409652,
                    "site_name": "openlane",
                    "clean_make": "BMW",
                    "clean_model": "320d",
                    "model_display": "320d M Sport",
                    "registration_year": 2020,
                    "mileage": 45000,
                    "current_price": 25900,
                    "current_final": 33566,
                    "public_price_eur": 33926,
                    "auction_end_at": "2026-08-20T10:00:00Z",
                    "images": [],
                    "vault_gallery": {
                      "images": [
                        {
                          "served_url": "/image-vault/ab/cd/openlane_11409652_00_deadbeef.avif",
                          "remote_url": "https://cdn.example/photo_1.jpg",
                          "image_status": "ready"
                        }
                      ],
                      "count": 28,
                      "pending": 0
                    },
                    "vehicle_details": {},
                    "car_identification": {},
                    "live_price": {
                      "price": 25900,
                      "currency": "EUR",
                      "source": "openlane",
                      "fetched_at": 1786659750
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/auction/{site_slug}/{auction_id}/price-history": {
      "get": {
        "operationId": "get_api_auction_site_slug_auction_id_price_history",
        "summary": "Chronological source-price and public-price snapshots for a listing.",
        "description": "Chronological source-price and public-price snapshots for a listing.",
        "tags": [
          "Auctions & history"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "auctions",
        "x-examples": [
          "GET https://api.thecarapi.com/api/auction/encar/38112900/price-history",
          "GET https://api.thecarapi.com/api/auction/openlane/11125938/price-history"
        ],
        "parameters": [
          {
            "name": "site_slug",
            "in": "path",
            "required": true,
            "description": "Auction source slug. Value comes from: /api/search -> results[].site_name",
            "schema": {
              "type": "string"
            },
            "example": "encar"
          },
          {
            "name": "auction_id",
            "in": "path",
            "required": true,
            "description": "Auction database id. Value comes from: /api/search -> results[].auction_id",
            "schema": {
              "type": "integer"
            },
            "example": "38112900"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "site": "encar",
                  "auction_id": 38112900,
                  "source_auction_id": "38112900",
                  "history": [
                    {
                      "event_type": "price_change",
                      "changed_fields": [
                        "current_price"
                      ],
                      "current_price": 21500,
                      "public_price_eur": 21500,
                      "observed_at": "2026-07-10T08:00:00"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/auction-images/{site_slug}/{auction_id}": {
      "get": {
        "operationId": "get_api_auction_images_site_slug_auction_id",
        "summary": "Ordered gallery metadata backed by the image vault. Usually unnecessary — the same body rides on the auction detail response as vault_gallery.",
        "description": "Ordered gallery metadata backed by the image vault. Usually unnecessary — the same body rides on the auction detail response as vault_gallery.\n\nYou usually do not need this call: /api/auction/{site}/{id} embeds this same body as vault_gallery, so a detail page can be one request rather than two. This endpoint stays fully supported and is still the right one when you want the gallery on its own; both are served from a single cache entry, so they never disagree, and while pending is non-zero both carry max-age=10. Every entry carries a URL that works right now. Stored photos are AVIF or WebP depending on what the source served — rely on the URL and content type, not the extension. An empty images array means nothing is stored yet; an invalid site returns 404.\n\nResponse fields — pending (integer): How many photos the auction still owes. Show placeholders for these instead of a silently short gallery. A non-zero value also promotes the outstanding rows to user-requested priority. url (string): The best URL available right now — served_url once vaulted, remote_url until then. served_url (string): Same-origin vault path once the photo is stored. Load this directly. remote_url (string): Original source URL. Load this through an image proxy. image_status (enum): ready, pending, downloading, failed, or not_downloaded. image_source (enum): downloaded (in the vault) or proxied (still served from the source). index / is_primary (integer / boolean): Gallery order and which photo is the thumbnail. source_section (string): Section the source filed the photo under, e.g. exterior, interior, damage. width / height (integer): Pixel dimensions of the stored photo.",
        "tags": [
          "Auctions & history"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "auctions",
        "x-examples": [
          "GET https://api.thecarapi.com/api/auction-images/encar/38112900",
          "GET https://api.thecarapi.com/api/auction-images/openlane/11125938"
        ],
        "parameters": [
          {
            "name": "site_slug",
            "in": "path",
            "required": true,
            "description": "Auction source slug. Value comes from: /api/search -> results[].site_name",
            "schema": {
              "type": "string"
            },
            "example": "encar"
          },
          {
            "name": "auction_id",
            "in": "path",
            "required": true,
            "description": "Auction database id. Value comes from: /api/search -> results[].auction_id",
            "schema": {
              "type": "integer"
            },
            "example": "38112900"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "pending": 12,
                  "images": [
                    {
                      "url": "https://cdn.example/photo_1.jpg",
                      "remote_url": "https://cdn.example/photo_1.jpg",
                      "served_url": "/image-vault/ab/cd/ecarstrade_7399555_00_deadbeef.avif",
                      "thumbnail": "/image-vault/ab/cd/ecarstrade_7399555_00_deadbeef.avif",
                      "image_status": "ready",
                      "image_source": "downloaded",
                      "index": 0,
                      "is_primary": true,
                      "source_section": "exterior",
                      "width": 1024,
                      "height": 768
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/vin/{vin}/history": {
      "get": {
        "operationId": "get_api_vin_vin_history",
        "summary": "Look up a full VIN across current and archived auction records.",
        "description": "Look up a full VIN across current and archived auction records.\n\nReturns up to 100 matches, newest first. An invalid VIN returns 400.",
        "tags": [
          "Auctions & history"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "auctions",
        "x-examples": [
          "GET https://api.thecarapi.com/api/vin/WBA8E9G50GNU12345/history",
          "GET https://api.thecarapi.com/api/vin/KNAB3811ALT123456/history"
        ],
        "parameters": [
          {
            "name": "vin",
            "in": "path",
            "required": true,
            "description": "Valid 17-character VIN. Exact match only. Value comes from: /api/auction/{site}/{id} -> auction.chassis_number",
            "schema": {
              "type": "string"
            },
            "example": "WBA8E9G50GNU12345"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "vin": "WBA8E9G50GNU12345",
                  "match_count": 2,
                  "auctions": [
                    {
                      "site_name": "encar",
                      "auction_id": 38112900,
                      "clean_make": "BMW",
                      "clean_model": "320d",
                      "mileage": 45000,
                      "public_price_eur": 21500,
                      "first_seen_at": "2026-06-01T00:00:00",
                      "last_seen_at": "2026-07-10T00:00:00",
                      "archived": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/car-details": {
      "get": {
        "operationId": "get_api_car_details",
        "summary": "Fetch full vehicle detail by source and listing identifier.",
        "description": "Fetch full vehicle detail by source and listing identifier.\n\nParameters may be sent in the query string or a JSON body. This endpoint can be slower than canonical auction detail. Fee, transport, delivery and account-scoped fields are stripped here exactly as they are on auction detail. When no details are stored yet it fetches from the source during the request — read details_pending in the body and X-Details-Fetch in the headers, and poll rather than retrying in a tight loop. Live prices apply here too when the response comes from stored auction data; note the one trap that catches people — this body’s auction key is an image container, not the vehicle record, so prices are read from the top level.\n\nResponse fields — vehicle_details (object | 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_pending (boolean): 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_eur (number): 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_pending (object | 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. auction (object): 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_eur (number | 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. steering (enum | 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.",
        "tags": [
          "Vehicle details"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "details",
        "x-examples": [
          "GET | POST https://api.thecarapi.com/api/car-details?site=encar&id=38112900",
          "POST https://api.thecarapi.com/api/car-details\n{\n  \"site\": \"openlane\",\n  \"identifier\": \"11125938\",\n  \"search_id\": \"vehicle-page-42\"\n}"
        ],
        "parameters": [
          {
            "name": "site",
            "in": "query",
            "required": true,
            "description": "schadeautos, auto1, openlane, copart, encar, ecarstrade, or japanauction. Value comes from: /api/sites -> sites[].name",
            "schema": {
              "type": "string"
            },
            "example": "encar"
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "Provide any one source id or listing URL. For auto1 and japanauction this is the offer id/UUID, not the numeric auction id. Value comes from: /api/search -> results[].auction_id, or the source listing URL",
            "schema": {
              "type": "string"
            },
            "example": "38112900"
          },
          {
            "name": "link",
            "in": "query",
            "required": true,
            "description": "Provide any one source id or listing URL. For auto1 and japanauction this is the offer id/UUID, not the numeric auction id. Value comes from: /api/search -> results[].auction_id, or the source listing URL",
            "schema": {
              "type": "string"
            },
            "example": "38112900"
          },
          {
            "name": "identifier",
            "in": "query",
            "required": true,
            "description": "Provide any one source id or listing URL. For auto1 and japanauction this is the offer id/UUID, not the numeric auction id. Value comes from: /api/search -> results[].auction_id, or the source listing URL",
            "schema": {
              "type": "string"
            },
            "example": "38112900"
          },
          {
            "name": "search_id",
            "in": "query",
            "required": false,
            "description": "Optional correlation id. Value comes from: Optional correlation id generated by your application.",
            "schema": {
              "type": "string"
            },
            "example": "vehicle-page-42"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "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
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "post_api_car_details",
        "summary": "Fetch full vehicle detail by source and listing identifier.",
        "description": "Fetch full vehicle detail by source and listing identifier.\n\nParameters may be sent in the query string or a JSON body. This endpoint can be slower than canonical auction detail. Fee, transport, delivery and account-scoped fields are stripped here exactly as they are on auction detail. When no details are stored yet it fetches from the source during the request — read details_pending in the body and X-Details-Fetch in the headers, and poll rather than retrying in a tight loop. Live prices apply here too when the response comes from stored auction data; note the one trap that catches people — this body’s auction key is an image container, not the vehicle record, so prices are read from the top level.\n\nResponse fields — vehicle_details (object | 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_pending (boolean): 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_eur (number): 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_pending (object | 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. auction (object): 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_eur (number | 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. steering (enum | 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.",
        "tags": [
          "Vehicle details"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "details",
        "x-examples": [
          "GET | POST https://api.thecarapi.com/api/car-details?site=encar&id=38112900",
          "POST https://api.thecarapi.com/api/car-details\n{\n  \"site\": \"openlane\",\n  \"identifier\": \"11125938\",\n  \"search_id\": \"vehicle-page-42\"\n}"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "site",
                  "id",
                  "link",
                  "identifier"
                ],
                "properties": {
                  "site": {
                    "type": "string",
                    "description": "schadeautos, auto1, openlane, copart, encar, ecarstrade, or japanauction.",
                    "example": "encar"
                  },
                  "id": {
                    "type": "string",
                    "description": "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"
                  },
                  "link": {
                    "type": "string",
                    "description": "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"
                  },
                  "identifier": {
                    "type": "string",
                    "description": "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"
                  },
                  "search_id": {
                    "type": "string",
                    "description": "Optional correlation id.",
                    "example": "vehicle-page-42"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "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
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/listVehicles": {
      "get": {
        "operationId": "get_api_listVehicles",
        "summary": "Catalog-shaped listing feed — a compatibility alias for search.",
        "description": "Catalog-shaped listing feed — a compatibility alias for search.\n\nA compatibility alias kept for older integrations, also reachable at /listVehicles. It takes catalog-shaped parameter names and returns the same cards /api/search does. For anything new, use /api/search — it has the full filter surface, ETags and the deeper paging policy, and this route does not.\n\nResponse fields — vehicles / results (object[]): The same array under two keys, so either spelling works. Cards are augmented search result cards. total / limit / offset / total_pages / max_page (integer | null): Standard pagination fields, exactly as on /api/search.",
        "tags": [
          "Vehicle details"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "details",
        "x-examples": [
          "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"
        ],
        "parameters": [
          {
            "name": "manufacturer_slug",
            "in": "query",
            "required": false,
            "description": "Brand, under any of the three accepted spellings. Value comes from: /api/catalog/manufacturers -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "manufacturer",
            "in": "query",
            "required": false,
            "description": "Brand, under any of the three accepted spellings. Value comes from: /api/catalog/manufacturers -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "brand",
            "in": "query",
            "required": false,
            "description": "Brand, under any of the three accepted spellings. Value comes from: /api/catalog/manufacturers -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "bmw"
          },
          {
            "name": "model_group_slug",
            "in": "query",
            "required": false,
            "description": "Model group, under any of the three accepted spellings. Value comes from: /api/catalog/model-groups?manufacturer__slug=bmw -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "320d"
          },
          {
            "name": "model_group",
            "in": "query",
            "required": false,
            "description": "Model group, under any of the three accepted spellings. Value comes from: /api/catalog/model-groups?manufacturer__slug=bmw -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "320d"
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "description": "Model group, under any of the three accepted spellings. Value comes from: /api/catalog/model-groups?manufacturer__slug=bmw -> results[].slug",
            "schema": {
              "type": "string"
            },
            "example": "320d"
          },
          {
            "name": "fuel_type",
            "in": "query",
            "required": false,
            "description": "Canonical fuel group. Value comes from: /api/fuels -> fuels[]",
            "schema": {
              "type": "string"
            },
            "example": "Diesel"
          },
          {
            "name": "fuel",
            "in": "query",
            "required": false,
            "description": "Canonical fuel group. Value comes from: /api/fuels -> fuels[]",
            "schema": {
              "type": "string"
            },
            "example": "Diesel"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Left- or right-hand drive. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          },
          {
            "name": "min_year",
            "in": "query",
            "required": false,
            "description": "Registration-year range. Value comes from: Year bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "2018"
          },
          {
            "name": "max_year",
            "in": "query",
            "required": false,
            "description": "Registration-year range. Value comes from: Year bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "2018"
          },
          {
            "name": "max_mileage",
            "in": "query",
            "required": false,
            "description": "Mileage ceiling. Value comes from: Mileage ceiling chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "120000"
          },
          {
            "name": "ordering",
            "in": "query",
            "required": false,
            "description": "Sort order. A leading minus reverses it. Value comes from: One of -created_at, price, -price, year, -year.",
            "schema": {
              "type": "string"
            },
            "example": "-created_at"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Or page_size / page. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Or page_size / page. Default limit 50. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "vehicles": [],
                  "results": [],
                  "total": 210,
                  "limit": 50,
                  "offset": 0,
                  "total_pages": 5,
                  "max_page": 5
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "post_api_listVehicles",
        "summary": "Catalog-shaped listing feed — a compatibility alias for search.",
        "description": "Catalog-shaped listing feed — a compatibility alias for search.\n\nA compatibility alias kept for older integrations, also reachable at /listVehicles. It takes catalog-shaped parameter names and returns the same cards /api/search does. For anything new, use /api/search — it has the full filter surface, ETags and the deeper paging policy, and this route does not.\n\nResponse fields — vehicles / results (object[]): The same array under two keys, so either spelling works. Cards are augmented search result cards. total / limit / offset / total_pages / max_page (integer | null): Standard pagination fields, exactly as on /api/search.",
        "tags": [
          "Vehicle details"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "details",
        "x-examples": [
          "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"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "manufacturer_slug": {
                    "type": "string",
                    "description": "Brand, under any of the three accepted spellings.",
                    "example": "bmw"
                  },
                  "manufacturer": {
                    "type": "string",
                    "description": "Brand, under any of the three accepted spellings.",
                    "example": "bmw"
                  },
                  "brand": {
                    "type": "string",
                    "description": "Brand, under any of the three accepted spellings.",
                    "example": "bmw"
                  },
                  "model_group_slug": {
                    "type": "string",
                    "description": "Model group, under any of the three accepted spellings.",
                    "example": "320d"
                  },
                  "model_group": {
                    "type": "string",
                    "description": "Model group, under any of the three accepted spellings.",
                    "example": "320d"
                  },
                  "model": {
                    "type": "string",
                    "description": "Model group, under any of the three accepted spellings.",
                    "example": "320d"
                  },
                  "fuel_type": {
                    "type": "string",
                    "description": "Canonical fuel group.",
                    "example": "Diesel"
                  },
                  "fuel": {
                    "type": "string",
                    "description": "Canonical fuel group.",
                    "example": "Diesel"
                  },
                  "steering": {
                    "type": "string",
                    "description": "Left- or right-hand drive.",
                    "example": "left"
                  },
                  "min_year": {
                    "type": "integer",
                    "description": "Registration-year range.",
                    "example": "2018 / 2024"
                  },
                  "max_year": {
                    "type": "integer",
                    "description": "Registration-year range.",
                    "example": "2018 / 2024"
                  },
                  "max_mileage": {
                    "type": "integer",
                    "description": "Mileage ceiling.",
                    "example": "120000"
                  },
                  "ordering": {
                    "type": "string",
                    "description": "Sort order. A leading minus reverses it.",
                    "example": "-created_at"
                  },
                  "limit": {
                    "type": "integer",
                    "description": "Or page_size / page. Default limit 50.",
                    "example": "50 / 0"
                  },
                  "offset": {
                    "type": "integer",
                    "description": "Or page_size / page. Default limit 50.",
                    "example": "50 / 0"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "vehicles": [],
                  "results": [],
                  "total": 210,
                  "limit": 50,
                  "offset": 0,
                  "total_pages": 5,
                  "max_page": 5
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/top-offers": {
      "get": {
        "operationId": "get_api_top_offers",
        "summary": "Feed of auctions priced below their market reference, newest comparison first.",
        "description": "Feed of auctions priced below their market reference, newest comparison first.\n\nA car qualifies only when its saving clears a continuous, reference-quality-aware bar — wider price spread, thinner evidence, and slower-selling models all raise it — so this is a shortlist, not everything below average. Rows leave the feed the moment the auction ends, so total shrinks through the day and grows again after each comparison run. The comparable’s own listing URL and identity are not exposed. A non-numeric value on a numeric parameter is a 400, not a dropped filter.\n\nResponse fields — results[] (object[]): A standard search result card — every field documented in the data dictionary — plus the top-offer fields below. is_top_offer (boolean): Always true on this feed. Also present on /api/search cards. top_offer_savings (number): Absolute EUR saving against the market reference. top_offer_savings_pct (number): Saving as a percentage of the reference price. Default sort key. market_reference.price_eur (number): The reference price this car was measured against. market_reference.mileage (integer): The reference mileage, so you can judge whether the comparison is like-for-like. market_reference.km_difference (integer): This car’s mileage minus the reference. Negative means this car has done fewer kilometres. market_reference.explanation (string): The rule that admitted this car to the feed, in words — e.g. the minimum EUR saving it had to clear.",
        "tags": [
          "Top offers"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "top-offers",
        "x-examples": [
          "GET https://api.thecarapi.com/api/top-offers?site=openlane&min_savings_pct=20&limit=24",
          "GET https://api.thecarapi.com/api/top-offers?brand=BMW&country=DE&sort=savings&page=2&page_size=20"
        ],
        "parameters": [
          {
            "name": "site",
            "in": "query",
            "required": false,
            "description": "Comma-separated source slugs. An unknown value returns 400. Value comes from: /api/sites -> sites[].name",
            "schema": {
              "type": "string"
            },
            "example": "ecarstrade"
          },
          {
            "name": "site_exclude",
            "in": "query",
            "required": false,
            "description": "Comma-separated source slugs to leave out. Same rules as on /api/search. Value comes from: /api/sites -> sites[].name",
            "schema": {
              "type": "string"
            },
            "example": "copart"
          },
          {
            "name": "steering",
            "in": "query",
            "required": false,
            "description": "Left- or right-hand drive. Value comes from: left | lhd | right | rhd — any other value is a 400.",
            "schema": {
              "type": "string"
            },
            "example": "left"
          },
          {
            "name": "brand",
            "in": "query",
            "required": false,
            "description": "Exact clean_make, case-insensitive. Value comes from: /api/search -> results[].clean_make",
            "schema": {
              "type": "string"
            },
            "example": "BMW"
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "description": "Exact clean_model, case-insensitive. Value comes from: /api/search -> results[].clean_model",
            "schema": {
              "type": "string"
            },
            "example": "3 Series"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Vehicle country code, case-insensitive. Value comes from: /api/countries -> country_details[].code",
            "schema": {
              "type": "string"
            },
            "example": "DE"
          },
          {
            "name": "year_from",
            "in": "query",
            "required": false,
            "description": "First-registration year bounds. Value comes from: Year bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "2018"
          },
          {
            "name": "year_to",
            "in": "query",
            "required": false,
            "description": "First-registration year bounds. Value comes from: Year bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "2018"
          },
          {
            "name": "kilometers_from",
            "in": "query",
            "required": false,
            "description": "Mileage bounds. Value comes from: Mileage bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "0"
          },
          {
            "name": "kilometers_to",
            "in": "query",
            "required": false,
            "description": "Mileage bounds. Value comes from: Mileage bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "0"
          },
          {
            "name": "price_from",
            "in": "query",
            "required": false,
            "description": "Public EUR price bounds. Value comes from: EUR budget chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "5000"
          },
          {
            "name": "price_to",
            "in": "query",
            "required": false,
            "description": "Public EUR price bounds. Value comes from: EUR budget chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "5000"
          },
          {
            "name": "min_savings_pct",
            "in": "query",
            "required": false,
            "description": "Only offers saving at least this percentage. Value comes from: Threshold chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "20"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Default savings_pct. Value comes from: Choose savings_pct, savings, price_low, price_high, or newest.",
            "schema": {
              "type": "string"
            },
            "example": "savings_pct"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Or page_size / page. limit caps at 100. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "24"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Or page_size / page. limit caps at 100. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "24"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "results": [
                    {
                      "auction_id": 8842711,
                      "site_name": "openlane",
                      "car_name_en": "BMW 320d Touring",
                      "clean_make": "BMW",
                      "clean_model": "3 Series",
                      "public_price_eur": 9000,
                      "is_top_offer": true,
                      "top_offer_savings": 2500,
                      "top_offer_savings_pct": 21.7,
                      "market_reference": {
                        "price_eur": 11500,
                        "mileage": 165000,
                        "km_difference": -15000,
                        "explanation": "Rule: this car must save at least 1,800 EUR — ..."
                      }
                    }
                  ],
                  "total": 318,
                  "limit": 24,
                  "offset": 0,
                  "total_pages": 14
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/theparking/listings": {
      "get": {
        "operationId": "get_api_theparking_listings",
        "summary": "Query retail classifieds aggregated from portals across Europe.",
        "description": "Query retail classifieds aggregated from portals across Europe.\n\nEvery multi-value filter is OR within the parameter and AND across parameters — country=de,at&brand=BMW,Audi means (DE or AT) and (BMW or Audi). A non-numeric value on a numeric parameter is a 400, not a dropped filter. Counting is bounded rather than exhaustive on a feed this size: read total together with total_capped and total_unavailable, or skip it with include_total=false. There is no detail endpoint for these rows: what you see here is the whole record. Returns 503 while the dataset has not been built yet.\n\nResponse fields — reference_id (string): Stable identity for the listing, prefixed tp-. Use it to de-duplicate across polls. title (string): Listing headline as published by the origin portal. brand / model / engine (string): Brand and model as published, plus the engine or trim string when the portal supplies one. year (integer): Registration year. price_eur (number): Retail asking price in EUR. This is an asking price, not a transaction price. mileage_km (integer): Odometer reading in kilometres. fuel_norm (string): Normalized fuel, e.g. diesel, petrol, electric, hybrid. Matches the fuel filter vocabulary. gearbox_norm (string): Normalized gearbox, e.g. automatic, manual. Matches the gearbox filter vocabulary. colour (string): Exterior colour as published. doors (string): Door count as published by the portal. country / country_code (string): Country the car is listed in — display name and lower-case code. country_code is what the country filter accepts. region (string): Sub-national region or state when the portal publishes one. seller_type (string): dealer or private. The single most useful axis for separating trade from retail asking prices. source_site (string): 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_count (integer): How many photos the origin listing carries. Only one thumbnail is exposed here. offer_url (string): 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_url (string): 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. published (date): Date the origin portal published the listing. first_seen_at / last_seen_at (timestamp): When our sweep first and most recently observed the listing. Use last_seen_at to judge staleness. total / limit / offset / total_pages (integer): Standard pagination envelope for the matching set. total is exact for ordinary filters, and null when total_unavailable is true. total_capped (boolean): 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_unavailable (boolean): 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.",
        "tags": [
          "European classifieds"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "theparking",
        "x-examples": [
          "GET https://api.thecarapi.com/api/theparking/listings?country=de,at&brand=BMW&price_to=15000",
          "GET https://api.thecarapi.com/api/theparking/listings?seller=dealer&source=mobile.de&sort=price_low&with_photo=true",
          "GET https://api.thecarapi.com/api/theparking/listings?country=de&source_exclude=mobile.de,kleinanzeigen.de&include_total=false"
        ],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Comma-separated country codes, case-insensitive. Value comes from: /api/theparking/facets -> countries[].value",
            "schema": {
              "type": "string"
            },
            "example": "de,at"
          },
          {
            "name": "brand",
            "in": "query",
            "required": false,
            "description": "Comma-separated brands, exact as published. Value comes from: /api/theparking/facets -> brands[].value",
            "schema": {
              "type": "string"
            },
            "example": "BMW,Audi"
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "description": "Comma-separated models. Value comes from: /api/theparking/models?brand=BMW -> value",
            "schema": {
              "type": "string"
            },
            "example": "3 Series"
          },
          {
            "name": "fuel",
            "in": "query",
            "required": false,
            "description": "Comma-separated normalized fuels. Value comes from: /api/theparking/facets -> fuels[].value",
            "schema": {
              "type": "string"
            },
            "example": "diesel"
          },
          {
            "name": "gearbox",
            "in": "query",
            "required": false,
            "description": "Comma-separated normalized gearboxes. Value comes from: /api/theparking/facets -> gearboxes[].value",
            "schema": {
              "type": "string"
            },
            "example": "automatic"
          },
          {
            "name": "seller",
            "in": "query",
            "required": false,
            "description": "Comma-separated seller types, such as dealer or private. Value comes from: /api/theparking/facets -> sellers[].value",
            "schema": {
              "type": "string"
            },
            "example": "dealer"
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "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. Value comes from: /api/theparking/facets -> sources[].value",
            "schema": {
              "type": "string"
            },
            "example": "mobile.de"
          },
          {
            "name": "source_exclude",
            "in": "query",
            "required": false,
            "description": "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. Value comes from: /api/theparking/facets -> sources[].value",
            "schema": {
              "type": "string"
            },
            "example": "mobile.de"
          },
          {
            "name": "price_from",
            "in": "query",
            "required": false,
            "description": "EUR bounds. Value comes from: EUR budget chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "5000"
          },
          {
            "name": "price_to",
            "in": "query",
            "required": false,
            "description": "EUR bounds. Value comes from: EUR budget chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "5000"
          },
          {
            "name": "year_from",
            "in": "query",
            "required": false,
            "description": "Year bounds. Value comes from: Year bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "2016"
          },
          {
            "name": "year_to",
            "in": "query",
            "required": false,
            "description": "Year bounds. Value comes from: Year bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "2016"
          },
          {
            "name": "kilometers_from",
            "in": "query",
            "required": false,
            "description": "Mileage bounds. Value comes from: Mileage bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "0"
          },
          {
            "name": "kilometers_to",
            "in": "query",
            "required": false,
            "description": "Mileage bounds. Value comes from: Mileage bounds chosen by your user.",
            "schema": {
              "type": "integer"
            },
            "example": "0"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Substring match on title and description. Value comes from: Free text entered by your user.",
            "schema": {
              "type": "string"
            },
            "example": "touring"
          },
          {
            "name": "with_photo",
            "in": "query",
            "required": false,
            "description": "Only listings that carry a thumbnail. Value comes from: Your filter choice.",
            "schema": {
              "type": "boolean"
            },
            "example": "true"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Default newest. Value comes from: Choose newest, price_low, price_high, year_new, year_old, or mileage_low.",
            "schema": {
              "type": "string"
            },
            "example": "price_low"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Or page_size / page. limit caps at 100. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Or page_size / page. limit caps at 100. Value comes from: Pagination state in your application.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          },
          {
            "name": "include_total",
            "in": "query",
            "required": false,
            "description": "Default true. Pass false to skip the match count entirely — total comes back null and the request is markedly faster. Value comes from: Your pagination strategy.",
            "schema": {
              "type": "boolean"
            },
            "example": "false"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "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
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/theparking/facets": {
      "get": {
        "operationId": "get_api_theparking_facets",
        "summary": "Counted filter vocabulary for the classifieds dataset.",
        "description": "Counted filter vocabulary for the classifieds dataset.\n\nThis is the discovery endpoint for every other classifieds filter — always build selects from here rather than hard-coding values. The vocabulary is precomputed by the nightly sweep and read back in ~10 ms, so it is warm as soon as the data changes and no request pays to compute it; a dimension not yet precomputed is counted on demand and cached for an hour. Returns 503 while the dataset has not been built yet.\n\nResponse fields — countries ({value, count}[]): Every country code present in the dataset with its live listing count. This is the list to render a country picker from — it shows how wide the European coverage actually is. brands ({value, count}[]): Brands exactly as published, with counts. Feed a value straight back into the brand filter or into /api/theparking/models. fuels ({value, count}[]): Normalized fuel vocabulary with counts. These are the only values the fuel filter accepts. gearboxes ({value, count}[]): Normalized gearbox vocabulary with counts. sellers ({value, count}[]): Seller types with counts, typically dealer and private. sources ({value, count}[]): Origin portals with counts, most common first — the list of classifieds sites, dealer groups and manufacturer stock pages currently aggregated, and the vocabulary the source / source_exclude filters accept. There are ~681 of them, so the default trim of 50 is a leaderboard rather than a picker; pass limit=0 for the whole set. value_counts (object): How many distinct values each dimension really has, before the per-dimension trim. Check value_counts.sources against the length of sources to know whether you are looking at all of them. totals (object): Dataset-level summary: active listing count plus price and year bounds (price_min, price_max, year_min, year_max). Use it to seed slider ranges. totals.total follows the same capping rule as the listings feed and carries its own totals.total_capped.",
        "tags": [
          "European classifieds"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "theparking",
        "x-examples": [
          "GET https://api.thecarapi.com/api/theparking/facets",
          "GET https://api.thecarapi.com/api/theparking/facets?limit=0",
          "curl -H \"X-API-Key: $API_KEY\" \"https://api.thecarapi.com/api/theparking/facets\""
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Values returned per dimension, default 50. 0 returns all of them — the only way to get the full 681-portal sources list. Value comes from: How many values your picker can hold.",
            "schema": {
              "type": "integer"
            },
            "example": "0"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "countries": [
                    {
                      "value": "de",
                      "count": 184220
                    },
                    {
                      "value": "fr",
                      "count": 151077
                    }
                  ],
                  "brands": [
                    {
                      "value": "BMW",
                      "count": 41288
                    }
                  ],
                  "fuels": [
                    {
                      "value": "diesel",
                      "count": 302914
                    }
                  ],
                  "gearboxes": [
                    {
                      "value": "automatic",
                      "count": 188402
                    }
                  ],
                  "sellers": [
                    {
                      "value": "dealer",
                      "count": 402881
                    }
                  ],
                  "sources": [
                    {
                      "value": "mobile.de",
                      "count": 1109971
                    },
                    {
                      "value": "leboncoin.fr",
                      "count": 658810
                    }
                  ],
                  "value_counts": {
                    "countries": 39,
                    "brands": 118,
                    "fuels": 7,
                    "gearboxes": 3,
                    "sellers": 2,
                    "sources": 681
                  },
                  "totals": {
                    "listings": 9808689,
                    "total_capped": false,
                    "price_min": 300,
                    "price_max": 480000,
                    "year_min": 1970,
                    "year_max": 2026
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/theparking/models": {
      "get": {
        "operationId": "get_api_theparking_models",
        "summary": "List models available for one or more brands.",
        "description": "List models available for one or more brands.\n\nbrand is required — calling without it returns 400. Because brands are published verbatim by each portal, always take the brand value from /api/theparking/facets rather than typing it. Returns 503 while the dataset has not been built yet.\n\nResponse fields — 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/theparking/listings.",
        "tags": [
          "European classifieds"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "theparking",
        "x-examples": [
          "GET https://api.thecarapi.com/api/theparking/models?brand=BMW",
          "GET https://api.thecarapi.com/api/theparking/models?brand=BMW,Audi"
        ],
        "parameters": [
          {
            "name": "brand",
            "in": "query",
            "required": true,
            "description": "Comma-separated brand list. Required. Value comes from: /api/theparking/facets -> brands[].value",
            "schema": {
              "type": "string"
            },
            "example": "BMW,Audi"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "models": [
                    {
                      "value": "3 Series",
                      "count": 8841
                    },
                    {
                      "value": "5 Series",
                      "count": 6002
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/cars-bg-market": {
      "get": {
        "operationId": "get_api_cars_bg_market",
        "summary": "Cars.bg Bulgarian retail market snapshot.",
        "description": "Cars.bg Bulgarian retail market snapshot.\n\nMissing parameters return 400. An unknown brand/model, or a snapshot that has not been built yet, returns 404.",
        "tags": [
          "Market intelligence"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "market",
        "x-examples": [
          "GET https://api.thecarapi.com/api/cars-bg-market?brand=BMW&model=320d&year=2019",
          "GET https://api.thecarapi.com/api/cars-bg-market?make=Audi&model=A4&year=2020&flex=2"
        ],
        "parameters": [
          {
            "name": "brand",
            "in": "query",
            "required": true,
            "description": "Brand name. Value comes from: /api/brands -> brands[].name",
            "schema": {
              "type": "string"
            },
            "example": "BMW"
          },
          {
            "name": "make",
            "in": "query",
            "required": true,
            "description": "Brand name. Value comes from: /api/brands -> brands[].name",
            "schema": {
              "type": "string"
            },
            "example": "BMW"
          },
          {
            "name": "model",
            "in": "query",
            "required": true,
            "description": "Model name. Value comes from: /api/models?brand=bmw -> models[].name",
            "schema": {
              "type": "string"
            },
            "example": "320d"
          },
          {
            "name": "year",
            "in": "query",
            "required": true,
            "description": "Centre registration year. Value comes from: Centre year chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "2019"
          },
          {
            "name": "flex",
            "in": "query",
            "required": false,
            "description": "Year tolerance from 0 to 10. Default 1. Value comes from: Tolerance chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "2"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "snapshot": {
                    "brand": "BMW",
                    "model": "320d",
                    "year": 2019,
                    "sample_size": 42,
                    "avg_price_eur": 23100,
                    "min_price_eur": 17900,
                    "max_price_eur": 29500
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/auction-market": {
      "get": {
        "operationId": "get_api_auction_market",
        "summary": "Auction-market price snapshot for the same brand, model, and year window.",
        "description": "Auction-market price snapshot for the same brand, model, and year window.",
        "tags": [
          "Market intelligence"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "market",
        "x-examples": [
          "GET https://api.thecarapi.com/api/auction-market?brand=BMW&model=320d&year=2019&scope=active",
          "GET https://api.thecarapi.com/api/auction-market?brand=Kia&model=EV6&year=2023&flex=1"
        ],
        "parameters": [
          {
            "name": "brand",
            "in": "query",
            "required": true,
            "description": "Brand name. Value comes from: /api/brands -> brands[].name",
            "schema": {
              "type": "string"
            },
            "example": "BMW"
          },
          {
            "name": "make",
            "in": "query",
            "required": true,
            "description": "Brand name. Value comes from: /api/brands -> brands[].name",
            "schema": {
              "type": "string"
            },
            "example": "BMW"
          },
          {
            "name": "model",
            "in": "query",
            "required": true,
            "description": "Model name. Value comes from: /api/models?brand=bmw -> models[].name",
            "schema": {
              "type": "string"
            },
            "example": "320d"
          },
          {
            "name": "year",
            "in": "query",
            "required": true,
            "description": "Centre registration year. Value comes from: Centre year chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "2019"
          },
          {
            "name": "flex",
            "in": "query",
            "required": false,
            "description": "Year tolerance from 0 to 10. Default 1. Value comes from: Tolerance chosen by your application.",
            "schema": {
              "type": "integer"
            },
            "example": "2"
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "description": "Default all. Value comes from: Choose all, active, or inactive.",
            "schema": {
              "type": "string"
            },
            "example": "active"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "snapshot": {
                    "brand": "BMW",
                    "model": "320d",
                    "year": 2019,
                    "scope": "active",
                    "sample_size": 118,
                    "avg_price_eur": 18400
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/calculator/countries": {
      "get": {
        "operationId": "get_api_calculator_countries",
        "summary": "List supported origin and destination countries with EU membership and VAT rates.",
        "description": "List supported origin and destination countries with EU membership and VAT rates.",
        "tags": [
          "Import calculator"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "calculator",
        "x-examples": [
          "GET https://api.thecarapi.com/api/calculator/countries",
          "curl -H \"X-API-Key: $API_KEY\" \"https://api.thecarapi.com/api/calculator/countries\""
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "countries": [
                    {
                      "code": "DE",
                      "name": "Germany",
                      "eu": true,
                      "vat": 0.19
                    },
                    {
                      "code": "KR",
                      "name": "South Korea",
                      "eu": false,
                      "vat": 0
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/calculator/calculate": {
      "post": {
        "operationId": "post_api_calculator_calculate",
        "summary": "Estimate duty, VAT, fees, and the landed total for one lot price.",
        "description": "Estimate duty, VAT, fees, and the landed total for one lot price.\n\nDuty and VAT rates are returned as percentages. An invalid price returns 400.",
        "tags": [
          "Import calculator"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "calculator",
        "x-examples": [
          "POST https://api.thecarapi.com/api/calculator/calculate\n{\n  \"price\": 15000,\n  \"origin\": \"KR\",\n  \"destination\": \"BG\",\n  \"site_name\": \"encar\"\n}",
          "POST https://api.thecarapi.com/api/calculator/calculate\n{\n  \"price\": 9800,\n  \"origin\": \"BE\",\n  \"destination\": \"BG\",\n  \"site_name\": \"ecarstrade\"\n}"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "price"
                ],
                "properties": {
                  "price": {
                    "type": "number",
                    "description": "Lot price. Must be between 0 and 10,000,000.",
                    "example": "15000"
                  },
                  "origin": {
                    "type": "string",
                    "description": "Origin country code. Default KR.",
                    "example": "KR"
                  },
                  "destination": {
                    "type": "string",
                    "description": "Destination country code. Default BG.",
                    "example": "BG"
                  },
                  "car_type": {
                    "type": "string",
                    "description": "Default standard.",
                    "example": "standard"
                  },
                  "currency": {
                    "type": "string",
                    "description": "Echoed back in the response. Default EUR.",
                    "example": "EUR"
                  },
                  "site_name": {
                    "type": "string",
                    "description": "Source used to select the fee model: encar, openlane, auto1, schadeautos, copart, or ecarstrade.",
                    "example": "ecarstrade"
                  },
                  "db_tax": {
                    "type": "number",
                    "description": "Optional auction fee, delivery, or final price overrides.",
                    "example": "450"
                  },
                  "db_delivery": {
                    "type": "number",
                    "description": "Optional auction fee, delivery, or final price overrides.",
                    "example": "450"
                  },
                  "db_final": {
                    "type": "number",
                    "description": "Optional auction fee, delivery, or final price overrides.",
                    "example": "450"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "currency": "EUR",
                  "breakdown": {
                    "lot_price": 15000,
                    "auction_fee": 0,
                    "trucking": 0,
                    "shipping": 1800,
                    "our_fee": 700,
                    "subtotal_customs_value": 16800,
                    "duty_rate": 10,
                    "duty_amount": 1680,
                    "vat_rate": 20,
                    "vat_amount": 3696,
                    "customs_agency": 800,
                    "custom_clearance_total": 6176,
                    "estimated_total": 23676
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/health/live": {
      "get": {
        "operationId": "get_api_health_live",
        "summary": "Unauthenticated process liveness probe.",
        "description": "Unauthenticated process liveness probe.\n\nOne of only two endpoints in the whole API that need no key. Always 200 while the process is up. This is the right target for an uptime monitor — it says nothing about whether the data behind the API is reachable, which is what /api/health/ready and /api/health are for.",
        "tags": [
          "Health & contract"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "none — no API key required",
        "x-examples": [
          "GET https://api.thecarapi.com/api/health/live"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "status": "ok",
                  "service": "car-details-api",
                  "contract_version": "2026-08-19"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/health/ready": {
      "get": {
        "operationId": "get_api_health_ready",
        "summary": "Unauthenticated readiness probe — is the data layer reachable?",
        "description": "Unauthenticated readiness probe — is the data layer reachable?\n\n200 when the service can answer data requests, 503 when it cannot. Use this, not /api/health/live, to decide whether to send traffic. No key required.",
        "tags": [
          "Health & contract"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "none — no API key required",
        "x-examples": [
          "GET https://api.thecarapi.com/api/health/ready"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "status": "ready",
                  "service": "car-details-api",
                  "contract_version": "2026-08-19"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "get_api_health",
        "summary": "Return service, database-feed, Typesense, and schema health.",
        "description": "Return service, database-feed, Typesense, and schema health.",
        "tags": [
          "Health & contract"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "ops",
        "x-examples": [
          "GET https://api.thecarapi.com/api/health",
          "curl -H \"Authorization: Bearer $API_KEY\" \"https://api.thecarapi.com/api/health\""
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "status": "healthy",
                  "service": "car-details-api",
                  "contract_version": "2026-08-19",
                  "typesense": {
                    "enabled": true,
                    "running": true
                  },
                  "public_auction_feed": {
                    "enabled": true,
                    "fresh": true
                  },
                  "schema_findings": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/contract": {
      "get": {
        "operationId": "get_api_contract",
        "summary": "Machine-readable schema catalog, pagination limits, and live-price capability.",
        "description": "Machine-readable schema catalog, pagination limits, and live-price capability.\n\nRead this once at startup. It is the correct answer to “does this deployment support live prices, and for which sources” — a missing live_price block on a detail response is not an error and never distinguishes the two cases on its own.\n\nResponse fields — version (string): The contract version this deployment serves — the same value every response carries as contract_version. schemas (object): Required and optional keys per response shape. This is the authoritative machine-readable schema; prefer it to hardcoding field lists. As of 2026-08-19, auction_detail.optional lists vault_gallery and brands_models_facets.optional lists errors — gate on those rather than comparing version strings. pagination (object): max_limit and max_offset for paged endpoints. live_prices (object): Whether this deployment refreshes a running auction’s price when its detail is read ({ enabled, sites, ttl_seconds }). Read sites from here rather than hardcoding it. The whole block is absent on a build from before the feature — that absence is the only way to tell “this deployment cannot refresh prices” from “this car has none right now”, because both look identical in a detail response.",
        "tags": [
          "Health & contract"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "ops",
        "x-examples": [
          "GET https://api.thecarapi.com/api/contract",
          "curl -H \"X-API-Key: $API_KEY\" \"https://api.thecarapi.com/api/contract\""
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "version": "2026-08-19",
                  "schemas": {
                    "search_result_card": {
                      "required": [],
                      "optional": []
                    }
                  },
                  "pagination": {
                    "max_limit": 100,
                    "max_offset": 5000
                  },
                  "live_prices": {
                    "enabled": true,
                    "sites": [
                      "openlane",
                      "ecarstrade"
                    ],
                    "ttl_seconds": 120
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/": {
      "get": {
        "operationId": "get_",
        "summary": "Return the human-readable API index and service version.",
        "description": "Return the human-readable API index and service version.",
        "tags": [
          "Health & contract"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "ops",
        "x-examples": [
          "GET https://api.thecarapi.com/",
          "curl -H \"X-API-Key: $API_KEY\" \"https://api.thecarapi.com/\""
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "service": "Car Details API",
                  "version": "2.0.0",
                  "endpoints": {
                    "GET /api/search": "Search auction inventory",
                    "GET /api/health": "Service health"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/diagnostics": {
      "get": {
        "operationId": "get_api_diagnostics",
        "summary": "Executor and connection-pool diagnostics.",
        "description": "Executor and connection-pool diagnostics.\n\nOperational telemetry for support conversations. The shape is not part of the versioned contract and may change without a contract bump — do not build against it.",
        "tags": [
          "Health & contract"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "x-scope": "ops",
        "x-examples": [
          "GET https://api.thecarapi.com/api/diagnostics"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "success": true,
                  "executors": {},
                  "pools": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid filter, pagination, source, parameter, or request body.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Sanitized failure message."
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, invalid, or expired API key.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Sanitized failure message."
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Revoked key, or scope, IP, or origin denial.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Sanitized failure message."
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Source-aware resource not found.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Sanitized failure message."
                }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Authentication lockout or quota exceeded. Honour Retry-After.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Sanitized failure message."
                }
              }
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "apiKeyHeader": []
    },
    {
      "bearerAuth": []
    }
  ]
}
