Colorado (CO) Title & Registration - Developer Guide


1. Overview & Introduction

The Colorado (CO) Title & Registration API submits and processes vehicle title and registration transactions with the Colorado Department of Motor Vehicles (DMV), returning transaction status and confirmation data. It is intended for dealers, service providers, and platforms that need to file title/registration work electronically rather than through manual DMV channels.

The central domain object is the transaction. A transaction bundles everything a title/registration filing needs — the vehicle, its owners (and optional co-owner), any lessor/lessee and lienholder parties, prior-title information, and trade-ins — into a single submission (see the COEVRTransactionDTO schema). You create a transaction, optionally revise it, and the platform processes it asynchronously against the DMV. A transaction carries a transactionType (see TransactionTypeEnum) that governs how it is routed and reported; for this API the EVR/Interstate flows are the relevant ones.

Every transaction is addressable by two identifiers: a system-assigned integer transactionId and a client-supplied refNumber (a UUID). The operations that act on an existing transaction accept either form in the same path position (documented in the spec as "Either int transactionId or uuid refNumber"). Callbacks correlate results back to your submission using these identifiers.

The API is served from a single base host with a switchable environment segment (api, api-stage, api-test), defined under servers in the spec. Treat api as production and the others as pre-production. Do not hardcode the full URL in prose or code beyond the environment variable — read it from the spec's servers block.

Transactions contain personally identifiable and regulated data — driver license numbers, dates of birth, FEINs, owner addresses, and lien details. Treat all request and callback payloads as sensitive (see Data sensitivity).

Corresponding Title & Registration Notifications product: The Title & Registration Notifications product serves as a complementary offering to this Title & Registration service. Together, the transaction and notification capabilities provide a complete ecosystem for both initiating vehicle transaction requests and staying informed of relevant updates through secure, automated notifications. See that product in the Catalog for more details.


2. Getting Started / First Call

Prerequisites

  • Vitu-issued OAuth 2.0 client credentials. Obtain these from the Key Management area within Vitu's Developer Portal.
  • The ability to reach the environment host defined in the spec's servers block.
  • (Optional but recommended) A network-accessible HTTPS endpoint to receive status callbacks.

Shortest happy path

  1. Get a token. Use the client-credentials grant against the token endpoint defined in the keycloak security scheme, requesting the oneapi:access scope.
  2. Submit a transaction. Call the transaction-creation operation (CreateTransaction) with a COEVRTransactionDTO body. Optionally supply a callbackUrl query parameter so results are pushed to you.
  3. Receive acknowledgement. A successful submission is accepted for asynchronous processing — it does not mean the DMV filing is complete.
  4. Learn the outcome. Either receive a callback at your callbackUrl (see Asynchronous / callback patterns) or, for fee data, call the fee-retrieval operation (GetTransactionFees).
# 1. Token (client credentials)
POST {tokenUrl from keycloak scheme}
grant_type=client_credentials&scope=oneapi:access
→ { "access_token": "...", "expires_in": ... }

# 2. Submit
POST {create-transaction operation}?callbackUrl=https://you.example.com/hooks/co-evr
Authorization: Bearer <access_token>
Content-Type: application/json
{ ...COEVRTransactionDTO... }   # see spec for the full body
→ 202 Accepted (processing asynchronously)

For exact field names, required fields, and enum values in the body, read the COEVRTransactionDTO schema in the spec.


3. Authentication & Access Walkthrough

Authentication uses OAuth 2.0 client credentials. The formal definition lives in the spec's securitySchemes under keycloak (grant type, token URL, scope). This section covers only the operational how-to.

Obtaining credentials. Client credentials are issued by Vitu and are retrievable from the Key Management area of Vitu's Developer Portal. Keep the client secret confidential and rotate it per your organization's policy.

Getting a token. Exchange your credentials at the token endpoint defined in the keycloak scheme, requesting the oneapi:access scope. Every API operation in this spec requires that scope.

Attaching the token. Send the token as a bearer credential on the Authorization header of each API request.

Token lifecycle.

  • Tokens expire; the token response's expiry value is authoritative. Cache the token and reuse it until shortly before expiry rather than requesting one per call.
  • On a 401 response, obtain a fresh token and retry once. Repeated 401s after a fresh token indicate a credential or scope problem, not an expiry problem — stop and check configuration.
  • A 403 means the caller is authenticated but not authorized for the API; a new token will not help.

Alternatives. Only one security scheme (keycloak, client credentials) is defined. There is no API-key or user-interactive flow in this spec.


