# B2B Contact Data API - Work Emails and Direct Phones (`nabeelbaghoor/b2b-contact-data-api`) Actor

Find verified work emails and direct phone numbers for B2B contacts. Resolve a person from a profile URL, an email, or a name plus employer, look companies up by name or domain, and prospect segments by industry, technology, location and seniority. Pay per result. Bring your own API key.

- **URL**: https://apify.com/nabeelbaghoor/b2b-contact-data-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Business, Developer tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$15.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## B2B Contact Data API - Work Emails and Direct Phones

Find verified work email addresses and direct phone numbers for B2B contacts. Resolve a person you can already identify, look up a company by name or domain, or prospect a whole segment by industry, technology stack, location, job title and seniority. One flat row per person or company.

### What this actor does

- **Resolves a person from whatever identifier you have.** A profile URL, a work email address, or a name paired with their employer all lead to the same record, so lists exported from different systems can be enriched in one pass. A list of names crossed with a list of employers becomes every pairing, which turns ten names at one company into exactly ten lookups.
- **Returns the evidence behind each contact value.** Every email and phone comes back with its type and its verification status, not just the value. That distinction is the difference between a list you can send to today and one that needs a verification pass first, and it is preserved rather than flattened away.
- **Filters on contact availability before you pay.** Ask only for people with a work email, a verified work email, a work phone, a verified work phone or a personal email, so a prospecting list arrives free of records you cannot act on.
- **Prospects by technology stack.** Advanced search filters companies by the technologies and technology categories they run, alongside industry, country, state and description keywords, then returns the people inside each one who match your title, seniority and role filters.
- **Keeps the company context on every row.** Each contact row carries the employer's domain, industry, headcount, address, phone numbers and funding history, so the dataset is usable without a second lookup or a join.
- **Understands that this provider fails inside a success.** Rejected queries come back as HTTP 200 with an errors array, and a person the provider does not have comes back as an empty result. Both are recognised properly: the first stops the run with the provider's own message, the second becomes a visible miss.
- **Never charges for a miss.** Only rows carrying a resolved result are billed.

### Input

| Field | What it does |
| --- | --- |
| `mode` | Contact lookup, company lookup or advanced search. |
| `fullNames` | Names to resolve, paired with each company. |
| `companies` | Company names, as employers or as search targets. |
| `domains` | Company domains, used the same way. |
| `profileUrls` | Profile URLs to resolve. |
| `emails` | Work addresses to resolve back to a person. |
| `profileFilters` | Require a work email, verified email, phone or personal email. |
| `requireWorkContactInfo` | Only people with work contact information at all. |
| `premiumFields` | Ask for fields charged separately on your plan. |
| `jobTitles` | Job titles to match on the people returned. |
| `seniorities` | Seniority levels to match. |
| `roles` | Functional roles to match. |
| `industries` | Industries the company should be in. |
| `countries`, `states` | Where the company should be. |
| `technologies` | Technologies the company runs. |
| `technologyCategories` | Categories of technology the company runs. |
| `companyDescriptions` | Keywords matched against the company description. |
| `peoplePerCompany` | How many matching people to return per company. |
| `sortCompaniesBy` | Ordering for the advanced search. |
| `pageSize` | Results per request. |
| `requestsPerMinute` | Pace the run under your plan's rate limit. |
| `skipNotFound` | Leave unresolved inputs out of the dataset. |
| `maxResults` | Hard cap on rows, and therefore on spend and run time. |
| `apiKey` | Your own secret API key. Stored as a secret. |

### Example output

```json
{
  "found": true,
  "mode": "peopleSearch",
  "query": "Jane Doe at example.com",
  "personId": "PersonID-d053d022-7a5d-4d74-80e9-bf05ffb0bd6e",
  "fullName": "Jane Doe",
  "firstName": "Jane",
  "lastName": "Doe",
  "position": "VP of Engineering",
  "positionStarted": "2023-04-01",
  "workEmails": ["jane.doe@example.com"],
  "workEmailRecords": [
    { "value": "jane.doe@example.com", "type": "WorkEmail", "status": "Verified" }
  ],
  "workPhones": ["+14155550123"],
  "workPhoneRecords": [
    { "value": "+14155550123", "type": "WorkHQ", "status": "Unverified" }
  ],
  "personalEmails": null,
  "hasWorkContactInfo": true,
  "linkedinUrl": "https://www.linkedin.com/in/janedoe",
  "linkedinId": "4327441",
  "organization": "Example Labs",
  "companyDomain": "example.com",
  "companyIndustry": "Computer Software",
  "companyEmployees": 850,
  "city": "San Francisco",
  "state": "California",
  "country": "United States",
  "companyFundingTotalUsd": 92000000,
  "companyLastFundingOn": "2025-11-18",
  "error": null,
  "raw": { }
}
```

