LinktLinkt

Contact Discovery

Find and enrich people at target companies

Learn how to discover and enrich contacts (people) at your target companies, including email discovery, LinkedIn matching, and understanding hierarchical entity relationships.

Prerequisites

Before starting, ensure you have:

Person Entity Overview

Person entities represent individual contacts at companies. They include professional information, contact details, and social profiles.

Default Person Fields

Every person entity includes these default fields:

FieldTypeDescription
namestringFull name of the person
titlestringJob title or role
companystringCompany name
emailstringEmail address
linkedinSocialMediaProfileLinkedIn profile
locationLocationGeographic location
mobile_phonestringMobile phone number

Person Entity Structure

{
  "id": "507f1f77bcf86cd799439020",
  "sheet_id": "507f1f77bcf86cd799439012",
  "parent_id": "507f1f77bcf86cd799439015",
  "data": {
    "name": {
      "value": "Sarah Chen",
      "references": ["https://linkedin.com/in/sarachen"]
    },
    "title": {
      "value": "VP of Engineering",
      "references": ["https://linkedin.com/in/sarachen"]
    },
    "company": {
      "value": "TechCorp Inc",
      "references": ["https://techcorp.com/about"]
    },
    "email": {
      "value": "sarah.chen@techcorp.com",
      "references": []
    },
    "linkedin": {
      "value": {
        "platform": "linkedin",
        "url": "https://linkedin.com/in/sarachen"
      },
      "references": []
    },
    "location": {
      "value": {
        "city": "San Francisco",
        "state": "California",
        "country": "United States"
      },
      "references": []
    },
    "mobile_phone": {
      "value": "+1-415-555-0123",
      "references": []
    }
  },
  "created_at": "2025-01-06T10:15:00Z"
}

Hierarchical Relationships

Person entities are children of company entities, linked through the parent_id field.

Entity Hierarchy

Loading diagram...

How Parent-Child Works

FieldCompany EntityPerson Entity
parent_idnullCompany's entity ID
sheet_idCompany sheet IDPerson sheet ID

To get all contacts for a specific company:

# Get person entities with a specific parent_id
curl -X GET "https://api.linkt.ai/v1/entity?sheet_id={person_sheet_id}&parent_id={company_entity_id}" \
  -H "x-api-key: your-api-key"

Configure contact discovery by adding a person entity target to your ICP.

Basic Contact Discovery

curl -X POST "https://api.linkt.ai/v1/icp" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Engineering Leaders",
    "description": "Engineering leaders at SaaS companies",
    "mode": "discovery",
    "entity_targets": [
      {
        "entity_type": "company",
        "root": true,
        "description": "## Criteria\n- B2B SaaS companies\n- 50-500 employees\n- Series A or B funding"
      },
      {
        "entity_type": "person",
        "desired_count": 2,
        "description": "## Criteria\n- VP of Engineering, CTO, or Engineering Director\n- At least 2 years in role\n- Decision-making authority\n\n## Enrichment Fields\n- team_size: Size of engineering team managed\n- tech_focus: Primary technology focus areas"
      }
    ]
  }'

Person Targeting Criteria

Effective person criteria include:

CategoryExamples
Title/Role"VP of Engineering", "Director of Sales", "C-level"
Department"Engineering", "Product", "Marketing", "Sales"
Seniority"Director+", "VP or above", "Manager level"
Tenure"2+ years in role", "New to position"
Authority"Budget authority", "Decision maker"

Example Criteria Patterns

Sales Leadership:

## Criteria
- VP Sales, CRO, or Head of Sales
- B2B sales experience
- Team leadership responsibility

Technical Decision Makers:

## Criteria
- CTO, VP Engineering, or Principal Engineer
- Infrastructure or platform responsibility
- Vendor evaluation authority

Marketing Leaders:

## Criteria
- CMO, VP Marketing, or Director of Growth
- Digital marketing focus
- Marketing technology stack ownership

Contact Enrichment

Person entities are enriched with professional and contact information.

Enrichment Fields

Add custom enrichment fields to capture additional data:

curl -X POST "https://api.linkt.ai/v1/icp" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VP Sales with Enrichment",
    "mode": "discovery",
    "entity_targets": [
      {
        "entity_type": "company",
        "root": true,
        "description": "## Criteria\n- B2B SaaS companies\n- $10M+ ARR"
      },
      {
        "entity_type": "person",
        "desired_count": 1,
        "description": "## Criteria\n- VP Sales or CRO\n- B2B enterprise sales background\n\n## Enrichment Fields\n- sales_focus: Primary sales focus (enterprise, mid-market, SMB)\n- team_structure: Sales team size and structure\n- previous_companies: Notable previous employers\n- specializations: Industry or product specializations"
      }
    ]
  }'