4. Key Concepts & Glossary

TermMeaning
TransactionThe unit of work: a full title/registration filing described by COEVRTransactionDTO. Created, updated, cancelled, and processed asynchronously.
transactionId / refNumberThe two ways to address an existing transaction. transactionId is the system integer; refNumber is a client-supplied UUID. Operations on an existing transaction accept either.
transactionTypeRouting/reporting classifier for a transaction (TransactionTypeEnum). Defaults to INTERSTATE in the spec. Distinct from applicationType.
applicationTypeWhat the filing accomplishes for the vehicle (e.g., title-and-registration vs. title-only). Note the transaction body and the success callback define different value sets for this concept — see the warning below.
serviceTypeLevel of service requested (ServiceTypeEnum), e.g., forms-and-fees vs. full service. Affects downstream processing.
Owner / co-owner / lessor / lessee / lienholderThe parties on a transaction. Individuals vs. businesses are distinguished by an isIndividual flag within each party. Lessor/lessee are relevant to lease sales; lienholders (up to two) capture financing.
Trade-in vehicleOptional vehicle(s) applied against the taxable selling price.
FeeA calculated charge on a transaction (FeeDTO), classified by FeeTypeEnum (state fee, state tax, vendor fee, etc.), retrievable after the transaction is processed.
CallbackAn asynchronous notification delivered to your callbackUrl describing an outcome (CallbackDTO and its subtypes).
universalStatus / TransactionStatusEnumStatus vocabularies reported in callbacks. universalStatus conveys the transaction's overall lifecycle position; TransactionStatusEnum appears in the success callback. Consult the spec for the value lists.

Lifecycle (conceptual). A transaction is submittedaccepted for processing (HTTP 202) → processed asynchronouslyterminal outcome reported by callback (success/failure) and reflected in status fields. Fees become available once calculation completes. A transaction may be updated or cancelled while it is still open.


5. Common Use cases & Integration Patterns

Operations are referenced by their operationId. See the spec for request/response shapes.

Scenario A - Submit and confirm a title/registration filing

  1. CreateTransaction — submit the COEVRTransactionDTO. Supply callbackUrl to receive the outcome. Response is 202 (accepted, async).
  2. Await outcome — receive a success or failure callback at your endpoint, correlated by refNumber/transactionId.
  3. GetTransactionFees — retrieve the calculated fees once processing has produced them.

Intent: the create step files the work; confirmation is asynchronous. The 202 is an acknowledgement, not a completion signal.

Scenario B - Revise a not-yet-final transaction

  1. CreateTransaction — initial submission.
  2. UpdateTransaction — resubmit the full transaction to correct or complete it (address by transactionId or refNumber).
  3. Await outcome — new callback reflects the updated result.

Intent: use update to fix validation issues or add data before the filing is finalized.

Scenario C - Cancel a transaction

  1. CancelTransaction — cancel by identifier, optionally supplying a message describing the reason.

Intent: withdraw work that should not proceed. Cancellation is itself processed asynchronously (202).

Scenario D - Quote fees

  1. Submit or update a transaction as above.
  2. GetTransactionFees — read the fee breakdown (FeeDTO, with detail lines and fee types) after calculation completes.

Intent: obtain state fees, taxes, and vendor fees for display or reconciliation. Fees are computed by the platform, not supplied by you.

  • Prefer callbacks over polling. The API is callback-oriented; register a callbackUrl on the mutating operations rather than polling for status. If you cannot host a callback endpoint, GetTransactionFees is the only pull-style read available in this spec — there is no general "get transaction status" read operation (see gap note in §6).
  • Use refNumber as your correlation key. Generate the UUID yourself so you can correlate submissions and callbacks without waiting for the system transactionId.
  • Treat every mutating call as async. Downstream state does not exist at the moment you receive 202.

