Skip to content

DataVertex Contact Lookup API

Overview

The DataVertex Contact Lookup API retrieves detailed contact information for specific candidates, including personal emails, phone numbers, and enriched profile data. You can lookup contacts using: - Candidate IDs from search results - LinkedIn URLs directly (no search required)

Endpoint: POST https://api.data-vertex.com/v1/contact-lookup

Credit Cost: Variable (3-11 credits per candidate based on enrichments requested)

Billing: Success-based - you're only charged for data actually retrieved

Capacity: 1 contact per request

Performance: For multiple candidates, make concurrent API calls for optimal speed. Each request is processed independently, allowing for parallel execution and faster overall throughput


Authentication

All API requests must include your API key in the request headers:

x-api-key: YOUR_API_KEY

You can obtain your API key from DataVertex directly.


Credit Costs

DataVertex uses a flexible, success-based pricing model. You only pay for data that's actually retrieved:

Enrichment Type Credit Cost Parameter
Personal Email 3 credits per email reveal_personal_email: true
Mobile Phone 6 credits per phone reveal_phone: true
Detailed Profile 1 credit per profile reveal_detailed_person_enrichment: true
Healthcare Data 1 credit per profile reveal_healthcare_enrichment: true

Success-Based Billing Example

If you request email + phone for 5 candidates, but only 3 have emails and 2 have phones: - Email charges: 3 candidates × 3 credits = 9 credits - Phone charges: 2 candidates × 6 credits = 12 credits - Total: 21 credits (not 45 credits)

You're never charged for: - Failed lookups - Missing data - Invalid candidate IDs


Request Format

Headers

Header Value Required
x-api-key Your API key Yes
Content-Type application/json Yes

Body Parameters

Parameter Type Description Required
candidate_ids array of strings (1 item) Single candidate ID from search results One identifier required
linkedin_urls array of strings (1 item) Single LinkedIn profile URL One identifier required
reveal_personal_email boolean Retrieve personal email address No (default: false)
reveal_phone boolean Retrieve mobile phone number No (default: false)
reveal_detailed_person_enrichment boolean Retrieve skills, experience, education No (default: false)
reveal_healthcare_enrichment boolean Retrieve NPI, medical license, specialty No (default: false)

Important: - Provide exactly one identifier: either candidate_ids with 1 ID OR linkedin_urls with 1 URL - At least one enrichment parameter must be set to true - For multiple candidates, make concurrent API calls


Request Examples

Option 1: Lookup by Candidate ID (from search results)

Basic Request (Email Only)

{
  "candidate_ids": ["12345"],
  "reveal_personal_email": true,
  "reveal_phone": false,
  "reveal_detailed_person_enrichment": false,
  "reveal_healthcare_enrichment": false
}

Full Enrichment Request

{
  "candidate_ids": ["67890"],
  "reveal_personal_email": true,
  "reveal_phone": true,
  "reveal_detailed_person_enrichment": true,
  "reveal_healthcare_enrichment": false
}

Option 2: Lookup by LinkedIn URL (direct lookup)

Basic Request (Email Only)

{
  "linkedin_urls": ["https://www.linkedin.com/in/jane-smith-12345"],
  "reveal_personal_email": true,
  "reveal_phone": false,
  "reveal_detailed_person_enrichment": false,
  "reveal_healthcare_enrichment": false
}

Full Enrichment Request

{
  "linkedin_urls": ["https://www.linkedin.com/in/john-doe-67890"],
  "reveal_personal_email": true,
  "reveal_phone": true,
  "reveal_detailed_person_enrichment": true,
  "reveal_healthcare_enrichment": false
}

Response Format

Success Response (200 OK)

{
  "success": true,
  "data": {
    "contacts": [
      {
        "lookup_identifier": "12345",
        "lookup_type": "id",
        "success": true,
        "profile": {
          "id": "12345",
          "name": "Jane Smith",
          "current_title": "Software Engineer",
          "current_employer": "TechCorp",
          "personal_email": "jane.smith@gmail.com",
          "phone_number": "+14155551234",
          "phone_type": "mobile",
          "phones": [
            {
              "number": "+14155551234",
              "type": "mobile"
            }
          ],
          "skills": ["Python", "JavaScript", "React"],
          "experience": [...],
          "education": [...]
        },
        "contact_data_retrieved": ["email", "phone", "detailed_profile"],
        "retrieved_at": "2025-12-10T12:00:00Z"
      }
    ],
    "summary": {
      "total_requested": 1,
      "successful": 1,
      "failed": 0
    }
  },
  "credits": {
    "used": 10,
    "remaining": 990,
    "billing_note": "Charged for 1 successful lookup only"
  }
}