Enriched Person Response

{
  "id": "507f1f77bcf86cd799439025",
  "parent_id": "507f1f77bcf86cd799439015",
  "data": {
    "name": {
      "value": "Michael Torres",
      "references": ["https://linkedin.com/in/mtorres"]
    },
    "title": {
      "value": "VP of Sales",
      "references": ["https://linkedin.com/in/mtorres"]
    },
    "email": {
      "value": "mtorres@acmecorp.com",
      "references": []
    },
    "sales_focus": {
      "value": "Enterprise B2B, $100K+ ACV deals",
      "references": ["https://linkedin.com/in/mtorres"]
    },
    "team_structure": {
      "value": "Leads team of 15 AEs across NA and EMEA",
      "references": ["https://acmecorp.com/about"]
    },
    "previous_companies": {
      "value": "Salesforce, Oracle, HubSpot",
      "references": ["https://linkedin.com/in/mtorres"]
    }
  }
}

Email Discovery

Email addresses are discovered and validated during enrichment.

Email Field Structure

{
  "email": {
    "value": "sarah.chen@techcorp.com",
    "references": [],
    "created_at": "2025-01-06T10:15:00Z"
  }
}

Email Patterns

Linkt discovers emails through:

  • Public profiles and websites
  • Company email patterns
  • Professional databases

LinkedIn Matching

LinkedIn profiles are stored using the SocialMediaProfile type.

SocialMediaProfile Structure

{
  "linkedin": {
    "value": {
      "platform": "linkedin",
      "url": "https://linkedin.com/in/sarachen"
    },
    "references": []
  }
}

Supported Platforms

PlatformValueExample URL
LinkedInlinkedinhttps://linkedin.com/in/username
X (Twitter)xhttps://x.com/username
Instagraminstagramhttps://instagram.com/username

Using LinkedIn Data

Extract the profile URL for outreach:

# Get LinkedIn URL from person entity
person_data = entity["data"]
linkedin = person_data.get("linkedin", {}).get("value", {})
 
if linkedin:
    linkedin_url = linkedin.get("url")
    print(f"LinkedIn: {linkedin_url}")

Mobile Phone Discovery

Mobile phone numbers can be discovered for person entities.

Phone Field Structure

{
  "mobile_phone": {
    "value": "+1-415-555-0123",
    "references": []
  }
}

Complete Example

Here's a full workflow for contact discovery:

import requests
import time
 
API_KEY = "your-api-key"
BASE_URL = "https://api.linkt.ai/v1"
HEADERS = {"x-api-key": API_KEY, "Content-Type": "application/json"}
 
