SDKs & MCP
Ref grammar
Last updated:
Validate, build, and type refs offline with @cardog/entities.
Every identifier in the Vehicle Graph, from
make:honda to model-year:honda/civic/2021 to squish:5TDGSKFCR,
follows one grammar, and that grammar is published as an open-source
package. Install it and your code can validate, build, parse, and type refs
offline: no API key, no network call, no rate limit.
npm install @cardog/entitiesESM, TypeScript-first, zero dependencies, Apache-2.0. Runs in Node, browsers, workers, and edge runtimes.
Validate and build, offline
import {
isRef, isRefOf, buildRef, parseRef,
modelYearRef, parseModelYearRef, recallRef,
} from "@cardog/entities";
isRef("make:tesla"); // true
isRef("make:Tesla"); // false: casing is part of the grammar
isRefOf(input, "model-year"); // narrows to EntityRef<"model-year">
modelYearRef("model:tesla/model-y", 2024); // "model-year:tesla/model-y/2024"
parseModelYearRef("model-year:honda/civic/2021");
// { make: "make:honda", model: "model:honda/civic", year: 2021 }
recallRef("nhtsa", "23V123"); // "recall:nhtsa/23v123"Every builder validates against the grammar and throws rather than normalizing, which is the same rule the API applies at its boundary. Use it to validate user input before it costs a call, to reject a malformed ref in a form handler, or to assert grammar in your tests.
The VIN grains, offline
nano and squish, the grains between one VIN and a whole model year,
are pure functions of the VIN, so the package derives them locally:
import { squishFromVin, nanoFromVin, squishRef, nanoRef } from "@cardog/entities";
squishFromVin("5TDGSKFC8RS123456"); // "5TDGSKFCR": the exact-configuration market grain
nanoFromVin("5TDGSKFC8RS123456"); // "5TDGSKFC*RS": the comparables grain
squishRef("5TDGSKFCR"); // "squish:5TDGSKFCR": ready for /v2/quotesA VIN in your database becomes a market-grain ref without touching the network. The API call you then make is the one that quotes it.
Typed unions
The enumerable domains ship as TypeScript unions, so a misspelled ref in a fixed vocabulary fails at compile time rather than at request time:
import type { FuelTypeRef, BodyStyleRef, CountryRef, EntityDomain } from "@cardog/entities/types";
import type { SpecAttributeId } from "@cardog/entities";
const fuel: FuelTypeRef = "fuel-type:electric"; // ✓ checked by tsc
const made: CountryRef = "country:canada"; // every ISO 3166-1 country
const attr: SpecAttributeId = "curbWeight"; // the 155-attribute catalog, typedThe open-ended domains (make, model) are typed structurally as
EntityRef<"make">. Their vocabularies live in the registry, and free
text reaches them through resolve.
The package also carries the spec attribute catalog
(@cardog/entities/spec), the same catalog GET /v2/specs/catalog
serves. Use it to build filter UIs and to validate spec.{attributeId}
query keys before sending them.
The stability contract
Refs are permanent join keys, and the package states that in a form you can check:
GRAMMAR_VERSIONis1. It bumps only for a breaking change to the grammar itself, which the platform treats as something that should never happen. New domains and entities are additive.vocabularycarries the provenance of the build the package was generated from, so what your process validates against is auditable.- A ref, once issued, keeps its meaning for the life of the platform. Store refs in your columns and your config.
Where the API begins
The package contains no entity data (no make list, no model vocabulary, no display names) and no VIN decoding. Holding the grammar tells you a ref is well-formed. Only the registry can tell you what it names:
# free text → refs (the only route that accepts unstructured input)
curl "https://api.cardog.app/v2/entities/resolve?q=2021%20civic" -H "x-api-key: $CARDOG_API_KEY" -H "Cardog-Version: 2026-10-26"
# ref → the entity: names, hierarchy, counts, links into every group
curl "https://api.cardog.app/v2/entities/model:honda%2Fcivic" -H "x-api-key: $CARDOG_API_KEY" -H "Cardog-Version: 2026-10-26"
# VIN → identity as refs
curl "https://api.cardog.app/v2/vin/5TDGSKFC8RS123456" -H "x-api-key: $CARDOG_API_KEY" -H "Cardog-Version: 2026-10-26"The division of labour is simple. Validate and construct refs locally. When a question needs the registry (resolution, enumeration, specs, recalls, quotes), call /v2/entities and its sibling groups.
Was this helpful?