The Ownership API is available on Enterprise plans only. If you're interested in access, contact us and we'll walk you through your options.
Deep dive into Ownership — four lookup types that resolve people and contact details from CarsXE's identity graph. For the interactive playground, see the API Reference.
The Ownership API answers one core question from four different starting points: who is connected to this vehicle or place? You always have something to start from — a VIN, a name and address, just an address, or a ZIP code — and the API resolves the rest: a registered owner, a resident, or a pool of people matching a set of filters.
All four lookup types are gated behind a single ownership entitlement on your API key and billed the same way: you're only ever charged when a match is found.
| You have… | You call… | You get back… |
|---|---|---|
| A 17-character VIN | GET /v1/ownership/vin | The vehicle's registered owner(s), contact info, and vehicle history |
| A full name + address | GET /v1/ownership/person | Contact details and any vehicle linked to that identity |
| Just a street address | GET /v1/ownership/address | Everyone on file at that address, contact info, and vehicle history |
| A ZIP code + filters | GET /v1/ownership/zip | A page of matching people in that area |
Every response follows a strict "charge only on non-empty results" rule:
if there's no match, you get a 404 with error: "no_data", your usage
counter doesn't move, and nothing is billed. When there is a match, billing
scales with how many records come back — not a flat rate per request:
the billed quantity is exactly the number of entries in
owners/matches/records, so a 3-owner VIN response bills 3 units, not
- ZIP is the one to watch here — it can return dozens of records in a
single page, so one call there can consume far more quota than a typical
VIN/Person/Address lookup. Across all four lookup types,
include(and, on Address and ZIP, the legacyvariant) only shapes which sections of the response are shown — everything is fetched, and billed, as a single base call.
VIN → Owner
Interactive reference: Ownership by VIN.
Look up the registered owner(s) of a vehicle by VIN, along with vehicle attributes, vehicle history, and contact details.
Required attributes
- Name
key- Type
- string
- Description
Your CarsXE API key.
- Name
vin- Type
- string
- Description
The 17-character vehicle identification number.
Optional attributes
- Name
include- Type
- string
- Description
Comma-separated subset of
demographics,emails,phones,vehicle_history. Omit it to get everything.
demographics, vehicle_history, emails, and phones all come from the same single call — nothing about include changes what's fetched or billed, only which sections appear in the response. Omit include to get everything back by default.
Response attributes
- Name
success- Type
- boolean
- Description
Whether the request was processed successfully.
- Name
vin- Type
- string
- Description
The VIN you queried.
- Name
include- Type
- string
- Description
Echoes the
includevalue you passed. Omitted entirely when you didn't pass one.
- Name
vehicle- Type
- object
- Description
Attributes for the queried vehicle. See the table below.
- Name
owners- Type
- array
- Description
One entry per person linked to this VIN, each billed as a separate unit (see the billing note above). Listed in order of recency — the most recent owner is first. See the table below.
- Name
error- Type
- string
- Description
Machine-readable error code, or
""on success.
vehicle object
| Field | Type | Description |
|---|---|---|
make, model | string | Vehicle make and model. |
year | number | null | Model year. |
manufacturer | string | Full legal manufacturer name. |
fuel_type, drive_type, transmission_type | string | e.g. Diesel, 4WD, A. |
body_type, body_subtype | string | e.g. PICKUP, Crew Cab. |
doors, engine_cylinders | number | null | |
vehicle_class, size, vehicle_type | string | e.g. Mainstream, Full-Size, TRUCK. |
owners[] object
| Field | Type | Description |
|---|---|---|
record_id | string | Internal identity ID for this person. |
first_name, last_name | string | |
age, gender | string | Empty when not on file. |
address | object | { street, city, state, zip }. |
demographics | object | marital_status, home_owner, children_in_household, veteran_in_household, occupation, income_range, net_worth_range, credit_range — all raw string values, empty unless on file. |
emails[] | array | { address, last_seen }. |
phones[] | array | { number, type, dnc }. |
vehicle_history[] | array | Up to 3 other vehicles linked to this owner: { make, model, year, vin }. |
Errors
| Status | error | Cause |
|---|---|---|
| 400 | invalid_inputs | Missing vin. |
| 400 | invalid_vin | Not a well-formed 17-character VIN. |
| 404 | no_data | No match — not billed. |
Request
Request — narrowing the response with include
Response — documentation sample VIN (includes populated demographics)
The sample VIN above returns a canned documentation response (before auth) with fully populated demographics so the complete shape is visible. Demographics come back by default for any other VIN too — the second request example just narrows the response down to the demographics section alone.
Person → Contact Info
Interactive reference: Ownership by person.
Resolve contact details for a specific person you already have a name and address for.
Required attributes
- Name
key- Type
- string
- Description
Your CarsXE API key.
- Name
first_name- Type
- string
- Description
Max 50 characters.
- Name
last_name- Type
- string
- Description
Max 50 characters.
- Name
address- Type
- string
- Description
Street address only (no city/state) — max 100 characters.
- Name
zip- Type
- string
- Description
5-digit US ZIP, optionally ZIP+4.
Optional attributes
- Name
include- Type
- string
- Description
Comma-separated subset of
demographics,emails,phones,vehicle_history. Omit it to get everything.
demographics, vehicle_history, emails, and phones all come from the same single call — nothing about include changes what's fetched or billed, only which sections appear in the response. Omit include to get everything back by default.
Response attributes
- Name
success- Type
- boolean
- Description
Whether the request was processed successfully.
- Name
input- Type
- object
- Description
Echo of the query you made —
first_name,last_name,address,zip, plusincludewhen you passed one.
- Name
count- Type
- number
- Description
Number of matches found — this is exactly what's billed (see the billing note above).
- Name
matches- Type
- array
- Description
One entry per matched person. See the table below.
- Name
error- Type
- string
- Description
Machine-readable error code, or
""on success.
matches[] object
| Field | Type | Description |
|---|---|---|
record_id | string | Internal identity ID for this person. |
first_name, last_name | string | |
age, gender | string | Empty when not on file. |
address | object | { street, city, state, zip } — city/state are the canonical values for the address, which may differ in formatting from what you sent. |
vin | string | A vehicle linked to this identity, or "" when none. |
emails[] | array | { address, last_seen }. Can be empty. |
phones[] | array | { number, type, dnc }. Can be empty — don't assume a match has both emails and phones. |
demographics | object | marital_status, home_owner, children_in_household, veteran_in_household, occupation, income_range, net_worth_range, credit_range — all raw string values, empty unless on file. |
vehicle_history[] | array | Up to 3 other vehicles linked to this identity: { make, model, year, vin }. |
Errors
| Status | error | Cause |
|---|---|---|
| 400 | invalid_inputs | Missing or oversized name/address. |
| 400 | invalid_zip | Not a valid 5-digit (or ZIP+4) US ZIP. |
| 404 | no_data | No match — not billed. |
Request
Response
Address → Residents
Interactive reference: Ownership by address.
Find everyone on file at a street address.
Required attributes
- Name
key- Type
- string
- Description
Your CarsXE API key.
- Name
address- Type
- string
- Description
Street address only, max 100 characters.
- Name
zip- Type
- string
- Description
5-digit US ZIP, optionally ZIP+4.
Optional attributes
- Name
include- Type
- string
- Description
Comma-separated subset of
demographics,emails,phones,vehicle_history. Omit it to get everything.
- Name
variant- Type
- string
- Description
Legacy alias (
vehicle_historyorcompliance) from beforeincludeexisted — still accepted and echoed back, but no longer changes what's fetched or shown. Useincludeinstead.
demographics, vehicle_history, emails, and phones all come from the same single call — nothing about include changes what's fetched or billed, only which sections appear in the response. Omit include to get everything back by default.
Response attributes
- Name
success- Type
- boolean
- Description
Whether the request was processed successfully.
- Name
input- Type
- object
- Description
Echo of the query you made —
address,zip, plusinclude/variantwhen you passed them.
- Name
count- Type
- number
- Description
Number of matches found — this is exactly what's billed (see the billing note above).
- Name
matches- Type
- array
- Description
One entry per matched resident. See the table below.
- Name
error- Type
- string
- Description
Machine-readable error code, or
""on success.
matches[] object
| Field | Type | Description |
|---|---|---|
record_id | string | Internal identity ID for this person. |
first_name, last_name | string | |
age, gender | string | Empty when not on file. |
address | object | { street, city, state, zip } — city/state are the canonical values for the address, which may differ in formatting from what you sent. |
vin | string | A vehicle linked to this identity, or "" when none. |
emails[] | array | { address, last_seen }. Can be empty. |
phones[] | array | { number, type, dnc }. Can be empty — don't assume a match has both emails and phones. |
demographics | object | marital_status, home_owner, children_in_household, veteran_in_household, occupation, income_range, net_worth_range, credit_range — all raw string values, empty unless on file. |
vehicle_history[] | array | Up to 3 other vehicles linked to this identity: { make, model, year, vin }. |
Errors
| Status | error | Cause |
|---|---|---|
| 400 | invalid_inputs | Missing/oversized address, or invalid variant. |
| 400 | invalid_zip | Not a valid 5-digit (or ZIP+4) US ZIP. |
| 404 | no_data | No match — not billed. |
Request
Response
ZIP → Area Search
Interactive reference: Ownership by ZIP.
Search a broader area for people matching optional gender, age, and income filters. This is the only one-to-many, paginated lookup in the product.
Required attributes
- Name
key- Type
- string
- Description
Your CarsXE API key.
- Name
zip- Type
- string
- Description
Exactly 5 digits.
Optional attributes
- Name
gender- Type
- string
- Description
MorF, case-insensitive.
- Name
min_age- Type
- string
- Description
Whole number. Optional — only forwarded upstream when provided (CarsXE does not apply a default).
- Name
max_age- Type
- string
- Description
Whole number. Optional — only forwarded upstream when provided (CarsXE does not apply a default).
- Name
income- Type
- string
- Description
Full label, letter code, or a loose case/whitespace variant of either. See the table below.
- Name
page- Type
- string
- Description
Default
1.
- Name
limit- Type
- string
- Description
Default
15, max100. Each record returned is billed individually, so a full page atlimit=100bills up to 100 units in one call.
- Name
include- Type
- string
- Description
Comma-separated subset of
demographics,emails,phones,vehicle_history. Omit it to get everything — same behavior as VIN/Person.
- Name
variant- Type
- string
- Description
Legacy, deprecated.
vehicle_historyis accepted and echoed back for backward compatibility, but no longer changes the response — useincludeinstead.
Valid income values
Pass the full string, the letter code alone, or a sloppy variant of either — f, F. $50,000-$59,999, and f all resolve to the same bucket.
| Code | Full value |
|---|---|
| — | Unknown |
A | Under $10,000 |
B | $10,000–$19,999 |
C | $20,000–$29,999 |
D | $30,000–$39,999 |
E | $40,000–$49,999 |
F | $50,000–$59,999 |
G | $60,000–$74,999 |
H | $75,000–$99,999 |
K | $100,000–$149,999 |
L | $150,000–$174,999 |
M | $175,000–$199,999 |
N | $200,000–$249,999 |
O | $250K + |
Response attributes
- Name
success- Type
- boolean
- Description
Whether the request was processed successfully.
- Name
zip- Type
- string
- Description
The ZIP you queried.
- Name
filters- Type
- object
- Description
Only the filters you actually set — not the resolved defaults.
- Name
page- Type
- number
- Description
Current page.
- Name
limit- Type
- number
- Description
Page size.
- Name
count- Type
- number
- Description
Number of records on this page — this is exactly what's billed for this call (see the billing note above).
- Name
records- Type
- array
- Description
One entry per matched person. See the table below.
- Name
include- Type
- string
- Description
Echoes the
includevalue you passed. Omitted entirely when you didn't pass one.
- Name
variant- Type
- string
- Description
Echoes the (legacy)
variantvalue you passed. Omitted entirely when you didn't pass one.
- Name
error- Type
- string
- Description
Machine-readable error code, or
""on success.
records[] object
| Field | Type | Description |
|---|---|---|
record_id | string | |
first_name, last_name | string | |
age, gender | string | Each record's own values, same as VIN/Person/Address — unrelated to the gender/min_age/max_age filter params (those only narrow which records match, they don't determine what's shown per record). |
address | object | { street, city, state, zip }. |
vin | string | Linked VIN, or "" when none. |
vehicle | object | null | { make, model, year }, or null when no vehicle is linked. |
emails[] | array | { address, last_seen }. Included by default; narrow with include. |
phones[] | array | { number, dnc }. Included by default; narrow with include. |
demographics | object | marital_status, home_owner, children_in_household, veteran_in_household, occupation, income_range, net_worth_range, credit_range — same shape as VIN/Person/Address, all raw string values. Frequently blank — this is a broad-search endpoint, not every record has every attribute on file. Included by default; narrow with include. |
vehicle_history[] | array | Up to 3 other vehicles linked to this person: { make, model, year, vin }. Included by default; narrow with include. |
Errors
| Status | error | Cause |
|---|---|---|
| 400 | invalid_zip | Missing or not exactly 5 digits. |
| 400 | invalid_gender | Not M/F after normalization. |
| 400 | invalid_age | min_age/max_age not a whole number. |
| 400 | invalid_income | Doesn't match any known code or label. |
| 400 | invalid_variant | Unrecognized variant value. variant is a legacy, inert alias — kept for backward compatibility, still validated, but no longer changes what's fetched or shown. |
| 404 | no_data | No records match — not billed. |
Request
Response
Shared behavior
Billing. All four lookups follow the same rule: zero records means a 404 with error: "no_data", no usage increment, and no charge. When there is data, you're billed per record returned, not per request — the charged quantity is exactly the number of entries in the response (owners/matches/records), so a 3-owner VIN response or a 40-record ZIP page bills 3 or 40 units respectively. ZIP is the one to watch: it's paginated and can return far more records per call (up to limit=100) than VIN/Person/Address typically do, so a single ZIP request can consume noticeably more quota than expected.
Every response tells you what request produced it. Optional parameters that shape the response — include on all four endpoints, plus the legacy variant on Address and ZIP — are echoed back whenever they're set, and simply omitted when they're not.
include is one concept everywhere now. On VIN, Person, Address, and ZIP alike, it only decides which already-fetched fields to show — the full record is always fetched and billed as a single base call regardless of what you pass. An unrecognized include value is ignored and falls back to showing everything; it's never rejected with 400. The variant param on Address and ZIP is a legacy, inert alias kept for backward compatibility — it no longer selects a different lookup.
Error codes
| Status | Meaning | Seen on |
|---|---|---|
| 200 | Success — at least one match found. | All four |
| 400 | Malformed input — fix the request before retrying. | All four |
| 401 | Missing/invalid API key, or an inactive account. | All four |
| 403 | api_not_enabled — your key doesn't have the ownership entitlement. | All four |
| 404 | no_data — valid request, zero matches, not billed. | All four |
| 429 | Usage limit reached for your plan. | All four |
| 503 | Kill-switch — Ownership temporarily unavailable. Body is { success: false, message: "The Ownership API is temporarily unavailable." } (no error code). | All four |
| 408 / 500 | Upstream timeout or vendor error — safe to retry. | All four |
Frequently asked questions
What is the Ownership API?
Which endpoint should I use?
- Have a VIN? Use
VIN. - Have a full name and address? Use
Person. - Only have an address? Use
Address. - Have a ZIP code and want a filtered list of people in that area? Use
ZIP.
Do I get charged if there's no match?
What's the difference between variant and include on the Address endpoint?
Why is demographics empty even though I didn't pass include?
Can a VIN or address resolve to more than one person?
Why are age and gender blank on ZIP search results?
Does this API require authentication?
Resolve vehicle owners, contact details, and address residents from CarsXE's identity graph — by VIN, name and address, address alone, or ZIP code. Enterprise only.