def discover_contacts(company_criteria, person_criteria, contacts_per_company=2):
    """Discover companies and their contacts."""
 
    # Step 1: Create ICP with company + person targets
    print("Creating ICP...")
    icp_response = requests.post(
        f"{BASE_URL}/icp",
        headers=HEADERS,
        json={
            "name": "Contact Discovery",
            "description": "Discover contacts at target companies",
            "mode": "discovery",
            "entity_targets": [
                {
                    "entity_type": "company",
                    "root": True,
                    "description": company_criteria
                },
                {
                    "entity_type": "person",
                    "desired_count": contacts_per_company,
                    "description": person_criteria
                }
            ]
        }
    )
    icp = icp_response.json()
    icp_id = icp["id"]
 
    # Step 2: Create sheets for companies and people
    print("Creating sheets...")
    company_sheet = requests.post(
        f"{BASE_URL}/sheet",
        headers=HEADERS,
        json={
            "name": "Target Companies",
            "icp_id": icp_id,
            "entity_type": "company"
        }
    ).json()
 
    person_sheet = requests.post(
        f"{BASE_URL}/sheet",
        headers=HEADERS,
        json={
            "name": "Contacts",
            "icp_id": icp_id,
            "entity_type": "person"
        }
    ).json()
 
    # Step 3: Create and execute search task
    print("Creating search task...")
    task = requests.post(
        f"{BASE_URL}/task",
        headers=HEADERS,
        json={
            "name": "Contact Discovery Search",
            "flow_name": "search",
            "deployment_name": "main",
            "sheet_id": company_sheet["id"],
            "task_config": {
                "version": "v3.0",
                "config_type": "search-task",
                "desired_contact_count": contacts_per_company,
                "user_feedback": ""
            }
        }
    ).json()
 
    print("Executing search...")
    run = requests.post(
        f"{BASE_URL}/task/{task['id']}/execute",
        headers=HEADERS,
        json={"icp_id": icp_id}
    ).json()
 
    # Step 4: Wait for completion
    print("Waiting for results...")
    while True:
        status = requests.get(
            f"{BASE_URL}/run/{run['run_id']}",
            headers={"x-api-key": API_KEY}
        ).json()
 
        if status["status"] == "COMPLETED":
            break
        elif status["status"] in ["FAILED", "CANCELED", "CRASHED"]:
            raise Exception(f"Search failed: {status.get('error')}")
 
        time.sleep(10)  # Poll every 10 seconds
 
    # Step 5: Retrieve results
    print("\nResults:")
    companies = requests.get(
        f"{BASE_URL}/sheet/{company_sheet['id']}/entities",
        headers={"x-api-key": API_KEY}
    ).json()
 
    people = requests.get(
        f"{BASE_URL}/sheet/{person_sheet['id']}/entities",
        headers={"x-api-key": API_KEY}
    ).json()
 
    print(f"  Companies: {companies['total']}")
    print(f"  Contacts: {people['total']}")
 
    # Step 6: Organize contacts by company
    contacts_by_company = {}
    for person in people["entities"]:
        parent_id = person.get("parent_id")
        if parent_id:
            if parent_id not in contacts_by_company:
                contacts_by_company[parent_id] = []
            contacts_by_company[parent_id].append(person)
 
    # Print summary
    print("\nContacts by company:")
    for company in companies["entities"]:
        company_name = company["data"]["name"]["value"]
        company_id = company["id"]
        contacts = contacts_by_company.get(company_id, [])
 
        print(f"\n  {company_name}:")
        for contact in contacts:
            name = contact["data"]["name"]["value"]
            title = contact["data"].get("title", {}).get("value", "Unknown")
            email = contact["data"].get("email", {}).get("value", "No email")
            print(f"    - {name} ({title}) - {email}")
 
    return {
        "companies": companies,
        "people": people,
        "contacts_by_company": contacts_by_company
    }
 
# Run contact discovery
result = discover_contacts(
    company_criteria="""## Criteria
- B2B SaaS companies
- 100-500 employees
- Series A or B funding
- US headquarters
 
## Enrichment Fields
- primary_product: Main product offering
- target_market: Primary customer segment""",
 
    person_criteria="""## Criteria
- VP, Director, or C-level
- Engineering, Product, or Sales department
- Decision-making authority for technology purchases
 
## Enrichment Fields
- responsibilities: Primary job responsibilities
- tech_focus: Technology areas of focus""",
 
    contacts_per_company=3
)

Expected Output

Creating ICP...
Creating sheets...
Creating search task...
Executing search...
Waiting for results...

Results:
  Companies: 25
  Contacts: 68

Contacts by company:

  TechCorp Inc:
    - Sarah Chen (VP of Engineering) - sarah.chen@techcorp.com
    - James Wilson (Director of Product) - jwilson@techcorp.com
    - Maria Garcia (VP Sales) - mgarcia@techcorp.com

  DataFlow Systems:
    - Robert Kim (CTO) - rkim@dataflow.io
    - Emily Davis (VP Engineering) - edavis@dataflow.io

Best Practices

Optimize Person Criteria

DoDon't
Be specific about titlesUse vague role descriptions
Include seniority levelTarget all employees
Specify departmentsLeave department open
Add authority requirementsIgnore decision-making power

Balance Contact Density

Use CaseRecommended Count
Initial outreach1-2 contacts
Multi-threaded3-5 contacts
ABM campaigns5-10 contacts
Executive mapping2-3 C-level only

Handle Missing Data

Not all contacts will have complete information:

def get_contact_info(person_data):
    """Safely extract contact information."""
    return {
        "name": person_data.get("name", {}).get("value", "Unknown"),
        "title": person_data.get("title", {}).get("value", "Unknown"),
        "email": person_data.get("email", {}).get("value"),
        "phone": person_data.get("mobile_phone", {}).get("value"),
        "linkedin": person_data.get("linkedin", {}).get("value", {}).get("url"),
    }

Next Steps