Changelog

What shipped, newest first. Biweekly.

The build code

August 13, 2026

Trim names can't identify a vehicle. "Work Truck" spans four weight classes; "LE" spans gas and hybrid. The VIN's own build pattern — positions 1–8 plus 10, the nano — separates them, and as of today it is a first-class key across the platform.

bash
curl -H "Authorization: Bearer $CARDOG_KEY" \
  "https://api.cardog.app/v2/vin/2T3RWRFV4MW112492"
# → "nano": "nano:2T3RWRFVMW",
#   "links": { "specsBuild":  "/v2/specs/nano:2T3RWRFVMW",
#              "safetyBuild": "/v2/safety/nano:2T3RWRFVMW",
#              "nanoEntity":  "/v2/entities/nano:2T3RWRFVMW", ... }

The nano is pure string math over the VIN — derivable offline with @cardog/entities, stable forever, and now dereferenceable: 824,000 build codes are registry entities, one per configuration the decoder has verified.

GET /v2/specs/nano:{code} — the config-exact sheet. The decoded configuration (weight class, drive, fuel/hybrid family, engine — each with source, confidence, and the decoder build that produced it) plus every catalog entry that maps to this build. When several map (option packages don't change the VIN pattern), you get them all and the fold of what they agree on — never a silently-picked one.

GET /v2/safety/nano:{code} — the rating for THAT build. Ratings are selected by joining the build's decoded axes against what NHTSA declared — never by matching trim text. The response states its own narrowness:

  • configuration — exactly one rating survives: it's yours. tested: true marks the rating whose crash car was literally this build.
  • partial / model-year — the honest short list, or the full set. Blockers are named, never papered over.
  • exempt — NCAP does not rate vehicles over 8,500 lb GVWR. A 2023 F-350 answers exempt, not "missing" — with the listed configurations and their driver-assist data still included.

Weight class, filled in. North-American catalog rows never carried GVWR from source sheets; it is now derived from real decoded VINs, unanimity-gated — 15,000 rows including every 2023 F-350 — so /v2/specs/{model-year} serves the class your pricing model reads, and it agrees with the decode.

Nothing breaks: model-year refs keep answering everywhere they did, and the new links ride alongside the old ones. The build code is additive — a sharper key for consumers who need configuration truth, which is anyone pricing, insuring, or rating an actual vehicle rather than a nameplate.


API 2.0

July 30, 2026

The Cardog API is now one keyed surface at api.cardog.app/v2. Resolve free text to a permanent ref once, then dereference that ref into identity, specs, listings, live market data, and recalls behind a single key.

bash
curl -H "Authorization: Bearer $CARDOG_KEY" \
  "https://api.cardog.app/v2/entities/resolve?q=tesla+model+y"
# → { "ref": "model:tesla/model-y", ... }

curl -H "Authorization: Bearer $CARDOG_KEY" \
  "https://api.cardog.app/v2/listings?make=make:tesla&year=2024"

model:tesla/model-y is a permanent join key. Store it in a database column, a config file, or an agent's memory file; it will mean the same vehicle for as long as the platform exists.

Every non-2xx response carries the fix. The envelope is { code, message, hint, docs_url, suggestions }. An unknown ref returns a 400 that names the offending ref and offers the nearest valid ones — we never silently fuzzy-match a typo into a different vehicle. A wrong answer that looks right is worse than an error, so you get the error and the correction in the same response.

The contract generates the surface. Schemas in @cardog/contracts validate responses, not just requests, and every downstream artifact regenerates from them: the OpenAPI spec, the docs reference, the conformance table, the live-check suite, both SDKs' types, and the MCP tool layer. Nothing user-facing is hand-maintained, so nothing user-facing can drift.

Nine route groups, all ref-native:

GroupWhat it answers
entitiesfree text → permanent refs; the only door free text enters
vinVIN → identity, with per-item batch
specs155-attribute catalog by trim
listingsref-native search, facets, count over live Canadian listings
instruments · quotes · tapelive Canadian market data
recallsTransport Canada + NHTSA, fused, ref-keyed
pricingmachine-readable rate card at GET /v2/pricing

Docs are generated, and readable by machines. cardog.app/docs has zero hand-written endpoint prose — cURL / TypeScript / Python tabs come from both SDK method maps, ⌘K search, and a try-it panel that runs against your own key. Every page has a .md twin, and cardog.app/docs.md is the whole platform in one fetch.

@cardog/entities is on npm, Apache-2.0. The ref grammar as an open package: validate, build, and type refs offline, forever, with zero API calls and zero dependencies. The grammar is free; resolution and the facts behind the refs are the product.

ts
import { modelYearRef, parseRef, squishFromVin } from "@cardog/entities";

modelYearRef("model:tesla/model-y", 2024); // "model-year:tesla/model-y/2024"
squishFromVin("5TDGSKFC8RS123456");        // "5TDGSKFCR" — offline, no network

SDKs and MCP. @cardog/api (TypeScript) and cardog (PyPI) are siblings generated from the same OpenAPI artifact, with envelope-typed errors. mcp.cardog.io exposes five job-shaped tools — resolve_entity, identify_vehicle, search_inventory, market_quote, check_recalls — whose descriptions teach the ref grammar inline.

Credits are visible on every call. X-Credits-Rate, X-Credits-Remaining, X-Credits-Allowance, and X-Credits-Reset on every keyed response; X-Credits-Source on every debited one. The rate card is machine-readable at GET /v2/pricing. The free tier stops at 50 credits with an insufficient_credits envelope that says how to continue. Paid tiers bill overage and are never blocked.

What changed for existing users

  • v1 still works. No v1 route has been removed and none is being removed today. A deprecation window will be announced with dates in a future entry, not inferred from this one.
  • Your existing key works on /v2 unchanged. One channel gate covers API key, session, and internal callers.
  • Free text now enters at one door. v1 accepted make/model strings on several endpoints. In v2, free text goes to GET /v2/entities/resolve and every other route takes refs. If you send a string where a ref belongs, you get a 400 naming the field and pointing at resolve — the migration instruction arrives in the response.
  • Errors changed shape. v1 error bodies were not uniform. v2 is always { code, message, hint, docs_url, suggestions }. Dispatch on code; it is an open set, so fall back to message for codes you do not know.
  • Nulls are honest. null means not-derivable from the evidence. It never means unknown, and it is never a placeholder.

Improvements

  • Docs content negotiation: Accept: text/markdown on any docs page, or append .md.
  • Conformance table and live-check suite generated from the contract and run per-PR against a preview deployment.

Next

Named because they are being built, not because they are available: resolve that survives messier real-world queries, agent-minted trial keys, recall watches, ?include= so one call answers one job, a self-serve portal for metering and upgrades, and idempotency keys.

Full reference: cardog.app/docs · one fetch: cardog.app/docs.md · this changelog as markdown: cardog.app/changelog.md