DealerData

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

  1. GET /filters to see valid roles, OEMs, states, bands and prices.
  2. GET /contacts/count with your filters to size the list (free).
  3. GET /contacts page by page, passing cursor=<next_cursor> until it comes back null.
  4. POST /unlock with the ids you want and "return_rows": true to get the emails in the same call.
  5. GET /export/contacts any 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.

FilterTypeMeaning
qtextFree text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it.
rolelistJob 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
senioritylistSeniority.
Values: owner, executive, director, manager, staff
titletextJob title contains this phrase (case insensitive), e.g. "internet director".
title_anylistComma 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".
countrylistCountry codes.
Values: US, CA
statelistState or province codes, e.g. TX,FL,ON.
Values: two-letter US state or Canadian province codes
citylistExact city names (case insensitive), e.g. Houston,Dallas.
brandlistOEMs the store sells, e.g. Ford,Toyota. Matches any.
Values: OEM names as listed by GET /filters
typelistStore type.
Values: franchise, independent, group, powersports_rv, specialty
grouptextDealer group name contains this, e.g. AutoNation.
sizelistStore headcount band.
Values: 1-19, 20-49, 50-99, 100-249, 250+
revenuelistStore revenue band (USD).
Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+
mail_providerlistWho hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like).
Values: google, microsoft, gateway, other
domainlistStore website domains, e.g. boydauto.com. https://, www. and paths are stripped.
dealer_idlistOnly contacts at these dealer ids.
idslistLook up these record ids directly (max 1,000).
email_tierlistEmail check result.
Values: verified, unverified
has_emailtrue/falsetrue: only contacts with a verified work email.
has_phonetrue/falsetrue: only contacts with a mobile or direct line.
has_linkedintrue/falsetrue: only contacts with a LinkedIn profile.
movedtrue/falsetrue: only people recently found in a new seat at another store.
verified_within_daysintegerEmail verified within this many days.
max_per_dealerintegerAt most this many contacts per store (highest ranked first).
pageintegerPage number for offset paging. Default 1.
page_sizeintegerRows per page. Default 25, max 50 (500 on admin accounts).
cursortextnext_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.

FilterTypeMeaning
qtextFree text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it.
rolelistJob 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
senioritylistSeniority.
Values: owner, executive, director, manager, staff
titletextJob title contains this phrase (case insensitive), e.g. "internet director".
title_anylistComma 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".
countrylistCountry codes.
Values: US, CA
statelistState or province codes, e.g. TX,FL,ON.
Values: two-letter US state or Canadian province codes
citylistExact city names (case insensitive), e.g. Houston,Dallas.
brandlistOEMs the store sells, e.g. Ford,Toyota. Matches any.
Values: OEM names as listed by GET /filters
typelistStore type.
Values: franchise, independent, group, powersports_rv, specialty
grouptextDealer group name contains this, e.g. AutoNation.
sizelistStore headcount band.
Values: 1-19, 20-49, 50-99, 100-249, 250+
revenuelistStore revenue band (USD).
Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+
mail_providerlistWho hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like).
Values: google, microsoft, gateway, other
domainlistStore website domains, e.g. boydauto.com. https://, www. and paths are stripped.
dealer_idlistOnly contacts at these dealer ids.
idslistLook up these record ids directly (max 1,000).
email_tierlistEmail check result.
Values: verified, unverified
has_emailtrue/falsetrue: only contacts with a verified work email.
has_phonetrue/falsetrue: only contacts with a mobile or direct line.
has_linkedintrue/falsetrue: only contacts with a LinkedIn profile.
movedtrue/falsetrue: only people recently found in a new seat at another store.
verified_within_daysintegerEmail verified within this many days.
max_per_dealerintegerAt most this many contacts per store (highest ranked first).
pageintegerPage number for offset paging. Default 1.
page_sizeintegerRows per page. Default 25, max 50 (500 on admin accounts).
cursortextnext_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.

FilterTypeMeaning
qtextFree text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it.
rolelistJob 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
senioritylistSeniority.
Values: owner, executive, director, manager, staff
titletextJob title contains this phrase (case insensitive), e.g. "internet director".
title_anylistComma 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".
countrylistCountry codes.
Values: US, CA
statelistState or province codes, e.g. TX,FL,ON.
Values: two-letter US state or Canadian province codes
citylistExact city names (case insensitive), e.g. Houston,Dallas.
brandlistOEMs the store sells, e.g. Ford,Toyota. Matches any.
Values: OEM names as listed by GET /filters
typelistStore type.
Values: franchise, independent, group, powersports_rv, specialty
grouptextDealer group name contains this, e.g. AutoNation.
sizelistStore headcount band.
Values: 1-19, 20-49, 50-99, 100-249, 250+
revenuelistStore revenue band (USD).
Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+
mail_providerlistWho hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like).
Values: google, microsoft, gateway, other
domainlistStore website domains, e.g. boydauto.com. https://, www. and paths are stripped.
dealer_idlistOnly contacts at these dealer ids.
idslistLook up these record ids directly (max 1,000).
email_tierlistEmail check result.
Values: verified, unverified
has_emailtrue/falsetrue: only contacts with a verified work email.
has_phonetrue/falsetrue: only contacts with a mobile or direct line.
has_linkedintrue/falsetrue: only contacts with a LinkedIn profile.
movedtrue/falsetrue: only people recently found in a new seat at another store.
verified_within_daysintegerEmail verified within this many days.
max_per_dealerintegerAt 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.

