Skip to content

Contacts API [Starter]

The Contacts API enables searching for business contacts/personas using vector search, with support for similarity matching, filtering, and name-based lookup.

The primary endpoint is POST /v1/contacts/discover. The legacy GET /v1/contacts endpoint is still functional and documented at the end of this page for existing integrations.

FeatureRequired Plan
Base searchSTARTER
inclusion_query_idSTARTER
exclusion_query_idPRO
POST https://api.discolike.com/v1/contacts/discover

Search for business contacts and return them grouped by company domain, with per-company firmographic data on each entry. Billed additively: net-new contacts plus net-new firmo domains for any company surfaced for the first time in the 90-day cache window. The two counters share the same credit pool.

JSON body. Every parameter documented below is accepted as a JSON field.

ParameterDescription
persona_idUse one or more persona IDs as the basis for similarity matching. Up to 10 IDs can be provided.
icp_promptNatural language ICP description. Automatically extracts structured contact filters (seniority, department, industry, country, employee/revenue range, title keywords) and cleans the semantic description. When the query requires company-level signals (tech stack, funding, product descriptions), automatically chains to company discovery to find matching companies first, then searches contacts there. One parameter does everything — preferred over setting individual filters manually.
icp_textNatural language description of your ideal contact profile for semantic matching. Does NOT extract filters — use icp_prompt instead for automatic extraction.
domainLimit results to contacts at specific domains.
inclusion_query_idInclude results from saved queries. Works with domain lists (scopes to companies) and contact lists (scopes to specific contacts). Requires Starter plan or higher.
exclusion_query_idExclude results from saved queries. Works with domain lists (excludes companies) and contact lists (excludes specific contacts). Requires Pro plan or higher.
ParameterDescription
seniorityFilter by seniority level. Acceptable values: executive, vp, director, manager, senior_ic, mid_level, entry_level
negate_seniorityExclude contacts with specified seniority levels.
departmentFilter by department. Must be one of the 15 canonical values exactly (case-sensitive): Operations, Executive, Technology, Sales - Marketing, Finance, Legal, Human Resources, Medical - Science, Customer Service, Research & Development, Administration, Public Relations, Investor Relations, Pro Services, Other. Any other value returns 422. Use icp_prompt if you want natural-language extraction (e.g. “engineering leaders” → Technology).
negate_departmentExclude contacts in specified departments. Same 15 canonical values as department.
skillsFilter by skills. Multiple skills can be provided.
nameFilter by contact name (partial match supported).
titleFilter by job title. Each item is a separate match term. Supports quoted phrases and + prefix for required terms.
negate_titleExclude contacts with specified job titles.
summaryFilter by profile summary text (semantic search).
negate_summaryExclude contacts matching this summary description.
person_countryFilter by contact’s country using ISO-3166-1 alpha-2 codes. Also accepts region codes: ANZ, APAC, ASEAN, BENELUX, CEE, DACH, EMEA, EU, GCC, LATAM, MENA, NORDICS.
negate_person_countryExclude contacts in specified countries.
person_stateFilter by contact’s state/region. Accepts ISO 3166-2 codes (e.g. CA, BY) or full names (e.g. California, Bayern). Scoped to a single person_country — rejected if multiple countries are passed. See States for supported countries.
ParameterDescription
has_emailSet to true to only include contacts with email addresses.
email_validatedSet to true to only include contacts with validated email addresses. The email_validated flag reflects an SMTP/deliverability check on the address itself.
has_phoneSet to true to only include contacts with phone numbers.
has_mobileSet to true to only include contacts whose phone array contains at least one mobile number.
has_linkedinSet to true to only include contacts with LinkedIn profiles.
min_connectionsMinimum LinkedIn connections required.
ParameterDescription
filter_industryFilter by company industry. Uppercase enum values (e.g. SAAS, SOFTWARE, FINANCIAL_SERVICES, HEALTHCARE, CLOUD_COMPUTING). See BizData Dataset for the full enum.
negate_filter_industryExclude contacts at companies in specified industries.
filter_countryFilter by company country using ISO-3166-1 alpha-2 codes. Also accepts the same region aliases as person_country.
negate_filter_countryExclude contacts at companies in specified countries.
filter_stateFilter by company state/region. Accepts ISO 3166-2 codes (e.g. CA, BY) or full names (e.g. California, Bayern). Scoped to a single filter_country — rejected if multiple countries are passed. See States for supported countries.
negate_filter_stateExclude contacts at companies in specified states (same format as filter_state).
employee_rangeFilter by company size. Format: 'min,max' (e.g. '51,200'). Maps to buckets: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+.
revenue_rangeDeprecated, no-op. Revenue is a company-level attribute — filter on /discover by revenue_range and pass the resulting domains to /contacts/discover. The output field is still populated on each result.
ParameterDescription
max_recordsMaximum contacts to return, range 20-10,000 (optional, defaults to 100). Use this for a literal total-contact cap. Do not combine with max_companies.
max_companiesMaximum enriched companies to return, range 1-10,000. Use this when you want the response to stop after up to N company/domain entries. Do not combine with max_records. When paired with results_by_company=0 (no per-company cap), the total is capped at 10,000 contacts.
offsetRecords to skip for pagination (optional, defaults to 0).
results_by_companyMax contacts per company domain, range 0-100 (optional, defaults to 5). With max_companies, controls how many contacts can be returned under each enriched company. Example: max_companies=100, results_by_company=2 → up to 100 companies with up to 2 contacts each. Set results_by_company=0 to remove the per-company cap — with max_records, the total is capped at max_records; with max_companies, the total is capped at 10,000. Any non-zero value forces offset to 0.
include_search_contactsSet to true to include input persona_ids in results (optional, defaults to false).
consensusNumber of top results to use for building search vector, range 1-20 (optional, defaults to 1).
Terminal window
curl -X POST https://api.discolike.com/v1/contacts/discover \
-H "x-discolike-key: API_KEY" \
-H "Content-Type: application/json" \
-d '{
"icp_prompt": "VP of Sales at SaaS companies",
"filter_industry": ["SAAS"],
"max_companies": 50,
"results_by_company": 5
}'
{
"results": {
"stripe.com": {
"domain": "stripe.com",
"name": "Stripe",
"employees": "10001+",
"revenue_range": ">1B",
"industry_groups": {"SAAS": 0.81, "SOFTWARE": 0.1},
"address": {"country": "US", "state": "CA"},
"email_pattern": "{first_name}@stripe.com",
"email_pattern_confidence": 59,
"email_pattern_guess": "marissa@stripe.com",
"contacts": [
{
"persona_id": 319675651,
"domain": "stripe.com",
"name": "Marissa Fagnani",
"title": "Delivery Manager",
"department": "Technology",
"seniority": "manager",
"skills": ["program management", "delivery"],
"phone": [
{"phone": "+17406072462", "type": "mobile"},
{"phone": "+14197337789", "type": "mobile"}
],
"email": "marissa@stripe.com",
"email_validated": true,
"social_urls": ["https://www.linkedin.com/in/marissa-fagnani"],
"connections": 500,
"country": "US",
"state": "OR",
"industry": ["SAAS", "SOFTWARE"],
"employees": "10001+",
"revenue_range": ">1B",
"similarity": 87,
"summary": null,
"company_name": "Stripe"
}
]
}
},
"total_contacts": 142,
"total_domains": 38
}
  • phone is an array of objects: [{"phone": "+E164", "type": "mobile" | "landline"}, ...]. A contact can have multiple entries. Type is re-derived per call from libphonenumber, so it is always populated when a phone is present.
  • industry is an array of uppercase enum strings, e.g. ["SAAS", "SOFTWARE"]. See BizData Dataset for the full enum.
  • department is one of the 15 values listed under Persona Filters.
  • social_urls may include LinkedIn and X/Twitter URLs.

