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, with optional enrichment |
| 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. Optional parameters that trigger
a real, separately-billed lookup (like Address's include=demographics) are
called out explicitly below — everything else is included in the 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.
vehicle_history, emails, and phones come from the same call as everything else — including them costs nothing extra, and they're on by default. demographics is different: the field always appears in the response (empty by default), but it only gets populated when you explicitly pass include=demographics, because that triggers a second, separately-billed lookup.
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. 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 empty/false unless include=demographics found a match. |
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 }. |
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. The opt-in demographics call is skipped entirely in this case. |
Request
Request — with opt-in demographics
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. For any other VIN, demographics stay empty unless you pass include=demographics as in the second request example.
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
emails,phones. An unrecognized value is ignored, not rejected — you'll just get everything back.
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.
- 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 | |
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. |
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, with optional vehicle history, compliance-grade Do-Not-Call flags, or household demographics.
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
variant- Type
- string
- Description
vehicle_historyorcompliance— mutually exclusive, pick one. An unrecognized value is rejected with 400, not silently ignored.
- Name
include- Type
- string
- Description
Only recognized value:
demographics. Also rejected with 400 if garbled — it triggers a second, billed lookup, so typos don't fail silently.
variant | Adds | When to use it |
|---|---|---|
| (omit it) | Baseline identity + contact fields | You just need who's there and how to reach them. |
vehicle_history | Up to 3 vehicles historically linked to each match | You care about what they've owned, not just contact info. |
compliance | Real Do-Not-Call flags + a linked VIN | You're about to call or text and need to honor DNC status. |
Unlike include on VIN and Person, both variant and include here each select a specific, separately-billed vendor call — so an unrecognized value is rejected outright with a 400 instead of silently falling back to a 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, plusvariant/includewhen you passed them.
- Name
count- Type
- number
- Description
Number of matches found.
- 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 | |
address | object | { street, city, state, zip }. |
emails[] | array | { address, last_seen }. |
phones[] | array | { number, type, dnc } — dnc is only real with variant=compliance; otherwise false. |
vin | string | Present only with variant=compliance. |
vehicle_history[] | array | Present only with variant=vehicle_history: up to 3 { make, model, year } entries. |
demographics | object | Present only with include=demographics and a match was found: age, gender, marital_status, credit_range, home_owner, income_hh, net_worth_hh, children_hh, occupation, veteran_hh. |
demographics is capped at one enriched match per address — a limit in the underlying dataset, not something this API can lift. On a multi-resident address, at most one match ever carries a demographics object.
Errors
| Status | error | Cause |
|---|---|---|
| 400 | invalid_inputs | Missing/oversized address, invalid variant, or invalid include. |
| 400 | invalid_zip | Not a valid 5-digit (or ZIP+4) US ZIP. |
| 404 | no_data | No match on the primary lookup — not billed. |
Request
Request — compliance variant + demographics
Response — baseline
Response — variant=compliance + include=demographics
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.
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.
- Name
records- Type
- array
- Description
One entry per matched person. See the table below.
- 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 | Usually blank — these are filter inputs, not guaranteed per-record output. Use VIN or Person if you need a confirmed value. |
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 }. |
phones[] | array | { number, dnc }. |
demographics | object | credit_range, education, home_owner, income_hh, marital_status, net_worth_hh, num_adults_hh, num_children_hh, occupation_type. Frequently blank — this is a broad-search endpoint, not every record has every attribute on file. |
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. |
| 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. You're only billed on a response that actually returns data.
Every response tells you what request produced it. Optional parameters that shape the response — include on VIN and Person, variant and include together on Address — are echoed back whenever they're set, and simply omitted when they're not. Useful for auditing which (separately-priced) enrichment actually ran.
include isn't one concept. On VIN and Person it only decides which already-fetched fields to show, so an unrecognized value is ignored and falls back to showing everything. On Address, include=demographics (and variant) each select a real, separately-billed lookup — so an unrecognized value is rejected with 400 instead.
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 asked for it?
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.