# Vehicle catalogue

The AutoUncle vehicle catalogue is a car specifications database (makes, models, generations, drivetrains and equipment variants) and the shared vocabulary of the platform: every valuation resolves its vehicle against it, and its IDs let you say exactly which vehicle you mean. This page explains how it is organized and how to use it well. Every endpoint is listed in the [catalogue reference](/docs/reference/catalogue).

Catalogue calls are free, need the `catalogue:read` scope and have their own rate limit (default 120 requests per minute per workspace).

## The hierarchy

| Level | Example | Endpoint | ID prefix |
| --- | --- | --- | --- |
| Brand | `VW` | `GET /v1/catalogue/brands` | `b-` |
| Model | `Golf` | `GET /v1/catalogue/brands/{id}/models` | `cm-` |
| Generation | `Golf VIII` (2020–2024) | `GET /v1/catalogue/models/{id}/generations?year=` | `mg-` |
| Drivetrain | `1.5 TSI (130 Hp)`, petrol, manual | `GET /v1/catalogue/generations/{id}/drivetrains` | `dv-` |
| Equipment variant | `Active`, `Life`, `R-Line` | `GET /v1/catalogue/brands/{id}/equipment-variants` | `ev-` |

Generations include their body variant where it matters, such as `Golf VIII Variant` for the estate. Drivetrains describe engine, power, fuel and transmission. Equipment variants are trim lines and belong to a brand, not to a generation.

The drilldown for a 2021 Golf looks like this:

**curl**

```bash
curl 'https://data-services.autouncle.com/v1/catalogue/models/cm-6bb52590daf6d1b19108ec93/generations?year=2021' \
  -H "Authorization: Bearer $AUTOUNCLE_API_KEY"
```

**Ruby**

```ruby
require "json"
require "net/http"

uri = URI("https://data-services.autouncle.com/v1/catalogue/models/cm-6bb52590daf6d1b19108ec93/generations?year=2021")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("AUTOUNCLE_API_KEY")}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
puts JSON.pretty_generate(JSON.parse(response.body))
```

**Python**

```python
import json
import os

import requests

response = requests.get(
    "https://data-services.autouncle.com/v1/catalogue/models/cm-6bb52590daf6d1b19108ec93/generations?year=2021",
    headers={
        "Authorization": f"Bearer {os.environ['AUTOUNCLE_API_KEY']}",
    },
    timeout=30,
)
print(json.dumps(response.json(), indent=2))
```

**JavaScript**

```javascript
const response = await fetch("https://data-services.autouncle.com/v1/catalogue/models/cm-6bb52590daf6d1b19108ec93/generations?year=2021", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AUTOUNCLE_API_KEY}`,
  },
});
console.log(JSON.stringify(await response.json(), null, 2));
```

## Identifiers

Catalogue IDs are opaque strings such as `b-0957579dc5bca6de229d2f32` or `dv-947a3199394a5a4b41cb2869`. The contract describes them as UUIDs, but they are not RFC 4122 UUIDs: treat them as opaque, up to 100 characters.

- Store IDs exactly as returned. Do not parse them, derive meaning from the prefix or construct them yourself.
- Send them back in `vehicle.catalogue` to pin a vehicle. Any level works; the lowest level you know is the most useful, and it implies its parents.
- All IDs in one request must describe one hierarchy, or the valuation is refused with `catalogue_id_conflict`.
- An ID that no longer exists returns `unknown_catalogue_id` (404) from both the catalogue and valuations.

## Model aliases

Some catalogue models are aliases that stand for one or more generations of another model, for example `Golf VII` alongside `Golf`. Listing generations for an alias returns the generations it stands for, and a valuation with an alias model ID is scored against its canonical model. The resolved vehicle may therefore name a different model ID from the one you looked up; both are valid. When you list drivetrains for a generation reached through an alias, pass `model_id` to keep only that alias's drivetrains.

## Search

`GET /v1/catalogue/search?q=` finds brands and models by a case-insensitive substring of their catalogue names:

**curl**

```bash
curl 'https://data-services.autouncle.com/v1/catalogue/search?q=golf' \
  -H "Authorization: Bearer $AUTOUNCLE_API_KEY"
