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.
Subscription Level
Section titled “Subscription Level”| Feature | Required Plan |
|---|---|
| Base search | STARTER |
inclusion_query_id | STARTER |
exclusion_query_id | PRO |
Discover Contacts
Section titled “Discover Contacts”Endpoint
Section titled “Endpoint”POST https://api.discolike.com/v1/contacts/discoverSearch 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.
Request Body
Section titled “Request Body”JSON body. Every parameter documented below is accepted as a JSON field.
Search Parameters
Section titled “Search Parameters”| Parameter | Description |
|---|---|
| persona_id | Use one or more persona IDs as the basis for similarity matching. Up to 10 IDs can be provided. |
| icp_prompt | Natural 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_text | Natural language description of your ideal contact profile for semantic matching. Does NOT extract filters — use icp_prompt instead for automatic extraction. |
| domain | Limit results to contacts at specific domains. |
| inclusion_query_id | Include 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_id | Exclude results from saved queries. Works with domain lists (excludes companies) and contact lists (excludes specific contacts). Requires Pro plan or higher. |
Persona Filters
Section titled “Persona Filters”| Parameter | Description |
|---|---|
| seniority | Filter by seniority level. Acceptable values: executive, vp, director, manager, senior_ic, mid_level, entry_level |
| negate_seniority | Exclude contacts with specified seniority levels. |
| department | Filter 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_department | Exclude contacts in specified departments. Same 15 canonical values as department. |
| skills | Filter by skills. Multiple skills can be provided. |
| name | Filter by contact name (partial match supported). |
| title | Filter by job title. Each item is a separate match term. Supports quoted phrases and + prefix for required terms. |
| negate_title | Exclude contacts with specified job titles. |
| summary | Filter by profile summary text (semantic search). |
| negate_summary | Exclude contacts matching this summary description. |
| person_country | Filter 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_country | Exclude contacts in specified countries. |
| person_state | Filter 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. |
Contact Data Filters
Section titled “Contact Data Filters”| Parameter | Description |
|---|---|
| has_email | Set to true to only include contacts with email addresses. |
| email_validated | Set to true to only include contacts with validated email addresses. The email_validated flag reflects an SMTP/deliverability check on the address itself. |
| has_phone | Set to true to only include contacts with phone numbers. |
| has_mobile | Set to true to only include contacts whose phone array contains at least one mobile number. |
| has_linkedin | Set to true to only include contacts with LinkedIn profiles. |
| min_connections | Minimum LinkedIn connections required. |
Company Filters
Section titled “Company Filters”| Parameter | Description |
|---|---|
| filter_industry | Filter by company industry. Uppercase enum values (e.g. SAAS, SOFTWARE, FINANCIAL_SERVICES, HEALTHCARE, CLOUD_COMPUTING). See BizData Dataset for the full enum. |
| negate_filter_industry | Exclude contacts at companies in specified industries. |
| filter_country | Filter by company country using ISO-3166-1 alpha-2 codes. Also accepts the same region aliases as person_country. |
| negate_filter_country | Exclude contacts at companies in specified countries. |
| filter_state | Filter 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_state | Exclude contacts at companies in specified states (same format as filter_state). |
| employee_range | Filter 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+. |
Deprecated, 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. |
Pagination & Output
Section titled “Pagination & Output”| Parameter | Description |
|---|---|
| max_records | Maximum 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_companies | Maximum 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. |
| offset | Records to skip for pagination (optional, defaults to 0). |
| results_by_company | Max 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_contacts | Set to true to include input persona_ids in results (optional, defaults to false). |
| consensus | Number of top results to use for building search vector, range 1-20 (optional, defaults to 1). |
Example Request
Section titled “Example Request”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 }'Example Response
Section titled “Example Response”{ "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}Field Notes
Section titled “Field Notes”phoneis 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.industryis an array of uppercase enum strings, e.g.["SAAS", "SOFTWARE"]. See BizData Dataset for the full enum.departmentis one of the 15 values listed under Persona Filters.social_urlsmay include LinkedIn and X/Twitter URLs.
Search Modes
Section titled “Search Modes”The endpoint supports three modes, selected by which parameters you provide:
- Similarity mode — When
persona_id,icp_text, oricp_promptis provided. Uses vector search with cosine similarity scores (0-100 scale on thesimilarityfield). - Domain mode — When only
domainis provided. Returns all contacts at the specified domains matching filters. - Filter mode — When no search input is provided. Returns contacts matching the company and persona filters.
Discover Contacts — BYOK Generate
Section titled “Discover Contacts — BYOK Generate”Endpoint
Section titled “Endpoint”POST https://api.discolike.com/v1/contacts/discover/generateUses 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.
Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
| icp_text | String | Yes | Persona description (e.g., “VPs or Directors of Marketing at B2B SaaS”) |
| domains | Array | Yes | List of company domains to search at (max 10,000) |
| context_mode | String | No | What data the LLM sees: website (default), profile, domain |
| integration_id | String | No | LLM provider integration UUID. Uses your default if omitted |
| search_provider_id | String | No | Search provider UUID. Uses your default if omitted |
Web search is always enabled server-side — contact discovery depends on LinkedIn/company-site lookups.
Response
Section titled “Response”{ "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}Result Schema (per domain, multi-row)
Section titled “Result Schema (per domain, multi-row)”Each domain yields zero or more rows. Every row carries contact fields plus the company-wide email pattern (repeated per row):
| Column | Type | Notes |
|---|---|---|
| name | String | Full name of the contact |
| title | String|null | Job title |
| department | String|null | One of the 15 canonical department values (see Persona Filters) |
| seniority | String|null | executive, vp, director, manager, senior_ic, mid_level, entry_level |
| String|null | Only if publicly verifiable | |
| linkedin_url | String|null | LinkedIn profile URL |
| skills | Array|null | Skills attributed to the contact |
| phone | Array | Array of phone objects with phone (+E164) and type (mobile or landline) fields, same shape as the indexed /contacts/discover response. |
| email_pattern | String|null | Template, e.g. first.last@, flastname@ |
| email_pattern_confidence | Number|null | 0-1 |
| email_pattern_guess | String|null | Example email for a hypothetical John Smith |
Example
Section titled “Example”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:
curl https://api.discolike.com/v1/discogen/status/TASK_ID \ -H "x-discolike-key: API_KEY"Count Contacts
Section titled “Count Contacts”Endpoint
Section titled “Endpoint”GET https://api.discolike.com/v1/contacts/countAccepts 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.
Example Request
Section titled “Example Request”curl "https://api.discolike.com/v1/contacts/count?seniority=vp&filter_industry=SAAS&filter_country=US" \ -H "x-discolike-key: API_KEY"Example Response
Section titled “Example Response”{ "count": 15432}Lookup Contact
Section titled “Lookup Contact”Endpoint
Section titled “Endpoint”GET https://api.discolike.com/v1/contacts/lookupParameters
Section titled “Parameters”| Parameter | Description |
|---|---|
| persona_id | The persona ID to look up (provide this OR linkedin). |
| LinkedIn URL or username to look up (provide this OR persona_id). |
Example Request
Section titled “Example Request”curl "https://api.discolike.com/v1/contacts/lookup?persona_id=12345678" \ -H "x-discolike-key: API_KEY"Or lookup by LinkedIn URL/username:
curl "https://api.discolike.com/v1/contacts/lookup?linkedin=https://www.linkedin.com/in/janedoe" \ -H "x-discolike-key: API_KEY"Example Response
Section titled “Example Response”{ "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..."}Legacy: Search Contacts (GET)
Section titled “Legacy: Search Contacts (GET)”Endpoint
Section titled “Endpoint”GET https://api.discolike.com/v1/contactsSame 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.
Example Request
Section titled “Example Request”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"Example Response
Section titled “Example Response”[ { "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 }]