FilterTypeMeaning
qtextFree text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it.
countrylistCountry codes.
Values: US, CA
statelistState or province codes, e.g. TX,FL,ON.
Values: two-letter US state or Canadian province codes
citylistExact city names (case insensitive), e.g. Houston,Dallas.
brandlistOEMs the store sells, e.g. Ford,Toyota. Matches any.
Values: OEM names as listed by GET /filters
typelistStore type.
Values: franchise, independent, group, powersports_rv, specialty
grouptextDealer group name contains this, e.g. AutoNation.
sizelistStore headcount band.
Values: 1-19, 20-49, 50-99, 100-249, 250+
revenuelistStore revenue band (USD).
Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+
mail_providerlistWho hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like).
Values: google, microsoft, gateway, other
domainlistStore website domains, e.g. boydauto.com. https://, www. and paths are stripped.
idslistLook up these record ids directly (max 1,000).
min_headcountintegerStores with at least this many staff.
min_contactsintegerStores with at least this many contacts on file.
pageintegerPage number for offset paging. Default 1.
page_sizeintegerRows per page. Default 25, max 50 (500 on admin accounts).
cursortextnext_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.

FilterTypeMeaning
qtextFree text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it.
countrylistCountry codes.
Values: US, CA
statelistState or province codes, e.g. TX,FL,ON.
Values: two-letter US state or Canadian province codes
citylistExact city names (case insensitive), e.g. Houston,Dallas.
brandlistOEMs the store sells, e.g. Ford,Toyota. Matches any.
Values: OEM names as listed by GET /filters
typelistStore type.
Values: franchise, independent, group, powersports_rv, specialty
grouptextDealer group name contains this, e.g. AutoNation.
sizelistStore headcount band.
Values: 1-19, 20-49, 50-99, 100-249, 250+
revenuelistStore revenue band (USD).
Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+
mail_providerlistWho hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like).
Values: google, microsoft, gateway, other
domainlistStore website domains, e.g. boydauto.com. https://, www. and paths are stripped.
idslistLook up these record ids directly (max 1,000).
min_headcountintegerStores with at least this many staff.
min_contactsintegerStores with at least this many contacts on file.
pageintegerPage number for offset paging. Default 1.
page_sizeintegerRows per page. Default 25, max 50 (500 on admin accounts).
cursortextnext_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.

FilterTypeMeaning
qtextFree text. Contacts: title, full name or dealership name contains it. Dealers: name or city contains it.
countrylistCountry codes.
Values: US, CA
statelistState or province codes, e.g. TX,FL,ON.
Values: two-letter US state or Canadian province codes
citylistExact city names (case insensitive), e.g. Houston,Dallas.
brandlistOEMs the store sells, e.g. Ford,Toyota. Matches any.
Values: OEM names as listed by GET /filters
typelistStore type.
Values: franchise, independent, group, powersports_rv, specialty
grouptextDealer group name contains this, e.g. AutoNation.
sizelistStore headcount band.
Values: 1-19, 20-49, 50-99, 100-249, 250+
revenuelistStore revenue band (USD).
Values: <1M, 1-5M, 5-10M, 10-25M, 25-50M, 50M+
mail_providerlistWho hosts the store's email. gateway = behind a security gateway (Mimecast, Proofpoint and the like).
Values: google, microsoft, gateway, other
domainlistStore website domains, e.g. boydauto.com. https://, www. and paths are stripped.
idslistLook up these record ids directly (max 1,000).
min_headcountintegerStores with at least this many staff.
min_contactsintegerStores 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 fieldTypeMeaning
kindstringRequired. 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).
idsinteger[]Record ids from search. contact_ids or dealer_ids also work, and without a kind they unlock contact_email or dealer.
return_rowsbooleanOptional. 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.

ToolWhat it does
search_contactsSame filters as GET /contacts. Free.
search_dealersSame filters as GET /dealers. Free.
count_contactsExact count, same filters. Free.
count_dealersExact count, same filters. Free.
get_contactsContacts by id (up to 500).
get_dealersDealerships by id (up to 500).
filter_valuesEvery valid filter value with counts, and unlock prices.
unlockSpend credits; same rules as POST /unlock, including return_rows and skipped.
accountCredit balance and prices.

Limits

Standard accountAdmin account
Calls60 a minute, 600 an hourNo limit
Exports20 an hourNo limit
Rows per page50500
Ids per unlock1001,000
Search pages a day600 (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>"}.

StatusCodeMeaning
400unknown_filterA 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.
400bad_valueA value outside the allowed set (unknown role, state name instead of code, bad boolean, bad cursor). The message lists what is valid.
400kind_requiredUnlock sent without kind. The response lists the valid kinds in kinds.
400too_many_idsMore ids in one unlock than the account may send (100, or 1,000 on admin accounts).
401invalid_api_keyMissing, wrong or revoked key.
402insufficient_creditsNot enough credits for the unlock. Nothing was charged.
404not_foundUnknown route or record id.
429rate_limitedPer-minute (60), per-hour (600) or export (20 per hour) limit reached. Wait Retry-After seconds. Admin accounts are not limited.
429daily_search_limitDaily search pages used up (20 a day before a plan, trial or invite; 600 a day after). Counts are not limited.