### Frequently asked questions

#### What data does this B2B contact API return?

Each contact row carries the full name and its parts, the current job title with its start date, the work email addresses and work phone numbers with a type and a verification status on each one, personal emails and phones where the provider holds them, the profile URL and identifier, and the past positions. The employer comes with it: domain, email domains, industry, headcount, address broken into city, state, postcode and country, company phone numbers, logo, and funding history with the round count, total raised and last round date.

#### What does the verification status on an email actually mean?

The provider reports each contact value as verified, verified likely, unverified or invalid, and keeps that status separate from the value itself. It matters because those four call for different handling: verified addresses can go straight into a sending tool, verified likely and unverified are worth a validation pass first, and invalid ones are there so you can suppress them rather than rediscover them later. Filter on a verified work email if you want only the first group.

#### How do I build a prospecting list for accounts using a specific technology?

Use advanced search. Put the technologies in the technologies filter, narrow with industry, country and headcount context as needed, then set the job titles and seniority levels you sell into and how many people you want per company. The result is one row per person, each carrying its company, so a search across four hundred accounts arrives as a flat list you can sort and segment without a join.

#### What is the difference between contact lookup and advanced search?

Contact lookup starts from people you can already name. It is the enrichment mode: give it profile URLs, addresses, or names with employers, and it fills in the rest. Advanced search starts from a market segment rather than a list of people. It is the prospecting mode: describe the companies and the kinds of people inside them, and it finds both. Use the first to enrich a CRM export, and the second to build a list from nothing.

#### Can one name return more than one person?

Yes, and the actor handles that rather than taking the first match. Two people with the same name at one employer is a real situation, so a contact lookup pages through every match the provider returns for that identifier. If that is not what you want, narrow the input by using a profile URL or an email address instead of a name, since both identify exactly one person.

#### Do I need my own API key?

Yes. This actor does not include data access. You use your own API key from LeadIQ, which is the provider whose contact data API this actor calls, created in your account settings. Use the secret key rather than the public one. Your own plan, usage caps and terms apply. Paste the key into the `apiKey` field, where it is stored as an Apify secret and sent in an authorization header rather than a URL parameter, so it never appears in a log line or a redirect.

#### Why does the actor say the key was rejected when the key looks right?

This provider authenticates with HTTP Basic where the key is the username and the password is empty, which means the credential is the key followed by a colon. Encoding the key without that trailing colon produces a rejection that looks exactly like a wrong key. The actor builds the credential correctly, so a rejection here almost always means the public key was pasted instead of the secret one.

#### How does this handle rate limits and usage caps?

Requests are spaced evenly across the minute rather than bursting, at a pace you set. A rate limit response is retried with backoff because it clears on its own. A usage cap is different: this provider reports it inside an otherwise successful response, the actor recognises it in the provider's own message, and the run stops with what it has rather than burning retries on an allowance that waiting will not restore.

#### What happens when a person or company returns nothing?

The row is written with `found: false` and an `error` explaining that the provider had no record, and the run continues to the next input. This provider has no not-found status, so an unknown person is an empty result inside a successful response rather than an error, and the actor treats that shape as a miss instead of a failure. Misses are not charged for. Set `skipNotFound` to true to leave them out of the dataset entirely.

#### How much does a run cost?

Pricing is pay per result: you are charged for each contact or company returned to the dataset, and never for misses or duplicates. Apify platform usage is included in the per-result price. Your own API provider's usage allowance, including any premium field credits, is separate and billed by them.

### Keyword map

B2B contact data API, work email finder, direct dial phone numbers, verified email API, contact enrichment API, sales prospecting API, technographic search, technology stack prospecting, company firmographics API, ICP list building, job title and seniority filtering, LinkedIn profile enrichment, email verification status, CRM enrichment, lead generation data, account based marketing data, company funding data, GraphQL contact API, people search API, mobile phone enrichment

# Actor input Schema

## `mode` (type: `string`):

Contact lookup resolves people you already have an identifier for: a profile URL, an email address, or a name plus their employer. Company lookup resolves companies by name or domain. Advanced search is the prospecting mode: it finds companies matching your filters and returns the matching people inside each one.

## `fullNames` (type: `array`):

Full names, one per line. In contact lookup each name is paired with each company below, so ten names and one company is ten lookups. In advanced search the names are used as a contact filter instead.

