Registration Fee Estimator - Developer Guide


1. Overview & Introduction

The Registration Fee Estimator calculates estimated title and registration fees for a vehicle based on jurisdiction, vehicle attributes, and transaction type. It is intended to be called before a transaction is submitted, so that an integrating application can present an accurate cost breakdown to a dealer or end user up front.

The core domain noun is the transaction: a description of a vehicle sale/registration event in a specific U.S. jurisdiction. Every request is jurisdiction-specific — the state determines which fields are meaningful and which fee rules apply. This is reflected structurally in the spec: the request bodies are polymorphic, discriminated by a state property, so a request is really a state-specific variant (for example, the California variant versus the Texas variant). The vehicle is the primary sub-entity of a transaction; depending on jurisdiction a transaction may also carry trade-in vehicles and other jurisdiction-specific attributes. The response is a fee breakdown: a set of itemized fees plus tax-related summary values.

There are two ways to request an estimate, corresponding to the two operations in the spec (CalculateFees and CalculateEstimateFees). Both return the same fee-breakdown response shape but accept different request models — see Key concepts and the AI Agent Reference for how they differ.

The API is served from a single base host with a selectable environment segment (production, staging, and test); the environment values and full server URL are defined in the spec's servers block. All operations require OAuth 2.0 authentication (see Authentication). Requests may describe individuals or businesses and can include personally identifying and address information; treat request and response payloads as sensitive (see Data sensitivity).


2. Getting Started / First Call

Prerequisites

  • API credentials issued by Vitu. Obtain these from the Key Management area within Vitu's Developer Portal.
  • The ability to perform an OAuth 2.0 client-credentials token exchange.
  • Knowledge of the jurisdiction (state) you are estimating for, since it determines the request variant.

Shortest path to one successful estimate

  1. Obtain a token. Exchange your client credentials at the token endpoint defined by the keycloak security scheme, requesting the oneapi:access scope.
  2. Choose the operation. For a full transaction-shaped request, use the fee-calculation operation (CalculateFees). For the lighter estimate model, use the estimate operation (CalculateEstimateFees).
  3. Build the request body for your jurisdiction. Set the discriminator state to your jurisdiction's code; this selects the correct state-specific variant. Populate the fields that variant defines. Refer to the spec for the exact field set — it differs per state.
  4. Send the request to the chosen environment host with the bearer token attached.
  5. Read the fee breakdown from the success response — the itemized fees and tax summary values (see the response schema in the spec).

Illustrative flow (values omitted; consult the spec for exact field names and the security scheme for the token URL):

# 1. Get a token
POST <token endpoint from keycloak scheme>
  grant_type=client_credentials
  scope=oneapi:access
  (client credentials)

# 2. Request an estimate
POST <base URL>/<fee-calculation or estimate operation path>
  Authorization: Bearer <access_token>
  Content-Type: application/json

  { "state": "<jurisdiction code>", ... }   # state-specific body per the spec

3. Authentication & Access Walkthrough

Authentication uses OAuth 2.0 client credentials. The formal definition — flow type, token URL, and scope name — is the keycloak security scheme in the spec. Do not hardcode values from this prose; read them from the scheme.

Obtaining credentials. Credentials are issued by Vitu and are available from the Key Management area within Vitu's Developer Portal.

Obtaining a token. Perform a client-credentials exchange against the token URL in the keycloak scheme, requesting the oneapi:access scope. You receive a bearer access token.

Attaching the token. Send the token as a bearer credential on every operation. Both operations declare the same security requirement (keycloak with oneapi:access).

Token lifecycle. Tokens expire. Cache and reuse a token until shortly before its expiry, then request a new one. There is no refresh-token step in the client-credentials flow — simply request a fresh token. On a 401 (not authenticated), obtain a new token and retry once; a persistent 401 indicates a credential or scope problem. A 403 means the token is valid but lacks permission — do not retry; resolve access with Vitu.

Environment differences. The environment is selected via the server variable in the spec's servers block (production, staging, test). Confirm that your credentials are valid for the environment you target.

Single scheme: Only one security scheme (keycloak, client-credentials) exists. There is no API-key or user-interactive flow — do not expect alternatives.


4. Key Concepts & Glossary

  • Transaction — The jurisdiction-specific description of a vehicle sale/registration event. It is the top-level request model for the fee-calculation operation and is polymorphic on state.
  • State (discriminator) — The state property selects which state-specific request variant applies. Each variant defines its own set of relevant fields; a field valid in one state may not exist in another. This is the single most important input: it governs both request shape and fee logic.
  • Vehicle — The primary sub-entity of a transaction, also polymorphic on state. Carries attributes such as vehicle type, use type, weight, and jurisdiction-specific characteristics that drive fee and tax computation.
  • Trade-in vehicle(s) — Optional sub-entities representing vehicles traded in as part of the transaction, where the jurisdiction supports trade-in credit. Presence and shape vary by state.
  • Transaction type — A classifier passed as a query parameter on the fee-calculation operation (see TransactionTypeEnum in the spec).
  • Registration action / period, plate category & type, use type, fuel type, body type — Jurisdiction-scoped classifiers that shape the calculation. The allowed values differ per state; always read the enum referenced by the specific state variant, not a global list.
  • Fee breakdown (response) — The result model: a collection of itemized fees (each with a name, value, fee type, and optional detail lines) plus tax/price summary values such as taxable selling price and applied trade-in value. See the response schema and FeeDTO/FeeTypeEnum in the spec.
  • Estimate model vs. transaction model — The estimate operation accepts a distinct, state-discriminated estimate request model; the fee-calculation operation accepts the transaction model. Both yield the same fee-breakdown response.

