---
title: "Decode a VIN to its graph identity"
method: GET
path: "/v2/vin/{vin}"
tags: ["vin"]
---

# Decode a VIN to its graph identity

`GET /v2/vin/{vin}`

## Request

- Base URL: `https://api.cardog.app`
- URL: `https://api.cardog.app/v2/vin/{vin}`
- Auth: one of:
  - API key in header `x-api-key`
  - HTTP bearer

Identity card: display names + entity refs + nano/squish grains + links to instrument, recalls, and listings.

## Path parameters

- `vin` string, required

## Response `200`

The identity card

- VinIdentity
  - `vin` string, required
  - `valid` boolean, required: Whether the VIN decodes to a vehicle. When false, every other field and every ref is null; the API does not fill in an unresolved VIN from similar vehicles.
  - `year` integer, nullable, required
  - `doors` integer, nullable
  - `trim` string, nullable
  - `numberOfWheels` integer, nullable
  - `numberOfAxles` integer, nullable
  - `shippingWeight` integer, nullable
  - `grossWeight` integer, nullable
  - `make` string, nullable, required: Display name. Use `refs.make` for joins.
  - `model` string, nullable, required: Display name. Use `refs.model` for joins.
  - `refs` object, required
    - `make` string, nullable, required: Make entity ref, e.g. "make:tesla"
    - `model` string, nullable, required: Model entity ref, e.g. "model:tesla/model-y"
    - `modelYear` string, nullable, required: Model-year entity ref, e.g. "model-year:tesla/model-y/2024"
    - `bodyStyle` string, nullable, required
    - `fuelType` string, nullable, required
    - `driveType` string, nullable, required
    - `transmission` string, nullable, required
    - `electrificationLevel` string, nullable, required
    - `vehicleType` string, nullable, required
    - `gvwr` string, nullable
    - `country` string, nullable, required: Ref of the country the vehicle was built in, e.g. "country:canada"
    - `bodyCab` string, nullable
    - `bedType` string, nullable
    - `series` string, nullable
    - `fuelTypeSecondary` string, nullable
    - `trailerBodyType` string, nullable
    - `trailerType` string, nullable
  - `nano` string, nullable, required: Build code ref (VIN positions 1–8 plus 10), e.g. "nano:5TDGSKFCRS". Vehicles sharing it are the same build, so use it as the deduplication and comparables key. Null when `valid` is false.
  - `squish` string, nullable, required: Configuration key ref (WMI + VDS + model year, plant-agnostic), e.g. "squish:5TDGSKFCS". This is the level market prices are quoted at. Null when `valid` is false.
  - `authorityTier` 'authoritative' | 'commercial' | 'derived' | 'observed': Trust tier of the identity facts. Source documents are never identified.
  - `reasons` string[], nullable: Why the VIN yielded no identity, from a closed vocabulary of eleven in three classes. The engine's refusals, written beside a row: WMI_UNKNOWN, PATTERN_UNKNOWN, UNKNOWN_MODEL_YEAR, INVALID_LENGTH, INVALID_CHARACTERS, CHECK_DIGIT_MISMATCH, NON_STANDARD_CHECK_DIGIT. The fold's own, for a refusal the engine gives no code for: NO_PATTERN_MATCH, MAKE_REF_GRAMMAR. And two minted at the READ, which answer a different question — not 'why could we not name this build' but 'why is there no row to read': UNSEEN_BUILD (the build is well-formed and has never been decoded — distinct from decoded and refused, and the one the refresh top-up mints next) and UNKEYABLE_VIN (the VIN projects onto no build code, so there is no key). Non-empty whenever `valid` is false; null exactly when `valid` is true. Typed as strings on the wire on purpose: the row classes are closed by a CHECK on ocean.identity.status_reasons and the read class by the API, so a new code is a deliberate change and never breaks a client parsing this field.
  - `corgiBuild` string, nullable: Decoder build that minted this identity, e.g. "2026_08_3befa53".
  - `attributes` object, nullable: Non-entity decode output for this build. Not the spec sheet.
  - `links` object, required: Server-relative paths to related resources. Always includes "instrument", "recalls", "listings", and one entity link per ref.

## Other responses

- `400`: Invalid request — grammar failure or unknown-but-well-formed refs, NAMED in `refs`/`details`, with nearest-ref `suggestions` where computable. Never a fuzzy fallback.
- `401`: No valid credential (API key, session, or internal token)
- `402`: Insufficient credits (free-tier hard stop; paid tiers bill overage instead)
- `429`: Per-minute rate limit exceeded
- `500`: Internal error

---

[API](https://skmtc.dev/cardog/apis/cardog-api-v2.md) · [All operations](https://skmtc.dev/cardog/apis/cardog-api-v2/llms.txt) · [OpenAPI document](https://skmtc.dev/cardog/apis/cardog-api-v2/revisions/b9d48193126f?raw)
