Contacts API
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.
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, and is 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). |
| exclusion_query_id | Exclude results from saved queries. Works with domain lists (excludes companies) and contact lists (excludes specific contacts). |
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. C-suite acronyms are auto-expanded to their spelled-out forms and vice versa (e.g. CEO also matches Chief Executive Officer); wrap a term in quotes to match it literally without expansion. |
| negate_title | Exclude contacts with specified job titles. C-suite acronyms are expanded the same way as in title. |
| 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, and 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. |
| jobstart_date | Filter by job start date: a minimum date (YYYY-MM-DD) or a range (YYYY-MM-DD,YYYY-MM-DD). Matches contacts who started their current role in this window, the “recently hired” filter. Contacts without a known start date are excluded. |
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, and 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", "jobstart_date": "2025-11-01", "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, so 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”). Must be non-empty |
| domains | Array | Yes | List of company domains to search at (1-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, because 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. |
| LinkedIn URL or username to look up. Must be a valid LinkedIn profile URL or a bare username. | |
| Email address to look up (exact match, case-insensitive). Must be a valid email address. |
One of persona_id, linkedin, or email must be provided. Returns 404 when no contact matches.
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"Or lookup by email:
curl "https://api.discolike.com/v1/contacts/lookup?email=jane.doe@example.com" \ -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", "jobstart_date": "2025-11-01", "similarity": 87 }]