# Domain model and terminology

This page defines the public tapinomahub terms and API relationships that integrations need. Exact request and response shapes remain normative in the OpenAPI reference.

The machine-readable definitions are available as [domain-dictionary.json](/machine/domain-dictionary.json).

## Canonical account terms

### Client

An account addressed by `clientId`. Every API key belongs to exactly one Client. Billing, credit, plans and rate limits attach to that Client, not to its parent.

### Master client

A Client with no parent and with administrative rights. It can create and manage Sub-users and issue sponsorships. A directly contracted customer is a Master client.

### Sub-user

A Client below one Master client. It has its own API keys, credit, plans and limits but cannot create another hierarchy level. Deactivating the Master client also deactivates its Sub-users.

Use **Sub-user** in English and **Unter-Nutzer** in German.

### Workspace

`workspace` is the response field that groups the Client information returned by the corresponding workspace operation. It does not introduce a separate tenant resource.

### Tenant

Not a tapinomahub object. It is the end customer inside the integrating system. There is no tenant field in the public API. Map each Tenant that needs isolation to its own Client, normally a Sub-user with its own API key. Keep the integrating system's tenant key in that system; never invent a `tenantId` request field.

## Public contract concepts

### VIN

`vin` is the vehicle identification number accepted by VIN operations and returned by several scanner and vehicle operations. The VIN is the starting input for vehicle lookup, vehicle-related parts, OE-cart checking, recall matching and economic evaluation. It is not a compatibility result and must not be used as a substitute for `tapiId`.

