i99dash docs
API referencei99dashTypes

VehicleCapabilitiesSnapshot

The backend's wire shape for `GET /api/v1/vehicle-capabilities` — the merged capability set for a ProfileKey, with the resolution tier the backend served from.

The response shape from GET /api/v1/vehicle-capabilities — the backend's empirical-overlay row for a ProfileKey, walked through the 4-tier server-side fallback chain. Hosts hit this on boot and after every successful probe sync.

When you'd consume this directly

Mini-app code rarely talks to the endpoint directly — the host caches the result and surfaces it via the vehicle block of display.list. Reach for the raw schema in three cases:

  1. Backend tooling — admin UIs that show the per-trim probe coverage.
  2. Server-side rendering — a backend that pre-renders catalog tiles for a known ProfileKey (e.g. an admin preview tool).
  3. Custom telemetry — an analytics pipeline that ingests probe-aggregate state alongside other car-fleet data.

For everything else, prefer the SDK helpers off display.list.

Wire shape

{
  // The ProfileKey the backend resolved this row for. Empty-string
  // slots indicate which fallback tier the resolver landed on (see
  // isFallback below).
  "dilinkFamily": "di5.0",
  "variantId":    "l5",
  "subTrim":      "flagship",
  "fingerprint":  "BYD/leopard5/...",

  // The same capability set in two redundant forms — pick whichever
  // fits your code path.
  "capabilities":   ["display.read", "pkg.read", "pkg.launch.dishare", ...],
  "capabilityBits": 67,  // bits set: 0,1,6  → display.read + pkg.read + pkg.launch.dishare

  // Wall-clock when the backend last folded a probe into this row.
  "updatedAt": "2026-05-04T12:00:00Z",

  // Probe count this row aggregates. Higher = more confident.
  // Telemetry only — the union semantic is independent of count.
  "probeCount": 17,

  // Resolution-tier metadata. False on a precise (Tier-1) hit.
  "isFallback":     false,
  "fallbackReason": null
}

Resolution tiers

The backend walks the 4-tier chain on every read; isFallback + fallbackReason tell you which tier answered:

isFallbackfallbackReasonWhat the row means
falsenullTier 1 — precise. Empirical truth for this exact (dilink, variant, subTrim, fingerprint).
true"unknown_fingerprint"Tier 2 — sub-trim aggregate. UNION of every probe on this hardware sub-trim across ROM builds.
true"unknown_sub_trim"Tier 3 — trim aggregate. UNION across every sub-trim of this variant.
true"unknown_variant"Tier 4 — DiLink-default. Generation-only floor — UNION across every variant on this DiLink generation.
true"unknown_dilink"(Reserved — the backend currently 404s in this case; the host falls back to its own static seed.)

When isFallback === true, the dilinkFamily field stays populated with the value the host sent, but the lower-precision slots may be empty strings depending on which tier hit.

Example responses

Precise hit (Tier 1)

GET /api/v1/vehicle-capabilities?dilinkFamily=di5.1&variantId=l8&subTrim=base&fingerprint=BYD/...

{
  "dilinkFamily": "di5.1",
  "variantId":    "l8",
  "subTrim":      "base",
  "fingerprint":  "BYD/leopard8/leopard8:13/Q0414/202512071900:user/release-keys",
  "capabilities": [
    "display.read", "pkg.read",
    "pkg.launch.ivi", "pkg.launch.passenger", "pkg.launch.cluster.pixel",
    "surface.write.ivi", "surface.write.passenger", "surface.write.cluster",
    "cursor.write", "gesture.dispatch",
    "ac.get", "ac.set", "door.set", "window.set"
  ],
  "capabilityBits": 65343,
  "updatedAt": "2026-05-04T12:00:00Z",
  "probeCount": 248,
  "isFallback": false,
  "fallbackReason": null
}

Sub-trim aggregate (Tier 2 — fresh ROM on a known trim)

GET /api/v1/vehicle-capabilities?dilinkFamily=di5.0&variantId=l5&subTrim=flagship&fingerprint=BYD/leopard5/leopard5:12/Q0312/...

{
  "dilinkFamily": "di5.0",
  "variantId":    "l5",
  "subTrim":      "flagship",
  "fingerprint":  "",                       // ← stripped by the resolver
  "capabilities": [
    "display.read", "pkg.read",
    "pkg.launch.ivi", "pkg.launch.passenger", "pkg.launch.dishare",
    "pkg.launch.cluster.icons",
    "surface.write.ivi",
    "cursor.write", "gesture.dispatch",
    "ac.get", "ac.set", "door.set", "window.set"
  ],
  "capabilityBits": 64575,
  "updatedAt": "2026-05-03T08:14:22Z",
  "probeCount": 91,
  "isFallback": true,
  "fallbackReason": "unknown_fingerprint"
}

Trim aggregate (Tier 3 — sub-trim couldn't be detected)

GET /api/v1/vehicle-capabilities?dilinkFamily=di5.0&variantId=l5&subTrim=&fingerprint=BYD/...

{
  "dilinkFamily": "di5.0",
  "variantId":    "l5",
  "subTrim":      "",
  "fingerprint":  "",
  "capabilities": [
    "display.read", "pkg.read",
    "pkg.launch.ivi", "pkg.launch.passenger", "pkg.launch.dishare",
    "surface.write.ivi",
    "cursor.write", "gesture.dispatch",
    "ac.get", "ac.set", "door.set", "window.set"
  ],
  "capabilityBits": 64511,
  "updatedAt": "2026-05-04T12:00:00Z",
  "probeCount": 312,
  "isFallback": true,
  "fallbackReason": "unknown_sub_trim"
}

Notice the trim aggregate is the intersection of features every sub-trim haspkg.launch.cluster.icons is in the Flagship aggregate but not the trim aggregate, because Lidar (l5l) reports into a different variantId and the Ultra/Navigator probes haven't all confirmed it.

404 (no row at all)

GET /api/v1/vehicle-capabilities?dilinkFamily=unknown&...

HTTP/1.1 404 Not Found
{ "detail": "no capability snapshot for this ProfileKey" }

The host treats this as "use the static seed compiled into the APK" — every display.list snapshot still carries a usable capability bitmask sourced from CarProfileSeed.

How capabilityBits and capabilities relate

They carry identical information:

import { bitsFromCapabilities, capabilitiesFromBits } from 'i99dash';

bitsFromCapabilities(snapshot.capabilities) === snapshot.capabilityBits;
capabilitiesFromBits(snapshot.capabilityBits)
  .every(c => snapshot.capabilities.includes(c));

The wire ships both because:

  • Logs / UI want the human-readable list. Showing 0b… to a user is unhelpful.
  • Hot-path subset checks want the bitmask. One AND beats an array intersection in any reasonable language.

Mini-app code typically uses capabilities (string list, easy to branch on); host code uses capabilityBits (single AND on the catalog merge hot path).

Type signature

Prop

Type

Source

On this page