https://vinchex.com/api
The VinChex API provides endpoints for managing VINs and lienholders. The API uses OAuth 2.0 client credentials flow for authentication and returns JSON responses.
GET /vins, investigation is null while a VIN is pending or in progress. When present, it always includes a finding_code — treat that as a required decision input. See FindingCode and Investigation.The API uses OAuth 2.0 client credentials grant type for authentication. You need to obtain an access token before making requests to protected endpoints.
/oauth/token
Obtain an access token using client credentials.
| Parameter | Type | Required | Description |
|---|---|---|---|
| grant_type | string | Yes | Must be "client_credentials" |
| client_id | string | Yes | Your client ID |
| client_secret | string | Yes | Your client secret |
curl -X POST "https://vinchex.com/api/oauth/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "your_client_id",
"client_secret": "your_client_secret"
}'
{
"access_token": "42b6cbb60f1412da0422e8db7b2a8c5f9d3...",
"token_type": "Bearer",
"expires_in": 86400,
"expires_at": 1691766000,
"company_id": 123,
"company_name": "Example Company"
}
/oauth/revoke
Revoke an access token.
curl -X POST "https://vinchex.com/api/oauth/revoke" \
-H "Content-Type: application/json" \
-d '{
"token": "42b6cbb60f1412da0422e8db7b2a8c5f9d3..."
}'
All protected endpoints require a valid Bearer token in the Authorization header:
Authorization: Bearer your_access_token
The VinState data type represents the processing status of a VIN in the system. It is an integer-backed enum with the following values:
| Value | Label | Description |
|---|---|---|
| 0 | Inactive | VIN has been deactivated or removed from processing |
| 1 | Pending | VIN is queued for lienholder lookup processing |
| 2 | In Progress | VIN lienholder lookup is currently being processed |
| 3 | Completed | VIN lienholder lookup completed successfully |
0, 1, 2, 3) in the GET /vins state query parameterstate field. Internal Review records are exposed to API clients as In Progress (2).The Priority data type represents the validation priority level of a VIN in the system. It is an integer-backed enum with the following values:
| Value | Label | Description |
|---|---|---|
| 0 | Low | Low Risk |
| 1 | Medium | Medium Risk |
| 2 | High | High Risk |
GET /vins returns the integer value in the priority fieldThe VinQueue data type selects the processing workflow for a submitted VIN. It is a string-backed enum with the following values:
| Value | Label | Description |
|---|---|---|
| default_lien_check | Default Lien Check | Runs the standard provider lien-verification workflow. This is the default when queue is omitted. |
| california_lien_check | California Lien Check | Bypasses the provider workflow and routes the VIN to manual California DMV verification. |
The FindingCode data type is a string returned on
investigation.finding_code when a VIN is Completed (or Inactive).
Each code describes a condition observed in title/lien data relative to the asserted (expected) lienholder you submitted.
Codes are observations for your workflow—not legal conclusions or fraud determinations.
The finding_label column matches the human-readable string returned in the API.
Branch automation on finding_code; treat unknown future codes as “needs review.”
| Code | finding_label | Condition |
|---|---|---|
| LIEN_CONFIRMED | Expected lienholder appears on title data | The asserted (expected) lienholder appears on the available title data. |
| LIENHOLDER_HOLDS_TITLE | Expected party appears as owner on title | The expected party appears as the titled owner (not necessarily as a listed lienholder). |
| COMPETING_LIEN | A different lienholder is recorded on title | A different lienholder is recorded on title; the expected lender is not. |
| SECONDARY_LIEN | An additional lienholder appears alongside the expected lien | The expected lien is present and another distinct lienholder also appears. |
| TITLE_TRANSFER_NO_EXPECTED_LIEN | Title appears transferred without the expected lien | Title or ownership appears to have transferred without the expected lien remaining in place. |
| LIEN_NO_LONGER_PRESENT | A prior lien is no longer present on the current title | An earlier record showed a lien that is no longer present on the current title. |
| UNPERFECTED_TITLE | Title or ownership is present but the expected lien is not recorded | Title or ownership is present, but the expected lien is not recorded. |
| TITLE_PREDATES_ORIGINATION | Title data predates the origination/contract date | Available title evidence predates the loan origination or contract date. |
| RESTRICTED_UNCONFIRMED | Title data is restricted or suppressed | Title data is restricted or suppressed, so the lien status could not be confirmed further. |
| INCONCLUSIVE | Title data is incomplete for specialized routing | Available title data is incomplete for a definitive determination. |
| NO_DATA | No usable lienholder title records were available | No usable lienholder or title record was available for this VIN. |
GET /vins inside investigation.finding_code when investigation is non-nullstate or priority alone—always persist finding_codefinding_label and summary are human-readable helpers; branch automation on the codeThe StateAbbreviation data type is a string containing one of the following supported state, district, or territory abbreviations. UNKNOWN represents an unavailable or unrecognized jurisdiction.
| Abbreviation | State or Territory |
|---|---|
| AL | Alabama |
| AK | Alaska |
| AZ | Arizona |
| AR | Arkansas |
| CA | California |
| CO | Colorado |
| CT | Connecticut |
| DE | Delaware |
| FL | Florida |
| GA | Georgia |
| HI | Hawaii |
| ID | Idaho |
| IL | Illinois |
| IN | Indiana |
| IA | Iowa |
| KS | Kansas |
| KY | Kentucky |
| LA | Louisiana |
| ME | Maine |
| MD | Maryland |
| MA | Massachusetts |
| MI | Michigan |
| MN | Minnesota |
| MS | Mississippi |
| MO | Missouri |
| MT | Montana |
| NE | Nebraska |
| NV | Nevada |
| NH | New Hampshire |
| NJ | New Jersey |
| NM | New Mexico |
| NY | New York |
| NC | North Carolina |
| ND | North Dakota |
| OH | Ohio |
| OK | Oklahoma |
| OR | Oregon |
| PA | Pennsylvania |
| RI | Rhode Island |
| SC | South Carolina |
| SD | South Dakota |
| TN | Tennessee |
| TX | Texas |
| UT | Utah |
| VT | Vermont |
| VA | Virginia |
| WA | Washington |
| WV | West Virginia |
| WI | Wisconsin |
| WY | Wyoming |
| DC | District of Columbia |
| PR | Puerto Rico |
| AS | American Samoa |
| GU | Guam |
| MP | Northern Mariana Islands |
| VI | U.S. Virgin Islands |
| UNKNOWN | Unknown |
/vins
Get a paginated list of VINs with optional filtering.
Note: All filters are optional. queue is applied only when provided.
| Parameter | Type | Required | Description |
|---|---|---|---|
| vin | string | No | Partial VIN match (8-17 characters) |
| state | integer | No | Filter by VinState: 0=Inactive, 1=Pending, 2=In Progress, or 3=Completed |
| queue | string | No | Filter by VinQueue. Applied only when provided; may be combined with state. |
| per_page | integer | No | Results per page (1-10000, default: 100) |
| page | integer | No | Page number (1-1000, default: 1) |
curl -X GET "https://vinchex.com/api/vins?queue=california_lien_check&state=2&per_page=20&page=1" \
-H "Authorization: Bearer your_access_token"
{
"success": true,
"message": "VINs retrieved successfully",
"data": [
{
"id": 1234,
"vin": "1HGBH41JXMN109186",
"state": 2,
"registered_state": "CA",
"priority": 2,
"title_date": null,
"owner_start_date": null,
"lienholder": null,
"lien_paid": null,
"restricted_state": false,
"data_found": false,
"investigation": null
},
{
"id": 1235,
"vin": "1HGBH41KXMN109187",
"state": 3,
"registered_state": "TX",
"priority": 0,
"title_date": "2020-01-01",
"owner_start_date": "2019-11-15",
"lienholder": "Chase Auto Finance",
"lien_paid": false,
"restricted_state": false,
"data_found": true,
"investigation": {
"status": "completed",
"finding_code": "LIEN_CONFIRMED",
"finding_label": "Expected lienholder appears on title data",
"summary": "Expected lienholder appears on title data",
"observed": {
"lienholders": ["Chase Auto Finance"]
},
"evidence": null
}
}
],
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 98,
"last_page": 5,
"from": 1,
"to": 20
}
}
restricted_state=true and registered_state="CA".null while the VIN is Pending or In Progress. When the VIN is completed (or inactive), always an object with a non-null finding_code — a critical field for that VIN. See investigation details below.
On GET /vins,
investigation is
null while a VIN is
Pending or In Progress.
When the VIN is Completed (or Inactive), investigation
is always an object and always includes a non-null
finding_code
describing the title/lien condition observed for that VIN (see FindingCode).
Your organization decides urgency and who should act next from the finding — VinChex does not return destination or urgency.
investigation is present, finding_code is always set. Always read and persist it. Do not rely on state or priority alone.LIEN_CONFIRMED, COMPETING_LIEN, NO_DATA, TITLE_TRANSFER_NO_EXPECTED_LIEN).finding_label / summary are human-readable helpers; observed and evidence support audit and case work. Branch automation on finding_code.POST /vins/add using the default queue (omit queue or set default_lien_check).GET /vins (filter by vin or list with state as needed).state is Pending (1) or In Progress (2), investigation is null.investigation is present, always capture finding_code first, then finding_label, summary, observed, and evidence.finding_code to your own internal workflows (team, urgency, SLA, case type). Do not depend on VinChex for destination or urgency.investigation is null for in-flight VINs; when non-null it always has a finding_code.queue: "investigation_queue" on POST /vins/add.| Value | When |
|---|---|
| completed | A finding is available (see FindingCode). |
| failed | Evaluation could not finish; finding_code is still present (typically INCONCLUSIVE). Optional soft error may be set. |
While the VIN itself is Pending or In Progress, the entire investigation field is null (not an object with nested nulls).
"investigation": {
"status": "completed",
"finding_code": "TITLE_TRANSFER_NO_EXPECTED_LIEN",
"finding_label": "Title appears transferred without the expected lien",
"summary": "Title appears transferred without the expected lien",
"observed": {
"lienholders": ["Other Bank NA"],
"owners": ["Jane Doe"],
"title_transfer_date": "2025-11-02",
"owner_start_date": null
},
"evidence": {
"anchor_date": "2024-03-01",
"anchor_source": "lien_date",
"suppressed": false,
"assessed_at": "2026-07-29T18:00:00+00:00"
}
}
"investigation": {
"status": "completed",
"finding_code": "LIEN_CONFIRMED",
"finding_label": "Expected lienholder appears on title data",
"summary": "Expected lienholder appears on title data",
"observed": {
"lienholders": ["Your Finance Company"],
"owners": ["John Smith"]
},
"evidence": {
"anchor_date": null,
"anchor_source": null,
"suppressed": false,
"assessed_at": "2026-07-29T18:00:00+00:00"
}
}
When a lien is confirmed, top-level VIN fields (lienholder, priority, data_found) reflect normal lien verification.
| Field | Type | Description |
|---|---|---|
| status | string | completed or failed |
| finding_code | string | Primary outcome field — always present when investigation is non-null. See FindingCode for the full catalog and condition descriptions. |
| finding_label | string | Soft, non-assumptive description of what investigation data shows |
| summary | string | Short customer-facing finding summary (no prescribed team handoff) |
| observed | object|null | Observed title parties/dates (e.g. lienholders, owners, transfer dates) |
| evidence | object|null | anchor_date, anchor_source, suppressed, assessed_at |
| error | string | Present only on some failed evaluations |
investigation.finding_code (plus observed / evidence). Map codes to urgency and internal teams yourself./vins/add
Add multiple VINs to the system for asynchronous processing. Default lien checks enter Pending (1); California lien checks enter In Progress (2) and bypass the standard provider workflow.
| Field | Type | Required | Description |
|---|---|---|---|
| vins | array | Yes | Array of VIN objects |
| vins[].vin | string | Yes | VIN string (10-17 alphanumeric characters) |
| vins[].lienholder | string | Yes | Lienholder name (required for every queue, max 255 characters, case-insensitive lookup). |
| vins[].origination_date | date | No | Date when the VIN originated (format: YYYY-MM-DD) |
| vins[].queue | string | No | VinQueue value. Defaults to default_lien_check when omitted. |
| options.ignore_duplicates | boolean | No | When true, duplicate VINs in the same request are collapsed to their first occurrence instead of causing validation to fail. |
curl -X POST "https://vinchex.com/api/vins/add" \
-H "Authorization: Bearer your_access_token" \
-H "Content-Type: application/json" \
-d '{
"vins": [
{
"vin": "1HGBH41JXMN109186",
"lienholder": "Chase Auto Finance",
"origination_date": "2025-09-15",
"queue": "default_lien_check"
},
{
"vin": "2T1BURHE0JC123456",
"lienholder": "California Test Lender",
"origination_date": "2025-09-20",
"queue": "california_lien_check"
}
],
"options": {
"ignore_duplicates": true
}
}'
{
"success": true,
"message": "VINs have been queued for processing",
"processing_type": "queued",
"total_vins": 2,
"size": "0.5 KB"
}
options.ignore_duplicates: true to skip duplicatesqueue: "california_lien_check" on an individual VIN to route it to manual California DMV verification. A lienholder is still required./vins/remove
Deactivate VINs by setting their state to VinState INACTIVE
curl -X PATCH "https://vinchex.com/api/vins/remove" \
-H "Authorization: Bearer your_access_token" \
-H "Content-Type: application/json" \
-d '{
"vins": [
"1HGBH41JXMN109186",
"2T1BURHE0JC123456"
]
}'
{
"success": true,
"message": "Processed 2 VINs successfully, 0 failed",
"summary": {
"total": 2,
"successful": 2,
"failed": 0
}
}
/vins/unique-count
Return the number of distinct VINs belonging to the authenticated company.
{
"success": true,
"message": "Unique VIN count retrieved successfully",
"data": {
"unique_vins": 1250
}
}
Every lienholder endpoint is company scoped. Your visible scope is global plus your company-owned lienholders.
california_lien_check_enabled is always the authenticated company's effective value, including for a global lienholder.
/lienholders
Returns visible lienholders with pagination. Optional query parameters are search (1-255 characters), california_lien_check_enabled=true|false, per_page (1-100, default 100), and page (positive page number).
curl -X GET "https://vinchex.com/api/lienholders?california_lien_check_enabled=true&per_page=100" \
-H "Authorization: Bearer your_access_token"
{
"success": true,
"data": [
{
"id": 42,
"name": "Chase Auto Finance",
"is_global": true,
"aliases": [],
"california_lien_check_enabled": true
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 100,
"total": 1
}
}
The literal query value false returns disabled visible lienholders, including both missing settings and settings explicitly stored as false.
/lienholders/{lienholder}
Returns one visible lienholder using the same fields as the list endpoint. An ID owned by another company and a nonexistent ID both return 404.
curl -X GET "https://vinchex.com/api/lienholders/42" \
-H "Authorization: Bearer your_access_token"
{
"success": true,
"data": {
"id": 42,
"name": "Chase Auto Finance",
"is_global": true,
"aliases": [],
"california_lien_check_enabled": true
}
}
/lienholders/search
Search accessible global and company lienholders by a case-insensitive partial name or alias match. Each result includes the authenticated company's effective California setting.
name is required and must be between 1 and 255 characters.
curl -X GET "https://vinchex.com/api/lienholders/search?name=Chase" \
-H "Authorization: Bearer your_access_token"
{
"success": true,
"message": "Found 1 lienholder(s) matching 'Chase'",
"data": [
{
"id": 42,
"name": "Chase Auto Finance",
"aliases": [
{
"id": 87,
"alias": "Chase Auto",
"alias_type": "user_generated"
}
],
"is_global": true,
"california_lien_check_enabled": true
}
]
}
/lienholders/create
Create a company-scoped lienholder with optional aliases. Returns HTTP 201 on success and HTTP 409 when the name already exists for the company or globally.
curl -X POST "https://vinchex.com/api/lienholders/create" \
-H "Authorization: Bearer your_access_token" \
-H "Content-Type: application/json" \
-d '{
"name": "Example Credit Union",
"aliases": [
{"alias": "Example CU"}
]
}'
{
"success": true,
"message": "Lienholder created successfully",
"data": {
"id": 43,
"name": "Example Credit Union",
"is_global": false,
"aliases": [
{
"id": 88,
"alias": "Example CU",
"alias_type": "user_generated"
}
],
"california_lien_check_enabled": false
}
}
HTTP 409 Conflict: Returned with success: false when the requested name already exists for the company, exists globally, or matches an existing alias.
/lienholders/{lienholder}/settings
Send one or more known settings. Today the supported key is california_lien_check_enabled (boolean). The operation is idempotent, changes only the authenticated company's settings, and returns id plus the settings that were updated. Additional settings can be added later without requiring this field.
curl -X PUT "https://vinchex.com/api/lienholders/42/settings" \
-H "Authorization: Bearer your_access_token" \
-H "Content-Type: application/json" \
-d '{"california_lien_check_enabled": true}'
Send {"california_lien_check_enabled": false} to disable it. False persists a disabled setting and does not delete the lienholder.
One company's change does not change another company's setting.
A linked company lienholder uses its canonical parent setting. Linking, unlinking, or reparenting changes which canonical group's setting applies; settings are not migrated.
Eligible restricted California provider results remain IN_PROGRESS in the California Lien Check Queue.
{
"success": true,
"data": {
"id": 42,
"california_lien_check_enabled": true
}
}
{
"message": "At least one setting must be provided.",
"errors": {
"settings": [
"At least one setting must be provided."
]
}
}
{
"error": "unauthorized",
"error_description": "Invalid or expired token"
}
{
"message": "Not Found"
}
Sandbox accounts use the same OAuth credentials, endpoints, and payloads as production. Ask your Vinchex contact to enable sandbox mode for your account. VINs submitted by a sandbox account are never sent to real data providers — a built-in simulator fabricates a result for each VIN, typically within ~1 minute. Reserved CA in-progress VINs are the exception: they stay at state 2 (In Progress) and are never completed by the simulator.
By default the simulator returns realistic, randomized results. To get a specific result on demand for testing, submit one of the reserved VINs below instead — regardless of the lienholder value you submit, the result is deterministic. They're reusable: resubmitting a completed reserved VIN runs it through the same flow again.
| Scenario | Reserved VINs | Result |
|---|---|---|
| Confirmed lien | 1HGCM82633ACLR001–003 | Matches submitted lienholder, priority Low |
| Possible lien loss | 1HGCM82633ALOS001–003 | Different lienholder than submitted, priority High |
| Restricted state | 1HGCM82633ARES001–003 | Matches submitted lienholder, restricted_state: true, priority Medium |
| No results | 1HGCM82633ANOD001–003 | Completes with data_found: false, priority High |
| Unknown lienholder | 1HGCM82633AUNK001–003 | Lienholder returns as "Unknown", priority Medium |
| Owner start date | 1HGCM82633AOSD001–003 | Matches submitted lienholder, guaranteed owner_start_date, priority Low |
| CA confirmed lien | 1HGCM82633ACLC001–003 | Auto-routes to California queue; registered_state: "CA", investigation.finding_code: "LIEN_CONFIRMED", priority Low |
| CA competing lien | 1HGCM82633ACMP001–003 | Auto-routes to California queue; registered_state: "CA", finding_code: "COMPETING_LIEN", priority High |
| CA clear title | 1HGCM82633ACTL001–003 | Auto-routes to California queue; registered_state: "CA", data_found: false, finding_code: "UNPERFECTED_TITLE", priority Medium |
| CA in progress | 1HGCM82633ACIP001–003 | Auto-routes to California queue; stays at state: 2 (In Progress) indefinitely. The simulator never completes these VINs. |
Use 1HGCM82633ACLC / ACMP / ACTL / ACIP for the California verification queue. Use 1HGCM82633ARES00x only when you need a default-path result with restricted_state: true — that is not the California queue.
Submit 1HGCM82633ACLR001 (default path) or 1HGCM82633ACLC001 (California queue) via Add VINs, then poll List VINs after about a minute to see the deterministic result. 1HGCM82633ACIP001 (California queue) stays at state 2 when polled — it will not complete. These VINs are reserved — avoid using them for real production data.
Error bodies vary between OAuth authentication and protected resource endpoints. Handle the documented shape for each category.
{
"success": false,
"message": "Validation failed",
"errors": {
"vin": ["The vin field is required."]
}
}
{
"error": "unauthorized",
"error_description": "Invalid or expired token"
}
{
"success": false,
"message": "Processed 0 VINs successfully, 2 failed",
"summary": {
"total": 2,
"successful": 0,
"failed": 2
}
}
{
"success": false,
"message": "An error occurred while processing the request",
"error": "Detailed error message"
}
error responses separately from resource endpoint success responsesinvestigation is null while pending/in progress; when present, always read finding_codepriority looks routinefinding_code; map unknown codes to reviewFor API support, questions, or feature requests, please contact our development team.
Additional technical documentation and guides are available in the project repository.
Access tokens normally expire after 24 hours. Request another token through the client-credentials endpoint before expiration.