The endpoint supports three modes, selected by which parameters you provide:

  1. Similarity mode — When persona_id, icp_text, or icp_prompt is provided. Uses vector search with cosine similarity scores (0-100 scale on the similarity field).
  2. Domain mode — When only domain is provided. Returns all contacts at the specified domains matching filters.
  3. Filter mode — When no search input is provided. Returns contacts matching the company and persona filters.
POST https://api.discolike.com/v1/contacts/discover/generate

Uses your own LLM and search provider (BYOK) to discover candidate contacts at a list of companies. Runs through the DiscoGen pipeline with web search always enabled — returns a task ID immediately, poll GET /discogen/status/{task_id} for per-domain contact rows plus the company’s inferred email pattern.

No platform billing per contact returned. Results may include hallucinated personas — treat email, linkedin_url, and other identifying fields as candidate data until validated.

ParameterTypeRequiredDescription
icp_textStringYesPersona description (e.g., “VPs or Directors of Marketing at B2B SaaS”)
domainsArrayYesList of company domains to search at (max 10,000)
context_modeStringNoWhat data the LLM sees: website (default), profile, domain
integration_idStringNoLLM provider integration UUID. Uses your default if omitted
search_provider_idStringNoSearch provider UUID. Uses your default if omitted

Web search is always enabled server-side — contact discovery depends on LinkedIn/company-site lookups.

