Developers
DealerData API
Verified contacts and store data for every US and Canadian car dealership, over REST or MCP. Search and counts are free; unlocking a record spends credits. Built for scripts and AI agents: every filter is validated, and a typo is refused with the valid options instead of returning the wrong list.
REST base URL
https://api.usedealerdata.com/functions/v1/api/v1
MCP server
https://api.usedealerdata.com/functions/v1/mcp
Auth
Authorization: Bearer dd_live_… Keys are made in your account.
For agents: the same reference as Markdown and OpenAPI 3.1.
Pull a list in five calls
GET /filtersto see valid roles, OEMs, states, bands and prices.GET /contacts/countwith your filters to size the list (free).GET /contactspage by page, passingcursor=<next_cursor>until it comes back null.POST /unlockwith the ids you want and"return_rows": trueto get the emails in the same call.GET /export/contactsany time for everything you have unlocked.
Lists take comma separated values (role=gm,gsm). Responses may carry warnings, for example when a plural filter name was read as the singular or an OEM matches no store.
GET /contacts
Search contacts (free)
Dealership staff matching the filters, best ranked first. Emails are masked and phones hidden until unlocked; the row id is what you pass to /unlock. Each page counts toward the daily search allowance.
| Filter | Type | Meaning |
|---|---|---|
q | text | Free text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it. |
role | list | Job role keys. Values: owner_dealer_principal, gm, gsm, sales_manager, used_car_manager, fi_manager, internet_sales, bdc_manager, marketing, fixed_ops_director, service_manager, parts_manager, fleet_manager, sales_staff, service_staff, accounting, hr, it, other |
seniority | list | Seniority. Values: owner, executive, director, manager, staff |
title | text | Job title contains this phrase (case insensitive), e.g. "internet director". |
title_any | list | Comma or | separated titles. A contact matches when its title holds every word of any one entry, in any order, e.g. "internet director|digital manager". |
country | list | Country codes. Values: US, CA |
state | list | State or province codes, e.g. TX,FL,ON. Values: two-letter US state or Canadian province codes |
city | list | Exact city names (case insensitive), e.g. Houston,Dallas. |
brand | list | OEMs the store sells, e.g. Ford,Toyota. Matches any. Values: OEM names as listed by GET /filters |
type | list | Store type. Values: franchise, independent, group, powersports_rv, specialty |
group | text | Dealer group name contains this, e.g. AutoNation. |
size | list | Store headcount band. Values: 1-19, 20-49, 50-99, 100-249, 250+ |
revenue | list | Store revenue band (USD). Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+ |
mail_provider | list | Who hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like). Values: google, microsoft, gateway, other |
domain | list | Store website domains, e.g. boydauto.com. https://, www. and paths are stripped. |
dealer_id | list | Only contacts at these dealer ids. |
ids | list | Look up these record ids directly (max 1,000). |
email_tier | list | Email check result. Values: verified, unverified |
has_email | true/false | true: only contacts with a verified work email. |
has_phone | true/false | true: only contacts with a mobile or direct line. |
has_linkedin | true/false | true: only contacts with a LinkedIn profile. |
moved | true/false | true: only people recently found in a new seat at another store. |
verified_within_days | integer | Email verified within this many days. |
max_per_dealer | integer | At most this many contacts per store (highest ranked first). |
page | integer | Page number for offset paging. Default 1. |
page_size | integer | Rows per page. Default 25, max 50 (500 on admin accounts). |
cursor | text | next_cursor from the previous page. Faster and stable for long pulls; overrides page. |
curl "https://api.usedealerdata.com/functions/v1/api/v1/contacts?role=gm,gsm&state=TX&has_email=true&page_size=50" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{
"total": 1188,
"page_size": 50,
"next_cursor": "16:204414",
"rows": [{
"id": 204401, "first_name": "Jane", "last_name": "Example", "title": "General Manager", "role": "gm",
"seniority": "executive", "dealer_id": 1840, "dealer_name": "Example Ford", "city": "Austin", "state": "TX",
"country": "US", "group_name": null, "brands": ["Ford"], "email": "j•••@exampleford.com",
"email_verified": true, "email_tier": "verified", "mail_provider": "google", "verified_at": "2026-10-21T09:12:00Z",
"has_phone": true, "phone": null, "phone_type": "mobile", "has_linkedin": true, "linkedin_url": null,
"moved_from": null, "unlocked": false, "phone_unlocked": false
}]
}
POST /contacts/search
Search contacts with a JSON body
Same as GET /contacts, with the filters in a JSON body. Lists can be arrays or comma separated strings. Use it for long id or domain lists.
| Filter | Type | Meaning |
|---|---|---|
q | text | Free text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it. |
role | list | Job role keys. Values: owner_dealer_principal, gm, gsm, sales_manager, used_car_manager, fi_manager, internet_sales, bdc_manager, marketing, fixed_ops_director, service_manager, parts_manager, fleet_manager, sales_staff, service_staff, accounting, hr, it, other |
seniority | list | Seniority. Values: owner, executive, director, manager, staff |
title | text | Job title contains this phrase (case insensitive), e.g. "internet director". |
title_any | list | Comma or | separated titles. A contact matches when its title holds every word of any one entry, in any order, e.g. "internet director|digital manager". |
country | list | Country codes. Values: US, CA |
state | list | State or province codes, e.g. TX,FL,ON. Values: two-letter US state or Canadian province codes |
city | list | Exact city names (case insensitive), e.g. Houston,Dallas. |
brand | list | OEMs the store sells, e.g. Ford,Toyota. Matches any. Values: OEM names as listed by GET /filters |
type | list | Store type. Values: franchise, independent, group, powersports_rv, specialty |
group | text | Dealer group name contains this, e.g. AutoNation. |
size | list | Store headcount band. Values: 1-19, 20-49, 50-99, 100-249, 250+ |
revenue | list | Store revenue band (USD). Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+ |
mail_provider | list | Who hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like). Values: google, microsoft, gateway, other |
domain | list | Store website domains, e.g. boydauto.com. https://, www. and paths are stripped. |
dealer_id | list | Only contacts at these dealer ids. |
ids | list | Look up these record ids directly (max 1,000). |
email_tier | list | Email check result. Values: verified, unverified |
has_email | true/false | true: only contacts with a verified work email. |
has_phone | true/false | true: only contacts with a mobile or direct line. |
has_linkedin | true/false | true: only contacts with a LinkedIn profile. |
moved | true/false | true: only people recently found in a new seat at another store. |
verified_within_days | integer | Email verified within this many days. |
max_per_dealer | integer | At most this many contacts per store (highest ranked first). |
page | integer | Page number for offset paging. Default 1. |
page_size | integer | Rows per page. Default 25, max 50 (500 on admin accounts). |
cursor | text | next_cursor from the previous page. Faster and stable for long pulls; overrides page. |
curl -X POST "https://api.usedealerdata.com/functions/v1/api/v1/contacts/search" \
-H "Authorization: Bearer $DEALERDATA_KEY" \
-H "Content-Type: application/json" \
-d '{"role":["gm"],"brand":["Toyota","Lexus"],"max_per_dealer":1,"page_size":50}'
{ "total": 912, "page_size": 50, "next_cursor": "15:88120", "rows": [ … ] }
GET /contacts/count
Count contacts (free)
Exact number of contacts matching the filters, to size a list before pulling it. Does not use the daily search allowance. Also accepts POST with a JSON body.
| Filter | Type | Meaning |
|---|---|---|
q | text | Free text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it. |
role | list | Job role keys. Values: owner_dealer_principal, gm, gsm, sales_manager, used_car_manager, fi_manager, internet_sales, bdc_manager, marketing, fixed_ops_director, service_manager, parts_manager, fleet_manager, sales_staff, service_staff, accounting, hr, it, other |
seniority | list | Seniority. Values: owner, executive, director, manager, staff |
title | text | Job title contains this phrase (case insensitive), e.g. "internet director". |
title_any | list | Comma or | separated titles. A contact matches when its title holds every word of any one entry, in any order, e.g. "internet director|digital manager". |
country | list | Country codes. Values: US, CA |
state | list | State or province codes, e.g. TX,FL,ON. Values: two-letter US state or Canadian province codes |
city | list | Exact city names (case insensitive), e.g. Houston,Dallas. |
brand | list | OEMs the store sells, e.g. Ford,Toyota. Matches any. Values: OEM names as listed by GET /filters |
type | list | Store type. Values: franchise, independent, group, powersports_rv, specialty |
group | text | Dealer group name contains this, e.g. AutoNation. |
size | list | Store headcount band. Values: 1-19, 20-49, 50-99, 100-249, 250+ |
revenue | list | Store revenue band (USD). Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+ |
mail_provider | list | Who hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like). Values: google, microsoft, gateway, other |
domain | list | Store website domains, e.g. boydauto.com. https://, www. and paths are stripped. |
dealer_id | list | Only contacts at these dealer ids. |
ids | list | Look up these record ids directly (max 1,000). |
email_tier | list | Email check result. Values: verified, unverified |
has_email | true/false | true: only contacts with a verified work email. |
has_phone | true/false | true: only contacts with a mobile or direct line. |
has_linkedin | true/false | true: only contacts with a LinkedIn profile. |
moved | true/false | true: only people recently found in a new seat at another store. |
verified_within_days | integer | Email verified within this many days. |
max_per_dealer | integer | At most this many contacts per store (highest ranked first). |
curl "https://api.usedealerdata.com/functions/v1/api/v1/contacts/count?role=gm&brand=Ford&has_email=true" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{ "total": 2481 }
GET /contacts/{id}
One contact
A single contact by id, showing whatever this account has unlocked. 404 if the id does not exist.
curl "https://api.usedealerdata.com/functions/v1/api/v1/contacts/204401" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{ "id": 204401, "first_name": "Jane", … }
GET /dealers
Search dealerships (free)
US and Canadian rooftops with OEMs, type, dealer group, size and revenue bands. Domain, phone, street, postal code, LinkedIn, headcount and revenue show once the store is unlocked.
| Filter | Type | Meaning |
|---|---|---|
q | text | Free text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it. |
country | list | Country codes. Values: US, CA |
state | list | State or province codes, e.g. TX,FL,ON. Values: two-letter US state or Canadian province codes |
city | list | Exact city names (case insensitive), e.g. Houston,Dallas. |
brand | list | OEMs the store sells, e.g. Ford,Toyota. Matches any. Values: OEM names as listed by GET /filters |
type | list | Store type. Values: franchise, independent, group, powersports_rv, specialty |
group | text | Dealer group name contains this, e.g. AutoNation. |
size | list | Store headcount band. Values: 1-19, 20-49, 50-99, 100-249, 250+ |
revenue | list | Store revenue band (USD). Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+ |
mail_provider | list | Who hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like). Values: google, microsoft, gateway, other |
domain | list | Store website domains, e.g. boydauto.com. https://, www. and paths are stripped. |
ids | list | Look up these record ids directly (max 1,000). |
min_headcount | integer | Stores with at least this many staff. |
min_contacts | integer | Stores with at least this many contacts on file. |
page | integer | Page number for offset paging. Default 1. |
page_size | integer | Rows per page. Default 25, max 50 (500 on admin accounts). |
cursor | text | next_cursor from the previous page. Faster and stable for long pulls; overrides page. |
curl "https://api.usedealerdata.com/functions/v1/api/v1/dealers?brand=Toyota&state=CA&size=100-249,250%2B" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{
"total": 64,
"page_size": 25,
"next_cursor": "91.2:40211",
"rows": [{
"id": 40211, "name": "Toyota of Example", "city": "Fresno", "state": "CA", "country": "US",
"dealer_type": "franchise", "brands": ["Toyota"], "group_name": null, "headcount_range": "100-249",
"size_band": "100-249", "revenue_band": "50M+", "contact_count": 38, "mail_provider": "microsoft",
"unlocked": false, "domain": null, "phone": null, "street": null, "postal_code": null,
"linkedin_url": null, "headcount": null, "revenue": null, "inventory_count": null, "rank_score": 91.2
}]
}
POST /dealers/search
Search dealerships with a JSON body
Same as GET /dealers, with the filters in a JSON body.
| Filter | Type | Meaning |
|---|---|---|
q | text | Free text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it. |
country | list | Country codes. Values: US, CA |
state | list | State or province codes, e.g. TX,FL,ON. Values: two-letter US state or Canadian province codes |
city | list | Exact city names (case insensitive), e.g. Houston,Dallas. |
brand | list | OEMs the store sells, e.g. Ford,Toyota. Matches any. Values: OEM names as listed by GET /filters |
type | list | Store type. Values: franchise, independent, group, powersports_rv, specialty |
group | text | Dealer group name contains this, e.g. AutoNation. |
size | list | Store headcount band. Values: 1-19, 20-49, 50-99, 100-249, 250+ |
revenue | list | Store revenue band (USD). Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+ |
mail_provider | list | Who hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like). Values: google, microsoft, gateway, other |
domain | list | Store website domains, e.g. boydauto.com. https://, www. and paths are stripped. |
ids | list | Look up these record ids directly (max 1,000). |
min_headcount | integer | Stores with at least this many staff. |
min_contacts | integer | Stores with at least this many contacts on file. |
page | integer | Page number for offset paging. Default 1. |
page_size | integer | Rows per page. Default 25, max 50 (500 on admin accounts). |
cursor | text | next_cursor from the previous page. Faster and stable for long pulls; overrides page. |
curl -X POST "https://api.usedealerdata.com/functions/v1/api/v1/dealers/search" \
-H "Authorization: Bearer $DEALERDATA_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":["exampleford.com","examplehonda.com"]}'
{ "total": 2, "rows": [ … ] }
GET /dealers/count
Count dealerships (free)
Exact number of stores matching the filters. Also accepts POST with a JSON body.
| Filter | Type | Meaning |
|---|---|---|
q | text | Free text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it. |
country | list | Country codes. Values: US, CA |
state | list | State or province codes, e.g. TX,FL,ON. Values: two-letter US state or Canadian province codes |
city | list | Exact city names (case insensitive), e.g. Houston,Dallas. |
brand | list | OEMs the store sells, e.g. Ford,Toyota. Matches any. Values: OEM names as listed by GET /filters |
type | list | Store type. Values: franchise, independent, group, powersports_rv, specialty |
group | text | Dealer group name contains this, e.g. AutoNation. |
size | list | Store headcount band. Values: 1-19, 20-49, 50-99, 100-249, 250+ |
revenue | list | Store revenue band (USD). Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+ |
mail_provider | list | Who hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like). Values: google, microsoft, gateway, other |
domain | list | Store website domains, e.g. boydauto.com. https://, www. and paths are stripped. |
ids | list | Look up these record ids directly (max 1,000). |
min_headcount | integer | Stores with at least this many staff. |
min_contacts | integer | Stores with at least this many contacts on file. |
curl "https://api.usedealerdata.com/functions/v1/api/v1/dealers/count?type=franchise&country=CA" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{ "total": 3104 }
GET /dealers/{id}
One dealership
A single store by id. 404 if the id does not exist.
curl "https://api.usedealerdata.com/functions/v1/api/v1/dealers/40211" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{ "id": 40211, "name": "Toyota of Example", … }
GET /filters
Valid filter values with counts
Every role, seniority, state, OEM, store type, size and revenue band and mail provider, with live counts, plus the top dealer groups and the credit price of each unlock. Read this before building filters.
curl "https://api.usedealerdata.com/functions/v1/api/v1/filters" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{ "totals": { "dealers": 75800, "contacts": 755428, … }, "role": { "gm": 34766, … }, "brand": { "Ford": 6222, … }, "prices": { "contact_email": 4, … } }
POST /unlock
Unlock records (spends credits)
Reveals records for this account. Already unlocked ids are free. Ids that do not qualify for the kind (for example contact_email on a contact without a verified email) are skipped, not charged, and listed in skipped with the reason. Max 100 ids per call (1,000 on admin accounts).
| Body field | Type | Meaning |
|---|---|---|
kind | string | Required. contact_email (verified work email + full name + LinkedIn), contact_profile (full name + LinkedIn, for contacts without a verified email), contact_phone (mobile or direct line), or dealer (domain, phone, address, headcount, revenue). |
ids | integer[] | Record ids from search. contact_ids or dealer_ids also work, and without a kind they unlock contact_email or dealer. |
return_rows | boolean | Optional. true also returns the unlocked records, so no second call is needed. |
curl -X POST "https://api.usedealerdata.com/functions/v1/api/v1/unlock" \
-H "Authorization: Bearer $DEALERDATA_KEY" \
-H "Content-Type: application/json" \
-d '{"kind":"contact_email","ids":[204401,204407,301122],"return_rows":true}'
{
"unlocked": 2, "credits_spent": 8, "credits_left": 492,
"skipped": [301122], "skipped_reason": "no verified email; use contact_profile for name + LinkedIn",
"rows": [ { "id": 204401, "email": "[email protected]", "unlocked": true, … } ]
}
GET /account
Credit balance and prices
The account email, credit balance and the credit price of each unlock kind.
curl "https://api.usedealerdata.com/functions/v1/api/v1/account" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{ "email": "[email protected]", "credits": 492, "prices": { "dealer": 1, "contact_email": 4, "contact_phone": 10, "contact_profile": 2 } }
GET /export/contacts
Every unlocked contact
All contacts this account has unlocked (email, profile or phone), with store details, in one response with total. 20 exports per hour.
curl "https://api.usedealerdata.com/functions/v1/api/v1/export/contacts" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{ "total": 9162, "rows": [ { "first_name": "Jane", "email": "[email protected]", "phone": null, "dealer_domain": "exampleford.com", … } ] }
GET /export/dealers
Every unlocked dealership
All stores this account has unlocked, with full details, in one response with total. 20 exports per hour.
curl "https://api.usedealerdata.com/functions/v1/api/v1/export/dealers" \
-H "Authorization: Bearer $DEALERDATA_KEY"
{ "total": 412, "rows": [ { "name": "Example Ford", "domain": "exampleford.com", … } ] }
MCP tools
Add https://api.usedealerdata.com/functions/v1/mcp as a remote MCP server (streamable HTTP) with the same Bearer key. The tools take the same filters as the REST endpoints.
| Tool | What it does |
|---|---|
search_contacts | Same filters as GET /contacts. Free. |
search_dealers | Same filters as GET /dealers. Free. |
count_contacts | Exact count, same filters. Free. |
count_dealers | Exact count, same filters. Free. |
get_contacts | Contacts by id (up to 500). |
get_dealers | Dealerships by id (up to 500). |
filter_values | Every valid filter value with counts, and unlock prices. |
unlock | Spend credits; same rules as POST /unlock, including return_rows and skipped. |
account | Credit balance and prices. |
Limits
| Standard account | Admin account | |
|---|---|---|
| Calls | 60 a minute, 600 an hour | No limit |
| Exports | 20 an hour | No limit |
| Rows per page | 50 | 500 |
| Ids per unlock | 100 | 1,000 |
| Search pages a day | 600 (20 before a plan, trial or invite) | No limit |
Every response carries X-RateLimit-Limit and X-RateLimit-Remaining; a 429 carries Retry-After in seconds.
Errors
Errors are JSON: {"error": "<code>", "message": "<what to fix>"}.
| Status | Code | Meaning |
|---|---|---|
| 400 | unknown_filter | A filter name the endpoint does not take. The message lists the valid ones. Common plurals (roles, states, brands) are read as the singular and named in warnings instead. |
| 400 | bad_value | A value outside the allowed set (unknown role, state name instead of code, bad boolean, bad cursor). The message lists what is valid. |
| 400 | kind_required | Unlock sent without kind. The response lists the valid kinds in kinds. |
| 400 | too_many_ids | More ids in one unlock than the account may send (100, or 1,000 on admin accounts). |
| 401 | invalid_api_key | Missing, wrong or revoked key. |
| 402 | insufficient_credits | Not enough credits for the unlock. Nothing was charged. |
| 404 | not_found | Unknown route or record id. |
| 429 | rate_limited | Per-minute (60), per-hour (600) or export (20 per hour) limit reached. Wait Retry-After seconds. Admin accounts are not limited. |
| 429 | daily_search_limit | Daily search pages used up (20 a day before a plan, trial or invite; 600 a day after). Counts are not limited. |