Response Fields

Contact Object

Each contact in the contacts array contains:

Success Case

Field Type Description
lookup_identifier string The requested identifier (candidate ID or LinkedIn URL)
lookup_type string Type of lookup: "id" or "linkedin_url"
success boolean Whether lookup succeeded (true)
profile object Enriched profile data (see below)
contact_data_retrieved array of strings Types of data retrieved
retrieved_at string ISO timestamp when data was retrieved

Failure Case

Field Type Description
lookup_identifier string The requested identifier (candidate ID or LinkedIn URL)
lookup_type string Type of lookup: "id" or "linkedin_url"
success boolean Whether lookup succeeded (false)
error string Error description
status_code integer HTTP status code (404, 500, etc.)

Profile Object

The profile object contains enriched data based on your requested enrichments:

Basic Fields (Always Included)

Field Type Description
id string Candidate ID
name string Full name
current_title string Current job title
current_employer string Current company name

Email Fields (reveal_personal_email: true)

Field Type Description
personal_email string Personal email address (verified)

Multi-Source Data: DataVertex uses multiple data sources to maximize email retrieval success. If our primary source doesn't have an email, we automatically check secondary sources at no extra cost.

Phone Fields (reveal_phone: true)

Field Type Description
phone_number string Primary/mobile phone number
phone_type string Phone type (mobile, work, home)
phones array Complete list of phone numbers with types

Example phones array:

"phones": [
  {
    "number": "+14155551234",
    "type": "mobile"
  },
  {
    "number": "+16505559876",
    "type": "work"
  }
]

Detailed Profile Fields (reveal_detailed_person_enrichment: true)

Field Type Description
skills array List of skills
experience array Work experience/job history
education array Educational background
job_history array Complete employment history

Healthcare Fields (reveal_healthcare_enrichment: true)

Field Type Description
npi_data object National Provider Identifier data

The npi_data object contains: - npi_number: National Provider Identifier - license_number: Medical license number - license_state: State where licensed - specialty: Medical specialty - credentials: Professional credentials (MD, RN, etc.)

Contact Data Retrieved Array

Indicates what data types were successfully retrieved:

Value Description
"email" Personal email was found
"phone" Phone number was found
"detailed_profile" Skills/experience/education data was found
"healthcare_profile" Healthcare/NPI data was found

Summary Object

Field Type Description
total_requested integer Total candidates requested
successful integer Number of successful lookups
failed integer Number of failed lookups

Credits Object

Field Type Description
used integer Credits charged for this request
remaining integer Your remaining credit balance
billing_note string Explanation of charges

Code Examples

cURL

curl -X POST https://api.data-vertex.com/v1/contact-lookup \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "candidate_ids": ["12345"],
    "reveal_personal_email": true,
    "reveal_phone": true,
    "reveal_detailed_person_enrichment": false,
    "reveal_healthcare_enrichment": false
  }'

Python

import requests

url = "https://api.data-vertex.com/v1/contact-lookup"

headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
}

payload = {
    "candidate_ids": ["12345"],
    "reveal_personal_email": True,
    "reveal_phone": True,
    "reveal_detailed_person_enrichment": False,
    "reveal_healthcare_enrichment": False
}

response = requests.post(url, headers=headers, json=payload)

if response.status_code == 200:
    data = response.json()

    for contact in data['data']['contacts']:
        if contact['success']:
            profile = contact['profile']
            print(f"Name: {profile['name']}")
            print(f"Email: {profile.get('personal_email', 'N/A')}")
            print(f"Phone: {profile.get('phone_number', 'N/A')}")
            print(f"Retrieved: {', '.join(contact['contact_data_retrieved'])}")
            print("---")

    print(f"\nCredits used: {data['credits']['used']}")
    print(f"Credits remaining: {data['credits']['remaining']}")