Relationships & dependencies: A request is state → (variant of transaction or estimate) → vehicle (+ optional trade-ins). There are no server-side stored resources, no identifiers to create first, and no lifecycle states. Each call is independent and stateless.


5. Common Use Cases & Integration Patterns

Both operations are synchronous, stateless, single-call estimates. There is no resource to create, poll, or clean up, and no ordering dependency between calls. The "pattern" work is almost entirely about assembling a correct, jurisdiction-appropriate request.

Use case A - Estimate fees for a straightforward purchase

  1. Obtain a token (oneapi:access).
  2. Determine the jurisdiction and set state.
  3. Populate the estimate request model for that state (use CalculateEstimateFees), including selling price, vehicle classifiers, and address/jurisdiction fields the variant requires.
  4. Read the fee breakdown from the response.

Intent: the estimate operation is the lighter-weight path when you have summary-level inputs rather than a full transaction record.

Use case B - Estimate fees from a full transaction record

  1. Obtain a token.
  2. Build the transaction model for the jurisdiction (CalculateFees), including the vehicle and any tradeInVehicles.
  3. Optionally set the transactionType query parameter.
  4. Optionally set the on-behalf-of user header if acting for another user (see the parameter in the spec).
  5. Read the fee breakdown.

Intent: the fee-calculation operation aligns with a complete transaction object you already hold, and supports transaction-type and on-behalf-of context.

Use case C - Comparing scenarios (trade-in, lease vs. purchase)

Issue multiple independent calls varying only the relevant inputs (e.g., trade-in values, sale type, lease terms) and compare the returned breakdowns. Because calls are stateless, scenario comparison is just repeated invocation — no correlation or sequencing required.

Recommended patterns

  • Cache tokens across calls; do not fetch a token per request.
  • Select the correct state variant before building the body; validation failures most often come from sending fields that don't belong to the target state's variant.
  • Treat every call as retry-safe on transient failures (see Error handling) — they are read-only computations.

6. Behavioral & Operational Notes

  • Read-only / no side effects. Both operations compute and return an estimate. They create no persistent resource and change no server state. Repeated identical calls are safe and idempotent.
  • Estimates are non-binding. Returned values are estimated fees for pre-submission planning; they are not a commitment or a filed transaction.
  • Jurisdiction determines validity. Field applicability is governed by the state discriminator. Supplying fields outside the selected state variant, or omitting fields that variant requires, leads to validation errors rather than silent defaults.
  • additionalProperties: false. State variants forbid unknown properties. Extra or misnamed fields will be rejected — this is a common, easily-missed cause of 400.
  • Same response shape, two inputs. The estimate and fee-calculation operations share the fee-breakdown response, so downstream response-handling code can be common across both.
  • Enums are state-scoped and may grow. Many classifier enums are per-state and the spec indicates several are truncated (_enumCount exceeds the values shown). Always read allowed values from the spec for the specific state; never hardcode a copied list.

7. Rate Limiting & Quotas

The spec defines a rate-limit response (TooManyRequests, HTTP 429) returning the standard error schema. Treat 429 as retryable after a delay. The spec's description indicates a windowed limit ("retry after the window resets").


8. Environments & Sandbox Access

The environment is chosen through the server variable in the spec's servers block, which offers production, staging, and test targets (conceptually: a production environment and lower non-production environments for integration testing). Use a non-production environment for development and validation before pointing at production. Credentials are issued by Vitu via the Key Management area of the Developer Portal; confirm your credentials are provisioned for the environment you intend to call.


9. Error Handling & Troubleshooting

Errors return the spec's error schema (Errors, an array of Error, each with a message). Handle by class, not by memorizing individual messages:

ClassHTTPMeaningRetryable?Action
Auth (unauthenticated)401Missing/expired/invalid tokenOnce, after refreshGet a new token, retry once; if it persists, check credentials/scope
Authorization403Authenticated but not permittedNoResolve access with Vitu
Validation400Malformed body, wrong state variant, unknown/missing fieldsNo (fix input)Correct the request per the state variant; check additionalProperties violations
Not found404Resource/route not foundNoVerify base URL, environment, and operation path
Rate limit429Limit exceededYesBack off and retry after the window resets
Server500Server-side failureYes (transient)Retry with backoff; escalate if persistent

Backoff convention: for retryable classes (429, 500, transient network), use exponential backoff with jitter and a capped number of attempts. Do not retry 400/403/404. Parse message values from the Errors array for diagnostics, but do not branch program logic on their exact text.


10. Data Sensitivity & Compliance Notes

Requests can include owner/business identity details and registered addresses, and some state variants include additional identifiers. Treat request and response payloads as sensitive: transmit only over TLS, avoid logging full payloads, and restrict storage/retention to what your use case requires. This is guidance, not legal advice.


11. Support & Resources

​For any API assistance, contact Vitu's API support team at [email protected].