For exact producers and consumers, see [VIN data flow](/knowledge/identifiers-and-data-flow/#vin).

### `tapiId`

`tapiId` is the stable public vehicle reference returned by a successful vehicle lookup. The `GET /vehicles/{tapiId}` contract clarifies that it references the technical vehicle type, not the individual physical vehicle; several VINs can share one value. Store the VIN and `tapiId` in separate fields.

Use `tapiId` for subsequent technical vehicle data and listing-text calls where the operation explicitly requires it. Do not derive, parse or create it locally.

### OE number

`oeNumber` is the submitted original-equipment part-number string used by OE operations. Different operations make different normalization promises. Preserve the original business input and also store `normalizedOeNumber` only when the selected operation returns a confirmed value.

An OE number may identify or reference a part, but by itself it does not prove that the part fits a particular vehicle.

### Normalized OE number

`normalizedOeNumber` is a contract result, not a string transformation that clients should guess. In `OeNormalizationResponse`, it is non-null only when `status` is `matched`; in `PartOeResponse`, it is the confirmed normalized number to which the response applies.

Do not replace the API's normalization result with locally guessed formatting rules. Use `GET /parts/oe/normalize` when the workflow needs an explicit normalization decision, and treat the returned value as authoritative for that response.

### OE part name

`PartOeResponse.part.name` is an optional nullable part designation. When available, its value is a string or `null`. Clients should preserve the returned value and must not reconstruct a missing name from another field.

### tapinomahub GenArt

`tapiGenArt` is a stable public tapinomahub part-category identity in the format `TGA-` followed by at least six digits. Every successful base OE response contains the field, but its value is `null` when no valid classification is available. A successful VIN-parts position contains one non-null value.

Treat a returned code as opaque. Store it as a string, do not convert it to an integer, and do not infer equality with any external taxonomy. A `null` OE value does not invalidate the confirmed base part.

### VDI 4081 code

The required `vdi` field of a successful base OE response and of every successful VIN-parts position contains only confirmed full codes matching `VDI4081_<number>` with an optional installation-location suffix. In the asynchronous VIN flow, the same field appears under `result.parts[].vdi`. `[]` means no valid mapping was available and is a complete terminal value, not a pending state. It does not mean the part is invalid and does not prove installation on a vehicle.

VDI 4081 is a classification system named by the public contract.

### Asynchronous job and `jobId`

Some order operations may return HTTP `202` instead of a result. `jobId` identifies the accepted processing job; the required full `statusUrl` is the safe polling address, while `Location` must be compared rather than reconstructed from its current root-relative example. A job-status request returning HTTP `200` can still report the domain state `failed`. Branch on `status`; for the part-image family, locally require and validate the corresponding result or error because the released schema does not make those fields state-dependent.

Different workflows use different job resources. Never send a VIN-parts `jobId` to the cart-check or economic-evaluation status path.

### OE replacement chain

`replacementChain` contains confirmed directional `from`/`to` edges in a base OE response. It is not a list of interchangeable inventory items and not a vehicle-fit guarantee. Preserve edge direction and validate the business use before substituting a part number.

### OE fitment

`PartOeResponse.fitment[]` contains the available type-level vehicle assignments for a confirmed OE base part. The list can be empty; an empty list means that no assignments were returned and is not proof that the part fits no vehicle.

Every fitment entry contains an opaque `vehicleTypeKey` and the readable `criteria[]` recorded for that key. Criteria are unstructured display text: the contract defines no AND/OR relationship, polarity, vocabulary or executable rule, so clients must preserve them with their key and must not derive compatibility logic from the text. An empty criteria list means that no restriction is recorded for that assignment; it does not turn the assignment into an unconditional installation guarantee.

The key is neither a VIN nor a `tapiId`. Keep it as a string and use it only in the same external key space. API 1.71.0 does not expose a public operation that resolves `vehicleTypeKey` to make, model or `tapiId`.

### OE reference numbers

`PartOeResponse.references[]` groups confirmed reference and comparison numbers by `manufacturer`; each group contains a non-empty `numbers[]` list. `PartOeResponse.referenceNumbers` is a closed object with exactly `oe_oem_reference_numbers[]`, the consolidated confirmed numbers including the confirmed OE number.

These reference views do not state that every number is bidirectionally interchangeable and do not prove vehicle fitment. Read replacement direction only from `replacementChain`, and do not derive references from that chain or a chain from the references.

### Vehicle data and vehicle-related parts

Vehicle data describes the matched vehicle or technical vehicle type. Vehicle-related parts describes part assignments or candidates returned in a VIN workflow. These are different results and different operations. A vehicle lookup can produce `tapiId`; a parts lookup can produce `parts[]` and `matchLevel`.

`matchLevel` communicates the documented strength of a VIN-parts assignment. It must be stored and interpreted with the result. Do not collapse every value into “fits”.

### Vehicle–part compatibility

Two public evidence scopes for vehicle–part compatibility must remain separate:

- `GET /parts/oe/{oeNumber}` returns the available type-level `fitment[]` assignments for a confirmed OE base part. It is the reverse OE-to-vehicle-type view, but its keys are opaque and the response makes no catalogue-wide completeness promise.
- `POST /vin/cart-check` checks submitted OE-number positions against one concrete VIN at `mode=type|vehicle`. Interpret every line together with the response's completeness signal.

Neither result is an installation approval. Do not infer VIN-specific fitment from a type-level assignment, an OE family member, VDI or a replacement edge.

### Marketplace article optimisation

Marketplace article optimisation is the publication-side counterpart to the part data: for one OE number it produces the content an article needs in a marketplace or shop — the listing title, the marketplace category, the item specifics, search keywords and the on-page SEO text. `GET /parts/oe/{oeNumber}/seo` implements it, and `marketplaceId` selects the target marketplace. The documented marketplaces are the eBay sites (`EBAY_DE` by default, through to `EBAY_US`), so "eBay article optimisation", "eBay listing title", "eBay category" and "eBay item specifics" all resolve to this one operation and its `content.ebayTitle`, `categoryId` and `itemSpecifics[]` fields.

The result is publication content, not compatibility evidence. It says how an article should be titled, categorised and described; it never states that the part fits a particular vehicle. Keep it separate from `fitment[]` and from a cart check, and review it before publishing.

## Key relationships

```text
VIN
  -> vehicle lookup
  -> tapiId
  -> technical vehicle data or listing text

VIN
  -> vehicle-related parts lookup
  -> parts[] + matchLevel + parts[].tapiGenArt + parts[].vdi[]

OE number
  -> optional normalization decision
  -> confirmed normalizedOeNumber
  -> base OE lookup
  -> part + tapiGenArt + vdi[] + fitment[] + replacementChain[] + references[] + referenceNumbers

OE number
  -> marketplace article optimisation (marketplaceId + language)
  -> ebayTitle + categoryId + itemSpecifics[] + keywords[] + shop SEO text

VIN + OE-number positions
  -> OE-cart check
  -> position results + completeness

registration-document file URL
  -> POST /scanner/document/registration/international
  -> normalized document fields, including a VIN when detected
  -> vehicle lookup or vehicle intake

calculation document file URL
  -> POST /scanner/document/calculation
  -> fixed calculation fields + source-backed equipment[]

rich vehicle document file URL
  -> POST /scanner/document/vehicle
  -> detailed vehicle + equipment[] + warnings
```

The graph is a routing model, not a claim that each arrow always succeeds. Exact success, null and error behaviour comes from the selected operation's OpenAPI responses.