```

**Ruby**

```ruby
require "json"
require "net/http"

uri = URI("https://data-services.autouncle.com/v1/catalogue/search?q=golf")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("AUTOUNCLE_API_KEY")}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
puts JSON.pretty_generate(JSON.parse(response.body))
```

**Python**

```python
import json
import os

import requests

response = requests.get(
    "https://data-services.autouncle.com/v1/catalogue/search?q=golf",
    headers={
        "Authorization": f"Bearer {os.environ['AUTOUNCLE_API_KEY']}",
    },
    timeout=30,
)
print(json.dumps(response.json(), indent=2))
```

**JavaScript**

```javascript
const response = await fetch("https://data-services.autouncle.com/v1/catalogue/search?q=golf", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AUTOUNCLE_API_KEY}`,
  },
});
console.log(JSON.stringify(await response.json(), null, 2));
```

- It matches brand names and `brand model` names as the catalogue spells them. The brand is `VW`, so `q=golf` or `q=vw golf` finds the Golf models, but `q=volkswagen golf` finds nothing.
- It returns up to 20 brands and 80 models, without ranking beyond name order. Results are a starting point for a picker, not a resolver.
- It never consults market data or automated interpretation.

To match free-form names from your own data, send them as `make` and `model` in a valuation instead; the valuation's resolver recognizes common spellings and reports what it matched.

## Enums and markets

- `GET /v1/catalogue/enums` lists the accepted values for `fuel`, `transmission`, `drive`, mileage units, price basis, resolution, precision grades and every `equipment` key.
- `GET /v1/catalogue/countries` lists the markets you can send as `country`, with their mileage unit. See [markets](/docs/concepts/markets).

## Drivetrain fields

Drivetrain items carry specification fields from the catalogue. Two of them are not in the request vocabulary:

- `drive` is the catalogue's traction label, such as `2WD` or `AWD`. It is not the `fwd`/`rwd`/`awd`/`4wd` value that `vehicle.drive` accepts.
- `fuel` is usually a public value such as `petrol` or `plug_in_hybrid_petrol`, but some catalogue values, such as `CNG_Hybrid`, are passed through unchanged.

You do not need to copy these fields into a valuation: sending the `drivetrain_id` is enough, and its catalogue specification is used automatically.

The drivetrain filters `fuel`, `transmission`, `power_hp` and `model_id` narrow long lists, for example to the automatic petrol engines of one generation.

## Versions and caching

Catalogue lists change rarely. Every list includes a `version`, such as `5.6.7:NEW`, and `GET /v1/catalogue/version` returns it on its own.

A good caching strategy:

1. Cache brands, models and generations in your own store, keyed by ID.
2. Check `GET /v1/catalogue/version` once an hour or once a day.
3. When the version changes, refresh your cache. Keep old IDs until you have replaced them, and handle `unknown_catalogue_id` by looking the vehicle up again.

Lists are complete and not paginated; a large brand such as VW has about a hundred models.

## Catalogue over MCP

The `search_vehicles` MCP tool lists the same brands, models, generations, drivetrains, equipment variants, search results, enums, countries and version. In this version two REST features are not available over MCP: the drivetrain filters (`fuel`, `transmission`, `power_hp`, `model_id`) and lookup of a single item by ID (`GET /v1/catalogue/{kind}/{id}`). See the [tool reference](/docs/mcp/tools#search_vehicles).

## Attribution

Lists that contain catalogue data carry an `autouncle_vehicle_catalogue` attribution pointing at `/data`, and valuations attribute the identity levels they resolved. Keep attributions with any catalogue data you store or show; see [notes & data sources](/docs/notices).