## `companies` (type: `array`):

Company names, one per line. In contact lookup they are the employers to pair names with. In company lookup they are the companies to resolve. In advanced search they filter which companies are returned.

## `domains` (type: `array`):

Company domains, one per line, used the same way as the company names above. A domain is the more reliable identifier of the two when a company name is generic or shared. A pasted URL is reduced to the bare hostname.

## `profileUrls` (type: `array`):

Public professional profile URLs to resolve, one per line. The most precise identifier available, since it names exactly one person. A bare handle is expanded to a full URL and tracking parameters are stripped. Contact lookup only.

## `emails` (type: `array`):

Work email addresses to resolve back to a person, one per line. Useful for filling in who is behind an address already sitting in your CRM. Contact lookup only.

## `profileFilters` (type: `array`):

Only return people carrying these kinds of contact information. Requiring a verified work email is the difference between a list you can send to today and one that needs a verification pass first. Contact lookup only.

## `requireWorkContactInfo` (type: `boolean`):

Only return people the provider holds work contact information for at all. A blunter version of the filter above, and a quick way to keep a prospecting list free of records you cannot act on. Contact lookup only.

## `premiumFields` (type: `array`):

Ask for fields that are charged separately on your provider plan. Mobile phone numbers are the one the provider offers here. Leave empty unless your plan includes them, since requesting them consumes premium credits. Contact lookup only.

## `jobTitles` (type: `array`):

Job titles to match on the people returned, one per line. Advanced search only.

## `seniorities` (type: `array`):

Seniority levels to match on the people returned. Advanced search only.

## `roles` (type: `array`):

Functional roles to match on the people returned, one per line, for when titles vary too much between companies to filter on directly. Advanced search only.

## `industries` (type: `array`):

Industries the company should be in, one per line. Advanced search only.

## `countries` (type: `array`):

Countries the company should be in, one per line. Advanced search only.

## `states` (type: `array`):

States or regions the company should be in, one per line. Advanced search only.

## `technologies` (type: `array`):

Technologies the company runs, one per line. This is the technographic filter: it finds companies by what is in their stack rather than by what they say they do, which is how you build a list of accounts already using something you integrate with or replace. Advanced search only.

## `technologyCategories` (type: `array`):

Categories of technology the company runs, one per line, for when you care about the category rather than the specific product. Advanced search only.

## `companyDescriptions` (type: `array`):

Keywords matched against the company description, one per line, for segments the structured filters do not express. Advanced search only.

## `peoplePerCompany` (type: `integer`):

How many matching people to return inside each company. Keep it small when you want breadth across many accounts and larger when you want to map one organisation. Advanced search only.

## `sortCompaniesBy` (type: `string`):

How to order the companies returned by the advanced search. A stable ordering matters when you page through a large result set across several runs. Advanced search only.

## `pageSize` (type: `integer`):

How many results to ask for in one request. The actor pages through until the results run out, so this changes the request count rather than the total returned.

## `requestsPerMinute` (type: `integer`):

Pace the run so it stays under whatever rate your plan allows. Lower this if the provider starts returning rate limit responses.

## `skipNotFound` (type: `boolean`):

Leave inputs the provider had nothing for out of the dataset. Off by default, because keeping the misses is what lets you see which inputs resolved and which did not. Misses are never charged for either way.

## `maxResults` (type: `integer`):

Stop after this many rows. This is the cap on both spend and run time.

## `apiKey` (type: `string`):

Your own secret API key for the B2B contact data API, sent in an authorization header rather than a URL parameter, so it never appears in a log line or a redirect. Use the secret key from your account, not the public one. Required for every lookup. Stored as a secret.

## Actor input object example

```json
{
  "mode": "peopleSearch",
  "companies": [
    "Stripe"
  ],
  "profileFilters": [],
  "requireWorkContactInfo": false,
  "premiumFields": [],
  "seniorities": [],
  "peoplePerCompany": 5,
  "sortCompaniesBy": "NameAsc",
  "pageSize": 50,
  "requestsPerMinute": 120,
  "skipNotFound": false,
  "maxResults": 100
}
```

# Actor output Schema

## `results` (type: `string`):

B2B contacts with their work emails and phone numbers, and company records, one row each.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "Stripe"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/b2b-contact-data-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "companies": ["Stripe"] }

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/b2b-contact-data-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "Stripe"
  ]
}' |
apify call nabeelbaghoor/b2b-contact-data-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/b2b-contact-data-api"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/CmQXTp7lHMzU4F6Jt/builds/FkW5lSuS6BQnlvZj6/openapi.json
