Audi Public API Sources
Audi exposes its data through three public APIs used by the ai_audi pipeline.
No API keys or partner credentials are required; all endpoints are the same backends
the www.audiusa.com website (and the other market sites) calls from the browser.
Postman collection — Audi public APIs. All four ingested endpoints are recorded as
runnable requests in the live "Public OEM APIs" collection, Audi folder, in the
AutoIntel Workspace
(reconciled 2026-07-09) — the collection itself is the record of record, not an exported
file. The Postman MCP still exposes no folder-creation/delete/transfer tool in this
workspace, so the Audi folder mixes the 4 ingested requests with pre-existing
non-ingested items (now labeled [LEGACY / UNUSED] in place rather than moved to a
subfolder):
StockCarSearch — inventory (ingested)CarlineStructure — models (ingested)dealersByMarket — dealers (ingested)CatalogForModel — features (ingested)
Market coverage
All three APIs are market-parameterized and were probed against the full ISO 3166-1 alpha-2 country list on 2026-07-07. Neither GraphQL endpoint allows introspection, so there is no authoritative market list; the coverage below reflects what actually returned data.
The active pipeline currently ingests full-coverage markets only; those markets live in
defs/<oem>/<market>/raw/defs.yaml and include the components their APIs serve:
| Tier | Assets | Markets |
|---|---|---|
| Full | dealers, carlines, catalog features, inventory | ar, au, az, bh, br, ca, ch, de, es, fr, gb, gr, ie, it, jo, jp, kr, kw, lu, mx, nl, no, om, pl, sa, se, tw, us |
The partial tiers below are retained as discovery records in
defs/<oem>/<market>/raw/defs.yaml.disabled; Dagster ignores them until a future onboarding
renames the file to defs.yaml and adds the matching template vars / transformed defs:
| Tier | Available API data | Disabled markets |
|---|---|---|
| No inventory | dealers, carlines, catalog features | be, dk, fi, in, th, tr |
| Dealers only | dealers | at, bg, cz, hu, my, pt, ro, rs, si, sk |
"No inventory" markets return a carline structure but no stockCarSearch results;
"dealers only" markets return an empty carlineStructure.carlineGroups (they are not
on the OneGraph stack at all). PSS dealersByMarket responds for nearly every country
on earth — many with 1–2 import-dealer rows — so dealer counts alone do not indicate a
real market. Several more countries (e.g. nz, hk, eg, sg, qa, lb, and most
of Central America / the Caribbean) do return carline structures and could be onboarded
the same way if ever needed.
The partial tiers are not a language artifact. Sweeping the full ISO 639-1 list
(the API rejects region variants like de-AT) confirms this: the dealers-only markets
return no OneGraph data in any language. The no-inventory markets return carlines only
in the configured language(s), with no language yielding stock (stockCarsType: USED
is equally unknown for them). Every language that has ever returned data is in the
country's CLDR territory-language set (or en) — when re-verifying a market, probing
those candidates (plus en) is sufficient.
For multi-language markets one site language is ingested: ca→en, be→nl,
ch→de, lu→fr (both languages return identical inventory counts; only display
text differs).
API Domains
| Domain | Used for |
|---|---|
omnigraph.audi.com | Inventory (StockCarSearch) and model structure (CarlineStructure) |
graphql.pss.audi.com | Dealer locator |
web-api.audi.com | Feature / option catalog per model |
Raw dependency graph
| Node | Raw asset | Upstream | Source |
|---|---|---|---|
| a | audi/us/raw/onegraph_models | — | OmniGraph CarlineStructure |
| b | audi/us/raw/catalog_features | a | Web-API CatalogForModel per model_id |
| c | audi/us/raw/onegraph_inventory | — | OmniGraph StockCarSearch |
| d | audi/us/raw/pss_dealers | — | PSS dealersByMarket |
OmniGraph GraphQL API
POST https://omnigraph.audi.com/graphql
The Akamai edge deny-lists specific
(apollographql-client-name, apollographql-client-version) pairs on the inventory
endpoint, targeting stale versions of Audi's own frontend client. This is independent of
egress IP. Verified deterministic (20/20 requests per variant):
| client-name | version | Result |
|---|---|---|
fa-vlp-list-page | 5.16.0 (ours, was) | 403 |
fa-vlp-list-page | 5.28.4 (live site) | 200 |
fa-vlp-list-page | 5.17.0, 5.20.0, 1.0.0 | 403 |
fa-vlp-list-page | 5.18.0, 5.19.0, 5.21.0–5.28.4, 6.0.0, 0.0.1 | 200 |
audi-data-platform | 1.0.0 | 200 |
This is not a minimum-version rule; it is a discrete deny-list.
Required headers:
| Header | Inventory | CarlineStructure |
|---|---|---|
apollographql-client-name | audi-data-platform | audi-data-platform |
apollographql-client-version | 1.0.0 | 1.0.0 |
content-type | application/json | application/json |
audi-data-platform/1.0.0 is our own identifier, not a value observed in Audi
traffic. It is unrecognised by the edge, which is precisely why it is unaffected by
the deny-list above. origin/referer are not required; the endpoint is
unauthenticated and both were confirmed to have no effect on the 403.
CarlineStructure (node a)
Fetches the full Audi USA model hierarchy — carline groups → carlines → trimlines →
models. Drives the catalog_features fan-out (node b).
A single live call (verified 2026-07-09) returns the complete current lineup in one nested tree, spanning model years 2026 (current) and 2027:
- 16 carline groups
- 32 distinct carline ids / 36 carlines
- 36 distinct
modelId.code - 75
model_catalog_idvalues
There is no per-model/-year/-trim fan-out endpoint — the tree carries every model, year, and trim as attributes of this one response. The full current nameplate set is present (Q3/Q5/Q6 e-tron/Q7/Q8, A3/A5/A6/A8, e-tron GT, plus the S/RS variants).
The carlineStructure(identifier: {country, language}) query returns the whole tree
in one request — carline groups, carlines, trimlines, and per-model
modelId { code version extensions year }, prices and
technicalDataV2.modelAttributes.
StockCarSearch (node c)
Fetches all new vehicles nationwide. Paginated with offset; total available from
resultNumber on the first page.
stockCarSearch(stockIdentifier:, searchParameter:) returns resultNumber plus
results.cars[].stockCar. stockIdentifier takes a marketIdentifier
(brand, country, language) and a stockCarsType; searchParameter takes paging,
sort and criteria. The stockCar fragment carries the vehicle (vin, avpCode,
commissionNumber, weblink), model, carline, code, colorInfo, dealer,
engineInfo, features, carPrices, dynamicAttributes, salesInfo and images.
Images. images(groupIds:, imageIds:) returns one entry per id in imageIds —
url, type, mimeType and id { group image }. An empty imageIds returns an empty
list whatever groupIds asks for. Under groupIds: ["renderImagesPNG"], urls are PNGs
at https://mediaservice.audi.com/media/fast/...png, built for the vehicle's own color
and options. Each id added to imageIds grows the per-vehicle render work of every
search page, so responses slow with the size of the set.
Known image ids, verified by inspecting the rendered PNGs. The sc4* set is
transparent-background, sc3* is a transparent-background wide crop, sc5c01 is a
small 350x196 render, and vtp4x3* carries a background scene:
| View | Transparent | Transparent wide | With background |
|---|---|---|---|
| Front | sc4c03 | sc3c03 | vtp4x3n3c |
| 3/4 front | sc4c01 (also small: sc5c01) | — | vtp4x3n1c |
| Zoom 3/4 front hood | sc4c02 | — | vtp4x3n2c |
| Zoom 3/4 front bumper | — | sc3c02 | — |
| Side | sc4c14 | sc3c14 | vtp4x3n8c |
| 3/4 rear | sc4c12 | sc3c12 | vtp4x3n6c |
| Rear | sc4c11 | sc3c11 | vtp4x3n5c |
| Interior, rear-facing angled | sc4n05 | sc3n05 | vtp4x3i1n |
| Interior, front-facing near-straight | sc4n06 | sc3n06 | vtp4x3i2n |
groupIds: ["dealerImages"] serves real dealer photos rather than renders
(https://vtpimages.audi.com/carimg2/...jpg, resizable via im=Resize query params).
Its image ids are stringified integers counting up from "1", with no fixed ceiling;
counts can exceed "12". Population varies per vehicle: on a 200-car page verified
2026-08-25, 166 carried at least one dealer photo, with coverage tapering gradually
("1" on 166 cars, "12" on 156, "20" on 107). Groups combine in one request —
each imageIds entry resolves against every group in groupIds, and unmatched
(group, id) pairs are simply absent from images.
Pagination: offset via searchParameter.paging.offset + .limit. resultNumber
from the first response gives the total; termination is a short/empty page. Verified
2026-07-09: paging advances (page 2 ≠ page 1) and terminates naturally on the short
final page.
Page-size ceiling = 200. A limit of 250 or more returns a GRAPHQL subgraph
error.
Coverage: No geo or criteria filters — criteria: [] returns the full US
national inventory in one paginated pass. The unfiltered national resultNumber was
52,304 on 2026-07-09.
features.featureType — standard vs. optional equipment
Since OmniGraph disallows introspection, featureType semantics and the fields below
were reverse-engineered from the TypeScript source of Audi's Tier-3 dealer VDP apps
(fa-vdp-feature-and-specs, fa-vdp-pricing-bar, fa-vdp-pricing-breakdown), which
consume this same schema client-side.
featureType distinguishes SERIES = standard equipment from SPECIAL =
optional; the dealer frontend renders its standard/optional tabs directly from
this flag. The full vocabulary is unconfirmed.
manufacturerSpecificItems.cdbCategories — investigated, not ingested
cdbCategories (under manufacturerSpecificItems { ... on StockCarManufacturerAudi })
groups features into a category → subcategory → feature tree with per-feature
marketing copy (textInfos { name details benefits }, imageResources). Findings from
live probes (~3,900 US vehicles):
- cdb features are a strict subset of
stockCar.features(zero violations observed), but membership reflects marketing display content (CDB = content database), not ordering configuration. - Trim packages (e.g.
WPS) are omitted fromcdbCategoriesuniversally — for every model, regardless of whether the package is the trim default or a paid second tier. TheconfiguredCarquery's feature lists omit them the same way. So cdb absence carries no default-vs-optional signal; only inventorystockCar.featuresincludes package codes at all. - ~45% of
SERIESfeatures are also absent from cdb — it is a curated display list, not a complete standard-equipment list. - US-only: CA and DE return
manufacturerSpecificItemswith zero cdb feature codes.
Contrast with AccessAudi (private/ordering side), which omits a package code only when the package is the trim default.
carPrices — full price breakdown
Each carPrices entry carries type, label and price.value. The price
object also exposes valueAsText/formattedValue (display strings). Price-type
vocabulary confirmed from the frontend's priority-order constants (not exhaustive —
Audi can add types without a schema change):
- US, new:
list,OEMDiscount,dealerMarkup,dealerDocFees,destinationAndHandlingFees,dealerDiscount,dealerPrice,nonConditionalBonus,sale - Canada, new: adds levies —
freightPDI,acLevy,tireLevy,motoCouncil,adminFee,luxuryTax - Used: adds
final
Live US sampling (July 2026) observed list, dealerPrice, sale, final,
dealerDiscount (negative values), dealerMarkup, and dealerDocFees; label was
null on every entry.
Additional fields observed
Schema-valid on OmniGraph, confirmed either in live www.audiusa.com traffic or in
the feature-hub app source:
| Field | Description |
|---|---|
stockCar.techDataGroups { id label techDataList { id text label } } | Full per-car technical specs (displacement, max output/torque, transmission, suspension, brakes, steering, top speed, acceleration, fuel consumption, weights, cargo). Group/item ids differ by market: US uses engine/drivetrain/suspension/brakes/fuelconsumption; international markets use power/driveline/chassis/brake-system/fuel-consumption/performance-data/volumes. Model-level attributes. |
stockIdentifier.stockCarsType: "USED" | Same endpoint serves used stock with mileage, qualityLabel, preUse { code text } — see stockCar.preUse/qualityLabel below for the individual fields. |
stockCar.metaData { statImport } | Provenance tag (AGC_USA_JDP / AGC_CAN_JDP = JD Power feed) |
stockCar.modelInfo.genericModel { code text } | Generic model code alongside model |
stockCar.modelInfo.modelyear | Model year, redundant with model.salesModelyear |
stockCar.qualityLabel { label } | Quality label (e.g. Certified Pre-Owned) |
stockCar.cartypeText | Car type text |
stockCar.preUse { code text } | Pre-use classification |
stockCar.descriptionByDealer | Free-text dealer description |
stockCar.colorInfo.*.imageUrl | Swatch image URLs per color |
stockCar.carPrices.disclaimers { id legalEntityKey text } | Legal disclaimer text per price line — only observed on the single-vehicle stockCar(...) query, not stockCarSearch |
cars.geoDistance { unitText value { formatted number } } | Distance from a geo anchor (only populated when geo is passed in searchParameter) |
search.criteria[].possibleItems/selectedItems | Facet counts per filter dimension |
Single-vehicle query. stockCar(stockCarIdentifier: StockCarIdentifierInput!)
also exists and returns the same fragment as stockCarSearch.
Search criteria ids. Confirmed in the wild: stat-import, t_vin (VIN
filter — useful for targeted spot-check probes).
Frontend brand codes. us=50710 / ca=50720 feed the mediaservice render API
(https://mediaservice.audi.com/renderapi/v1/urlsvin) for VIN imagery.
Known data quality issues
dealer_mat_primary_code — same VIN listed under two dealers simultaneously during vehicle transit
Observed: 2026-06-30, e.g. VIN WAUF2BF21RN008391 at USA02F21 (Audi Ann Arbor) and USA03C10 (Audi North Shore).
The StockCarSearch API returns two records for the same VIN when a vehicle is in transit between dealers. One record represents the vehicle as allocated and priced at the receiving dealer (vehicle_order_status: "Dealer Stock", non-null msrp). The other is an open allocation at the originating dealer (sale_order_type: "SHIP - Deliverable Inventory Order", null pricing). Both records are genuine concurrent line items in Audi's order management system; neither is stale or erroneous.
The true current dealer location can be determined by following the weblink field — the URL resolves to the dealer's own inventory page for that VIN, which reflects where the vehicle actually is. No scalar field in the API response reliably identifies the authoritative record without resolving the URL.
StockCarSearch — subgraph failures arrive as HTTP 200
OmniGraph is a GraphQL federation gateway. When its stockcar-graphql subgraph
returns a non-JSON body, the gateway reports that as HTTP 200 with a 245-byte
envelope instead of an error status:
{"data":null,"errors":[{"message":"HTTP fetch failed from 'stockcar-graphql': expected value at line 1 column 1","path":[],"extensions":{"code":"SUBREQUEST_HTTP_ERROR","service":"stockcar-graphql","reason":"expected value at line 1 column 1"}}]}
Measured rate on pl (2026-08-20): ~2% of requests, independent of offset and
of concurrency (1.5% over 66 sequential single-request polls, 2.0% over 400 pages
fetched at 10 workers). Across a full 50-page market sweep that means most runs hit
at least one — 6 of 8 observed sweeps did. Identical request params succeed on an
immediate retry (8 of 8 recovered on the first retry), so the failure is transient
server-side non-determinism, not a rate limit or a bad request.
These responses also carry cache-control: no-store, where a good response carries
public, max-age=3600, s-maxage=3600. The advertised TTL is not honored by anything
in the request path — no age header is ever returned and resultNumber drifts
between calls seconds apart.
StockCarSearch — per-field errors arrive beside a complete page
An errors list does not by itself mean the response is unusable. The gateway also
reports a missing per-vehicle field as a VTP_API_ERROR entry alongside a full page
of cars:
{"message":"VTP API system did not deliver a required data field.",
"locations":[{"line":1,"column":1053}],
"path":["stockCarSearch","results","cars",87,"stockCar","model","id","version"],
"extensions":{"code":"VTP_API_ERROR","subCode":2001,"service":"stockcar-graphql",
"id":"b55becda-ced7-4a2b-bf30-b22955e05859",
"exception":{"message":"Exception details removed. Please use the error extension field 'id' to retrieve exception details from the StockCar subgraph log."}}}
The field named by path is non-null in the schema, so the null propagates to the
nearest nullable parent — for the path above, the car's entire model block, taking
model.id.code, .year, .extensions and model.name with it. Everything else on
the page survives: resultNumber is present, all 100 entries are there, and the
affected car's own stockCar is non-null with its remaining 21 fields intact.
The gap is fixed per vehicle, not transient.
Rate varies by market, measured 2026-08-21 over 8 requests each across offsets
0-300: es/es 6 of 8 pages, kr/ko 4 of 8, fr/fr 2 of 8, and none on pl/pl,
us/en, jp/ja or au/en. A shorter 6-request pass over de/de, gb/en, it/it
and ca/en saw none.
StockCarSearch — omitting the named field returns the rest
The field an error names is missing only because the query asked for it. Re-requesting the same window with that field left out of the selection returns the rest of the subtree, and no error at all (measured 2026-08-21):
| window | full query | named field omitted |
|---|---|---|
fr/fr offset 300 | 1 error, car 87's model null | no errors; model.name, id.code and id.year present, id.extensions still null |
au/en offset 100 | data: null — no page at all | no errors; 100 cars, resultNumber 3024 |
au/en offset 100 fails on every attempt with the full query, over one vehicle's
features[].text, at limit 100 and 50 alike — omitting the field is the only way that
window reads. The same offsets read cleanly at limit: 1 with the full query, so a lost
window is not reducible to a lost vehicle.
PSS GraphQL API — Dealer Locator (node d)
POST https://graphql.pss.audi.com/
Authentication — dynamic client ID
The PSS API requires a clientid header. The value is not static — it is fetched
at runtime from the Audi Market Context Service before every dealer request:
GET https://oneaudi-falcon-market-context-service.prod.renderer.one.audi/api/market-context
?path=/content/dam/country/us/configurations/config---market-context
&aemEnvironmentId=p119811-e1162341
&aemEnvironmentService=publish
Response: {"clientId": "<value>", ...}. The clientId field is passed as the
clientid request header to the PSS endpoint.
Dealers query
dealersByMarket(market: $market) returns dealers. Key fields returned:
dealerId, matPrimaryCode, kvpsId, name, address,
houseNumber, street, city, region, zipCode, latitude, longitude,
phone, fax, services, additionalData (display name, location
image, additional URL), openingHours (per-department day schedules).
A single A-USA call returns all 315 US dealers (verified 2026-07-09), each with a
real, in-range non-zero latitude/longitude. Two dealer identifiers are returned:
matPrimaryCode (e.g. USA01A23) and dealerId (e.g. USAA01A17, carrying an extra
brand letter). The value that matches the dealer code carried on inventory records
(stockCar.dealer.id) is matPrimaryCode, not dealerId.
Market coverage: The market variable is A-<ISO alpha-3> — A is the Audi
brand and <ISO alpha-3> the market's 3-letter country code (e.g. A-USA), where the
site itself is addressed by ISO alpha-2 (e.g. us). One request per market returns all of
that market's dealers in a single call — see Market coverage.
Audi Web-API — Feature Catalog (node b)
GET https://web-api.audi.com/vsapi/v1/us/en/CatalogForModel?model={model_id}
No authentication. One request per model ID; model IDs come from CarlineStructure.
The response names no model: it echoes back neither the requested model id nor
any model code or year of its own.
Response structure: featuresData containing named category lists —
accessories, bodyColors, extColors, groups, interiorTiles, roofColors,
specialGroups, stealthItems — each holding equipment families and individual
equipmentList items with id (PR3 code), name, price, type,
mbvId (PR7), renderCode, benefits, media, attributes, and optional
content (package sub-items).