else:
    print(f"Error: {response.status_code}")
    print(response.text)

JavaScript (Node.js)

const axios = require('axios');

const lookupContact = async (candidateId) => {
  try {
    const response = await axios.post(
      'https://api.data-vertex.com/v1/contact-lookup',
      {
        candidate_ids: [candidateId],
        reveal_personal_email: true,
        reveal_phone: true,
        reveal_detailed_person_enrichment: false,
        reveal_healthcare_enrichment: false
      },
      {
        headers: {
          'x-api-key': 'YOUR_API_KEY',
          'Content-Type': 'application/json'
        }
      }
    );

    const { contacts, summary } = response.data.data;

    contacts.forEach(contact => {
      if (contact.success) {
        const { profile, contact_data_retrieved } = contact;
        console.log(`Name: ${profile.name}`);
        console.log(`Email: ${profile.personal_email || 'N/A'}`);
        console.log(`Phone: ${profile.phone_number || 'N/A'}`);
        console.log(`Retrieved: ${contact_data_retrieved.join(', ')}`);
        console.log('---');
      } else {
        console.log(`Failed: ${contact.lookup_identifier} - ${contact.error}`);
      }
    });

    console.log(`Credits used: ${response.data.credits.used}`);

    return response.data;
  } catch (error) {
    console.error('Error:', error.response?.data || error.message);
  }
};

// Example usage
lookupContact('12345');

Complete Workflow Example

Here's a complete example showing search followed by concurrent contact lookups:

Python

import requests
from concurrent.futures import ThreadPoolExecutor, as_completed

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.data-vertex.com/v1"

headers = {
    "x-api-key": API_KEY,
    "Content-Type": "application/json"
}

# Step 1: Search for candidates
search_response = requests.post(
    f"{BASE_URL}/search",
    headers=headers,
    json={
        "search_criteria": {
            "current_title": ["Software Engineer"],
            "location": ["San Francisco::~50mi"],
            "contact_method": ["personal email"]
        },
        "page_size": 10
    }
)

search_data = search_response.json()

# Step 2: Extract candidate IDs
candidate_ids = [
    profile['id'] 
    for profile in search_data['data']['profiles']
][:5]  # Take first 5

print(f"Found {len(candidate_ids)} candidates to lookup")

# Step 3: Lookup contact information concurrently
def lookup_single_contact(candidate_id):
    """Lookup a single candidate"""
    response = requests.post(
        f"{BASE_URL}/contact-lookup",
        headers=headers,
        json={
            "candidate_ids": [candidate_id],
            "reveal_personal_email": True,
            "reveal_phone": True,
            "reveal_detailed_person_enrichment": True,
            "reveal_healthcare_enrichment": False
        }
    )
    return response.json()

# Make concurrent requests (up to 10 at a time)
all_results = []
with ThreadPoolExecutor(max_workers=10) as executor:
    future_to_id = {
        executor.submit(lookup_single_contact, cid): cid 
        for cid in candidate_ids
    }

    for future in as_completed(future_to_id):
        try:
            result = future.result()
            all_results.append(result)
        except Exception as e:
            print(f"Error looking up {future_to_id[future]}: {e}")

# Step 4: Process results
print("\nContact Information:")
total_credits = 0
for result in all_results:
    contacts = result['data']['contacts']
    for contact in contacts:
        if contact['success']:
            profile = contact['profile']
            print(f"\n{profile['name']} - {profile['current_title']} at {profile['current_employer']}")
            print(f"  Email: {profile.get('personal_email', 'N/A')}")
            print(f"  Phone: {profile.get('phone_number', 'N/A')}")
            print(f"  Skills: {', '.join(profile.get('skills', [])[:5])}")
        else:
            print(f"\nFailed to lookup {contact['lookup_identifier']}: {contact['error']}")

    total_credits += result['credits']['used']

# Step 5: Check credits
print(f"\n--- Credit Usage ---")
print(f"Search credits: {search_data['credits']['used']}")
print(f"Lookup credits: {total_credits}")
print(f"Total used: {search_data['credits']['used'] + total_credits}")
print(f"Remaining: {all_results[-1]['credits']['remaining']}")