6. Behavioral & Operational Notes

  • Acknowledgement ≠ completion. Create, update, and cancel all return 202 Accepted. The DMV outcome is only known later via callback and status fields. Determine success from the callback's status/universalStatus, not from the HTTP code.
  • Success signal lives in the payload, not the status code. For processed transactions, inspect the success/failure callback (SuccessCallbackDTO / FailureCallbackDTO) and its status fields. A SuccessCallbackDTO may still carry auditErrors/auditMessages; a FailureCallbackDTO carries errors.
  • Update semantics — assume full replacement. UpdateTransaction takes the same complete COEVRTransactionDTO as create. Send a full, self-consistent representation; do not assume field-level merge/patch behavior.
  • Dual identifiers are interchangeable on path operations. Passing either transactionId or refNumber addresses the same transaction. Be consistent within a workflow to avoid confusion in your own logs.
  • Callback authenticity. When an HMAC key is configured for callbacks, callback payloads are signed using HMAC/SHA-256 (base64-encoded), per the callback description in the spec. Verify the signature before trusting a callback. Configuration of that key is out of band — coordinate with Vitu.
  • Fees are calculated, and availability is timing-dependent. GetTransactionFees reflects platform-calculated values; results may not be present until processing has advanced. Expect eventual consistency between submission and fee availability.
  • Rate limiting is signalled per-response. All operations return RateLimit-Limit and RateLimit-Reset headers; 429 responses add Retry-After. See Rate limiting.

7. Asynchronous / Callback Patterns

The mutating operations declare an onStatusChange callback delivered by HTTP POST to the callbackUrl you supply at submission time.

Flow: you submit → receive 202 → the platform later POSTs a CallbackDTO to your endpoint when the transaction's state changes.

Payload shape. CallbackDTO is polymorphic, discriminated by callbackType (SUCCESS, FAILURE, DMVDESK, EVR, INVOICED, per the discriminator mapping). Branch on callbackType and deserialize to the matching subtype. Consult the spec for each subtype's fields.

NOTE: CallbackTypeEnum and the discriminator mapping differ in the number of values shown (the enum lists fewer than the mapping). Rely on the discriminator mapping in CallbackDTO as the source of truth, and handle unknown callbackType values defensively.

Correlation. Match a callback to its originating submission via refNumber (UUID) and/or transactionId.

Authenticity. If an HMAC key is configured, verify the HMAC/SHA-256 signature (base64) before acting on the callback.

Delivery expectations. Your endpoint should return 200 to acknowledge receipt. Make handling idempotent — design for the possibility of duplicate or repeated deliveries.

​> Corresponding Title & Registration Notifications product: The Title & Registration Notifications product serves as a complementary offering to this Title & Registration service. Together, the transaction and notification capabilities provide a complete ecosystem for both initiating vehicle transaction requests and staying informed of relevant updates through secure, automated notifications. See that product in the Catalog for more details.


8. Rate Limiting & Quotas

Every response carries RateLimit-Limit and RateLimit-Reset headers, and 429 Too Many Requests responses additionally carry Retry-After. Read these headers rather than hardcoding limits — the numeric values live in the spec and in the runtime headers, and will drift.

Handling strategy: on 429, wait for the interval indicated by Retry-After (or until RateLimit-Reset) before retrying, and apply exponential backoff with jitter if 429s persist. Proactively throttle when RateLimit-Limit indicates you are near the ceiling.


9. Error Handling & Troubleshooting

Error responses use the spec's Errors array (of Error) for validation/not-found/server classes, and a {code, message} object for auth and rate-limit classes. Treat these classes categorically:

ClassMeaningRetryable?Action
Auth (401)Missing/expired/invalid tokenYes, onceRe-obtain a token and retry once. Persistent → check credentials/scope.
Forbidden (403)Authenticated but not authorizedNoVerify entitlement with Vitu; do not retry.
Validation (400)Malformed or invalid request body/paramsNoFix the request per the returned messages; resubmit.
Not found (404)Referenced transaction/resource missingNoVerify the identifier; a wrong transactionId/refNumber won't succeed on retry.
Rate limit (429)Too many requestsYesHonor Retry-After, then back off. See Rate limiting.
Server (500)Platform-side failureYesRetry with exponential backoff + jitter; stop after a bounded number of attempts and escalate.

Backoff convention: exponential backoff with jitter for retryable classes (429, 500, transient 401-after-refresh). Cap total attempts and elapsed time; surface a durable failure to the caller rather than retrying indefinitely.

For exact field structure of Errors/Error, read the spec.


10. Data Sensitivity & Compliance Notes

Transaction payloads and callbacks carry regulated personal data: driver license numbers, dates of birth, FEINs, physical/residence addresses, and lienholder/financial details. Handle accordingly:

  • Transmit only over TLS (enforced by the https:// server host).
  • Do not log full request/callback bodies; redact PII in logs and error reports.
  • Restrict storage and access to what your integration genuinely needs, and apply your organization's retention policy.
  • Verify callback signatures before persisting or acting on inbound data.

This is handling guidance, not legal advice.


11. Support & Resources

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