{
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"column_name": ["name", "title", "department", "seniority", "email", "linkedin_url", "skills", "phone", "email_pattern", "email_pattern_confidence", "email_pattern_guess"],
"status": "in_progress",
"total_domains": 2
}

Each domain yields zero or more rows. Every row carries contact fields plus the company-wide email pattern (repeated per row):

ColumnTypeNotes
nameStringFull name of the contact
titleString|nullJob title
departmentString|nullOne of the 15 canonical department values (see Persona Filters)
seniorityString|nullexecutive, vp, director, manager, senior_ic, mid_level, entry_level
emailString|nullOnly if publicly verifiable
linkedin_urlString|nullLinkedIn profile URL
skillsArray|nullSkills attributed to the contact
phoneArrayArray of phone objects with phone (+E164) and type (mobile or landline) fields, same shape as the indexed /contacts/discover response.
email_patternString|nullTemplate, e.g. first.last@, flastname@
email_pattern_confidenceNumber|null0-1
email_pattern_guessString|nullExample email for a hypothetical John Smith
Terminal window
curl -X POST https://api.discolike.com/v1/contacts/discover/generate \
-H "x-discolike-key: API_KEY" \
-H "Content-Type: application/json" \
-d '{
"icp_text": "VPs or Directors of Marketing at B2B SaaS",
"domains": ["gusto.com", "rippling.com"]
}'

Poll for results:

Terminal window
curl https://api.discolike.com/v1/discogen/status/TASK_ID \
-H "x-discolike-key: API_KEY"
GET https://api.discolike.com/v1/contacts/count

Accepts the same filter parameters as the Discover Contacts endpoint (persona filters, contact data filters, and company filters). Useful for sizing a result set before paying to retrieve it.

Terminal window
curl "https://api.discolike.com/v1/contacts/count?seniority=vp&filter_industry=SAAS&filter_country=US" \
-H "x-discolike-key: API_KEY"
{
"count": 15432
}
GET https://api.discolike.com/v1/contacts/lookup
ParameterDescription
persona_idThe persona ID to look up (provide this OR linkedin).
linkedinLinkedIn URL or username to look up (provide this OR persona_id).
Terminal window
curl "https://api.discolike.com/v1/contacts/lookup?persona_id=12345678" \
-H "x-discolike-key: API_KEY"

Or lookup by LinkedIn URL/username:

Terminal window
curl "https://api.discolike.com/v1/contacts/lookup?linkedin=https://www.linkedin.com/in/janedoe" \
-H "x-discolike-key: API_KEY"
{
"persona_id": 12345678,
"name": "Jane Doe",
"title": "VP of Sales",
"domain": "example.com",
"company_name": "Example Corp",
"summary": "Experienced sales leader with 15+ years in enterprise software..."
}
GET https://api.discolike.com/v1/contacts

Same filter vocabulary as POST /v1/contacts/discover, passed as query parameters instead of a JSON body. For repeated values (e.g., multiple domains, seniority levels), repeat the query parameter: ?domain=a.com&domain=b.com&seniority=vp&seniority=director. For result limits, pass either max_companies or max_records, not both.

Terminal window
curl "https://api.discolike.com/v1/contacts?icp_text=VP%20of%20Sales%20at%20SaaS%20companies&seniority=vp&filter_industry=SAAS&max_companies=50&results_by_company=5" \
-H "x-discolike-key: API_KEY"
[
{
"persona_id": 319675651,
"domain": "stripe.com",
"name": "Marissa Fagnani",
"title": "Delivery Manager",
"department": "Technology",
"seniority": "manager",
"skills": ["program management", "delivery"],
"phone": [
{"phone": "+17406072462", "type": "mobile"},
{"phone": "+14197337789", "type": "mobile"}
],
"email": "marissa@stripe.com",
"email_validated": true,
"social_urls": ["https://www.linkedin.com/in/marissa-fagnani"],
"connections": 500,
"country": "US",
"state": "OR",
"industry": ["SAAS", "SOFTWARE"],
"employees": "10001+",
"revenue_range": ">1B",
"similarity": 87
}
]