Python Example - Direct LinkedIn URL Lookup

import requests

BASE_URL = "https://api.data-vertex.com/v1"
API_KEY = "your_api_key_here"

headers = {
    "x-api-key": API_KEY,
    "Content-Type": "application/json"
}

# Direct lookup using a LinkedIn URL (no search required)
linkedin_url = "https://www.linkedin.com/in/jane-smith-12345"

# Lookup contact information directly
lookup_response = requests.post(
    f"{BASE_URL}/contact-lookup",
    headers=headers,
    json={
        "linkedin_urls": [linkedin_url],
        "reveal_personal_email": True,
        "reveal_phone": True,
        "reveal_detailed_person_enrichment": False,
        "reveal_healthcare_enrichment": False
    }
)

lookup_data = lookup_response.json()

# Process result
contact = lookup_data['data']['contacts'][0]
if contact['success']:
    profile = contact['profile']
    print(f"{profile['name']} - {profile['current_title']} at {profile['current_employer']}")
    print(f"  LinkedIn: {contact['lookup_identifier']}")
    print(f"  Email: {profile.get('personal_email', 'N/A')}")
    print(f"  Phone: {profile.get('phone_number', 'N/A')}")
else:
    print(f"Failed to lookup {contact['lookup_identifier']}: {contact['error']}")

# Check credits
print(f"\n--- Credit Usage ---")
print(f"Lookup credits: {lookup_data['credits']['used']}")
print(f"Remaining: {lookup_data['credits']['remaining']}")

Error Responses

400 Bad Request

Missing or invalid parameters:

{
  "success": false,
  "message": "Either candidate_ids or linkedin_urls array is required."
}

Or invalid enrichment parameters:

{
  "success": false,
  "message": "At least one enrichment option must be enabled (set to true)."
}

Or too many identifiers:

{
  "success": false,
  "message": "Must provide exactly 1 identifier (candidate_id or linkedin_url) per request. You provided 5. For multiple candidates, make concurrent API calls."
}

403 Forbidden

Authentication error:

{
  "success": false,
  "message": "Invalid or inactive API key."
}

Or insufficient credits:

{
  "success": false,
  "message": "Insufficient credits. Required: 27, Available: 10",
  "credits_info": {
    "required": 27,
    "available": 10,
    "breakdown": "3 contacts × 9 credits each"
  }
}

Note: The required credits shown is the maximum if all data is found. Actual charges will be lower based on success-based billing.

404 Not Found

Individual candidate not found (per-contact error within 200 response):

{
  "candidate_id": "99999",
  "success": false,
  "error": "Profile not found",
  "status_code": 404
}

500 Internal Server Error

Server error:

{
  "success": false,
  "message": "Internal server error occurred."
}

Error Codes Summary

Status Code Meaning Common Causes
200 OK Request successful (check individual contact success)
400 Bad Request Missing parameters, invalid enrichment options, too many IDs
403 Forbidden Missing/invalid API key, insufficient credits
404 Not Found Candidate not found (per-contact, within 200 response)
500 Internal Server Error Unexpected server error

Important: A 200 response doesn't mean all lookups succeeded. Check each contact's success field individually.


Best Practices

1. Request Only What You Need

Only enable enrichments you'll actually use to minimize credit costs:

# Just need emails for outreach
payload = {
    "candidate_ids": ["12345"],
    "reveal_personal_email": True,
    "reveal_phone": False,
    "reveal_detailed_person_enrichment": False,
    "reveal_healthcare_enrichment": False
}

2. Make Concurrent Requests for Multiple Candidates

For optimal performance when looking up multiple candidates, make concurrent API calls:

from concurrent.futures import ThreadPoolExecutor, as_completed

def lookup_contact(candidate_id):
    """Lookup a single candidate"""
    response = requests.post(
        "https://api.data-vertex.com/v1/contact-lookup",
        headers=headers,
        json={
            "candidate_ids": [candidate_id],
            "reveal_personal_email": True,
            "reveal_phone": True
        }
    )
    return response.json()

# Process candidates concurrently (up to 15 at a time recommended)
with ThreadPoolExecutor(max_workers=15) as executor:
    futures = {
        executor.submit(lookup_contact, cid): cid 
        for cid in all_candidate_ids
    }

    for future in as_completed(futures):
        try:
            result = future.result()
            # Process result
            print(f"Completed: {futures[future]}")
        except Exception as e:
            print(f"Error: {e}")

Performance Benefits: - Results available progressively (don't wait for all to finish) - Better user experience with streaming results - Efficient parallel processing

3. Handle Partial Failures Gracefully

Not all lookups will succeed. Handle failures appropriately:

for result in results:
    contacts = result['data']['contacts']
    for contact in contacts:
        if contact['success']:
            # Process successful lookup
            print(f"Success: {contact['profile']['name']}")
        else:
            # Log failure
            print(f"Failed: {contact['lookup_identifier']} - {contact['error']}")

4. Validate Identifiers

Ensure identifiers are valid:

# Good: IDs from DataVertex search
candidate_ids = [profile['id'] for profile in search_results['profiles']]

# Good: Valid LinkedIn URLs
linkedin_urls = [
    "https://www.linkedin.com/in/john-doe-12345",
    "https://www.linkedin.com/in/jane-smith-67890"
]

# Bad: Random or malformed identifiers
candidate_ids = ["invalid_id", "expired_id"]
linkedin_urls = ["not-a-linkedin-url", "malformed"]

5. Monitor Success-Based Billing

Track what data you're actually getting:

email_count = 0
phone_count = 0
total_credits = 0

for result in results:
    contacts = result['data']['contacts']
    for contact in contacts:
        if contact['success']:
            if 'email' in contact['contact_data_retrieved']:
                email_count += 1
            if 'phone' in contact['contact_data_retrieved']:
                phone_count += 1

    total_credits += result['credits']['used']

print(f"Retrieved {email_count} emails and {phone_count} phones")
print(f"Total credits used: {total_credits}")

Common Use Cases

Example 1: Email-Only Lookup for Cold Outreach

{
  "candidate_ids": ["12345"],
  "reveal_personal_email": true,
  "reveal_phone": false,
  "reveal_detailed_person_enrichment": false,
  "reveal_healthcare_enrichment": false
}

Cost: 3 credits per email found (success-based)

Example 2: Full Contact + Profile Data

{
  "candidate_ids": ["12345"],
  "reveal_personal_email": true,
  "reveal_phone": true,
  "reveal_detailed_person_enrichment": true,
  "reveal_healthcare_enrichment": false
}

Cost: Up to 10 credits per contact (3 email + 6 phone + 1 profile)

Example 3: Healthcare Professional Lookup

{
  "candidate_ids": ["98765"],
  "reveal_personal_email": true,
  "reveal_phone": true,
  "reveal_detailed_person_enrichment": false,
  "reveal_healthcare_enrichment": true
}

Cost: Up to 10 credits per contact (3 email + 6 phone + 1 healthcare)

Example 4: Phone-Only Lookup for SMS Campaigns

{
  "candidate_ids": ["12345"],
  "reveal_personal_email": false,
  "reveal_phone": true,
  "reveal_detailed_person_enrichment": false,
  "reveal_healthcare_enrichment": false
}

Cost: 6 credits per phone found (success-based)

Example 5: Concurrent Lookups for Multiple Candidates

For multiple candidates, make concurrent API calls:

from concurrent.futures import ThreadPoolExecutor

candidate_ids = ["12345", "67890", "11111", "22222"]

def lookup_contact(cid):
    return requests.post(
        "https://api.data-vertex.com/v1/contact-lookup",
        headers={"x-api-key": API_KEY, "Content-Type": "application/json"},
        json={
            "candidate_ids": [cid],
            "reveal_personal_email": True,
            "reveal_phone": True
        }
    ).json()

# Make concurrent requests
with ThreadPoolExecutor(max_workers=15) as executor:
    results = list(executor.map(lookup_contact, candidate_ids))

# Total cost: Up to 9 credits per contact (3 email + 6 phone) × 4 contacts = up to 36 credits

Use Case: Efficiently lookup multiple candidates from search results or external lists.


Need Help?

  • Support: dev@data-vertex.com
  • Website: https://www.data-vertex.com

Last Updated: February 20, 2026