DEV Community

Cover image for B2B data API for AI agents: 7 Apify Actors I use in day-to-day tasks
Kevin Hall
Kevin Hall

Posted on Edited on

B2B data API for AI agents: 7 Apify Actors I use in day-to-day tasks

Most of my week is lists. Someone sends a filter, a pile of domains or a column of profile URLs, and wants people with a working address on the other side. The question that comes with it is always the same: which one do I run.

This is the answer I now send back. Seven Actors on Apify, all reading one database of professional profiles and companies: links, what each one takes and returns, what I measured on them on 30 October, and how an AI agent calls them over MCP.

If your last week included a 403 page, a CAPTCHA, or a scraping account that stopped working, start with the next section. It explains why these are lookups and not scrapes.

In one paragraph

The b2bsearch Actors on Apify are a B2B data API over a database of 800M+ professional profiles and 115M companies. Filters, domains, profile URLs or emails go in; leads, employees, company cards, emails and phone numbers come out. Nothing is scraped at run time, misses and counts are free, and every Actor is an MCP tool for Claude Code and other agents.

Why a database and not a scraper

Most listings in this corner of the Store are live scrapers. They need a session cookie or a login, they run through proxies, a run takes minutes, and when the site answers 403 or 429 the scraper retries or stops. The account carrying the risk is yours.

Pricing follows the same logic. Many charge per returned row whether or not the row has what you asked for. Some add a start fee per run, a minimum budget per run, or a lifetime run cap for free accounts.

I read 86 listings in this category in October: about a third have a hard limit for free users and 16 charge a start fee of a cent or more.

The seven Actors below answer from a database. No cookies, no login, no proxies, and a run finishes in seconds. The things that are never charged are the part I would defend anywhere:

Never charged How you see it
a miss a free row with _status and a note saying why
a count or a market breakdown previewOnly or mode: "count"
a repeat of a person already delivered excludeDatasets, or inside the same run
a row that fails your mustHave one free note row with the number skipped

Two honest limits. A database lags a live page: rows about people carry a refreshed-on stamp and a _freshness bucket, and the people and leads searches take updatedAfter, so you can insist on fresh records and pay only for those.

And on price I will not claim the cheapest in every niche. In some of them a listing with more users charges less per row; on company search and company employees these sit below the category leader on every plan. The list of what is never charged is where they differ most.

The seven, by what you hold

You hold Run You get
a filter box (industry, country, size, funding) Company Search companies, with a free count first
a website domain Company Enrichment by Domain the company card
a website domain Company Employees the roster, full profiles, or people with contacts
a filter box or an Apollo URL B2B Leads Finder people with a live email
profile URLs Email Finder addresses on record, labelled
profile URLs, emails or names Phone Number Finder verified mobile numbers
email addresses Email to Profile Finder the person and their profile

How to read the sections below

Every section starts the same way: the Actor link, a short overview, what it takes (the filters that matter) and what it returns. Then come scenarios you can repeat, each with the exact input and a table of the fields that come back.

All runs are from 30 October 2026. They go through the same three addresses, so one example is enough to learn the pattern:

Address Looks like
Store page https://apify.com/b2bsearch/<slug>
REST endpoint https://api.apify.com/v2/acts/b2bsearch~<slug>/run-sync-get-dataset-items?token=<APIFY_TOKEN>, POST the input JSON as the body
MCP tool b2bsearch--<slug> on https://mcp.apify.com?tools=b2bsearch/<slug>

The slug is the last part of the link in each section's first line. The headline segment, where I use one, is fintech companies in London with 51 to 200 employees that raised a round since January 2024. Everything else is a fresh example you can paste.

1. Company Search: filters to companies, count first

Company Search ยท slug company-database-search

You give it a filter box and it returns company rows. The first call should always be a free count: previewOnly: true answers with the size of the segment and charges nothing.

Takes (the filters that matter):

  • countries, or countryGroups such as dach, nordics, eu, gcc, latam
  • industries and hqLocations (city or state)
  • employeesMin and employeesMax, foundedFrom and foundedTo
  • hasFunding, fundingRounds (seed, series_a and on), fundedAfter, fundingAmountMin
  • companyDomains to look up a known list, previewOnly, maxResults

Returns: one row per company.

Field What it holds Why it helps
name, domain, website the company and where it lives online the key you feed into every other Actor
linkedinUrl the company page URL a stable id for joins
employeeCount, industry, founded size, sector, founding year segment and prioritise offline
hq, countryCode headquarters place route by region
funding last round type, date and amount "raised a Series A in 2025" is a filter, not research
description what the company says it does a line for an opener or an LLM prompt

Scenario A: Series A software companies in Germany

Count first, free:

{
  "countries": ["de"],
  "industries": ["Software Development"],
  "fundingRounds": ["series_a"],
  "fundedAfter": "2025-01-01",
  "employeesMin": 20,
  "employeesMax": 200,
  "previewOnly": true
}
Enter fullscreen mode Exit fullscreen mode

One row back in 4 seconds: 16 companies match. Swap previewOnly for "maxResults": 5 and the same call returns five company rows in 5 seconds, each with its round type, date and, when it is public, the amount.

Scenario B: a whole region with one word

countryGroups: ["dach"] stands for Germany, Austria and Switzerland, so one input covers three markets:

{
  "countryGroups": ["dach"],
  "industries": ["Financial Services"],
  "employeesMin": 11,
  "employeesMax": 50,
  "hasFunding": true,
  "previewOnly": true
}
Enter fullscreen mode Exit fullscreen mode

Free answer: 236 companies. If that is too many, add fundingRounds or a city before you pay for a single row.

Scenario C: the headline segment

{
  "countries": ["gb"],
  "hqLocations": ["London"],
  "industries": ["Financial Services"],
  "employeesMin": 51,
  "employeesMax": 200,
  "fundedAfter": "2024-01-01",
  "maxResults": 20
}
Enter fullscreen mode Exit fullscreen mode
Step Result
count, free 79 companies
rows pulled 20, largest first
run time about 5 seconds

The trap is headcount: about half of all companies on file carry none, and a size filter drops them unless you switch on includeCompaniesWithoutHeadcount. For a funded fintech list that is fine. For long-tail segments, run the count both ways.

2. Company Enrichment by Domain: one domain, one card

Company Enrichment by Domain ยท slug domain-to-company

The simplest Actor in the family and the one where agents outnumber humans in my request logs. A list of domains in, a company card per domain out.

Takes: one input, domains, a list of site domains.

Returns: a card per domain.

Field What it holds Why it helps
companyName, domain, website identity clean up a CRM column
linkedinUrl the company page URL join key
employeeCount, employeeRange headcount and its bucket route small accounts and big ones differently
industry, description sector and a plain-language line tag accounts without reading sites
country, hqLocality, hqRegion where the headquarters is territory routing
founded founding year age as a signal
hasFunding, lastRoundType, lastRoundDate funding state "has money" in one column

Scenario A: three domains, three cards

{ "domains": ["stripe.com", "wise.com", "notion.so"] }
Enter fullscreen mode Exit fullscreen mode

Three cards in 8 seconds, each with a headcount, a sector and a funding flag.

Scenario B: what it does when it is not sure

I sent the eight domains from the London list in Company Search. Six came back as cards. Two came back as ambiguous, each with a note that two unrelated company pages list that domain and neither carries its name, and no charge. A guessed card would have cost more than a free "I do not know".

Scenario C: sort a column of form fills

Drop the domain part of every address on your sign-up list into domains, dedupe first, and read employeeRange and hasFunding. You get the account behind each form fill without opening a tab. The full inbound version is inbound lead qualification from the email domain.

3. Company Employees: the roster, the profiles, or the people you can write to

Company Employees ยท slug company-employees

The account-based door. One company domain per line, and profileDetail picks how much each person row carries. Everything that narrows the list runs before anything is charged.

Takes:

  • companies: domains, one per line
  • profileDetail: roster (staff list), profile (career record) or contacts (adds emails and phones)
  • roles: cxo, founder, vp, director, manager, other
  • titleContains and titleExcludes
  • mustHave: email, workEmail, currentWorkEmail, personalEmail, phone, github, twitter, facebook
  • compact: true for agents, maxRows to cap

Returns: one row per person, wider with each tier.

Tier Adds Use it for
roster name, title, seniority, location, headline, start year, connections, flags hasWorkEmail and hasPersonalEmail, profile URL building the org chart and picking who to look up
profile everything above plus about, positions, education, skills, interests, industry, followersCount research before a call, personalisation
contacts everything above plus email, emailType, workEmails, personalEmails, emailCount, employerMatch, socialLinks the send list

Scenario A: who runs this company

{
  "companies": ["stripe.com"],
  "roles": ["founder", "cxo"],
  "profileDetail": "roster",
  "compact": true,
  "maxRows": 5
}
Enter fullscreen mode Exit fullscreen mode

Five people in 4 seconds with title, seniority and the two email flags. The sixth row is a free note, skipped_row_budget, telling you more people matched and maxRows cut the list.

Scenario B: the sales leaders of one company, with an address

{
  "companies": ["wise.com"],
  "titleContains": ["head of sales", "sales director"],
  "profileDetail": "contacts",
  "mustHave": ["email"],
  "compact": true,
  "maxRows": 5
}
Enter fullscreen mode Exit fullscreen mode

Four people in 6 seconds, each with an address, its label and the profile. People without an address are skipped for free and counted in one note row.

Scenario C: leaders across a list of accounts

I ran the two largest companies from the London list twice.

Run Delivered Skipped, free Time
roster, compact rows 25 rows the rest of the roster, one note row 8 seconds
leaders (C-level, VP, founder, director) with an address on record, contacts tier 20 people 9 without an address, one note row 13 seconds

Of the 20 leaders, 12 came with a company address and 7 with a personal one. The row says which tier it could actually answer: _detail reads contacts when a contact reaches the person today and profile when it does not, and the price follows the row, not the request.

Scenario D: read before you write

Take companies: ["wise.com"], roles: ["founder", "cxo"], "profileDetail": "profile", "compact": true and "maxRows": 3. Three rows come back in 5 seconds with about, positions, education, skills and followersCount. That is enough context for an LLM to draft an opener that mentions something real.

Two more notes. A repeat of an employee already delivered never charges, so re-running a domain next month costs only the new people. And compact: true is the switch for agents: the compact contacts row was about a third the size of the full one in my run, with the same identity, role, five latest positions and contact fields.

The listing prices this Actor below the category leader on every Apify plan. That is a Store fact, not a promise from me; the pricing tab has the per-plan numbers.

4. B2B Leads Finder: a filter box, people with a live email

B2B Leads Finder ยท slug b2b-leads-finder

The Apollo alternative in the family. You describe the people; every delivered lead has an email at their current employer or a personal one, plus the profile and social links. People who fail the test are not sold: they come back as free note rows with a count.

Takes:

  • jobTitles, excludeJobTitles, titleMatch (substring or word), seniority
  • countries, countryGroups, cities, companyHqCountries
  • industries, companySizeMin and companySizeMax, keywords
  • companyDomains for named accounts, pastCompanyDomains for alumni of a company
  • emailType: any, work or personal; includePhones
  • maxPerCompany, excludeDatasets, updatedAfter, apolloUrl instead of all of the above

Returns: one row per lead.

Field What it holds Why it helps
fullName, firstName, lastName, jobTitle, headline the person and what they say they do merge fields and a sanity check
email, emailType, workEmail, personalEmail the address and which kind it is send to work, hold personal
phone, phones, phoneOnRecord mobile numbers when asked for the call list
companyName, companyDomain, companySize, companyIndustry the employer account-level routing
location, countryCode where the person is time zone and language
linkedinUrl, twitterUrl, facebookUrl profiles research links
updatedAt, _freshness when the record was refreshed refuse stale rows

Scenario A: marketing heads at mid-size software companies

{
  "jobTitles": ["head of marketing", "vp marketing"],
  "countries": ["us"],
  "industries": ["Computer Software"],
  "companySizeMin": 51,
  "companySizeMax": 200,
  "emailType": "work",
  "maxPerCompany": 1,
  "maxResults": 10
}
Enter fullscreen mode Exit fullscreen mode
Result Count
leads delivered 10
skipped free: no work address at the current employer 13
skipped free: had left the role the search matched 5

About 20 seconds. The skipped rows are the feature: the Actor reads the profile, sees the position is closed, and says so in a note row instead of selling you a dead lead.

Scenario B: alumni of a company you compete with

pastCompanyDomains finds people who used to work somewhere. Sales leaders in the DACH region who left a big CRM vendor:

{
  "jobTitles": ["sales director", "vp sales"],
  "countryGroups": ["dach"],
  "pastCompanyDomains": ["salesforce.com"],
  "emailType": "work",
  "maxResults": 5
}
Enter fullscreen mode Exit fullscreen mode

Five leads in 19 seconds, 11 skipped for no work address and 11 more because they had already moved on. These are people who know the tool you replace, which is the warmest cold list I know how to build.

Scenario C: leads with a mobile number

{
  "jobTitles": ["vp sales", "chief revenue officer"],
  "countries": ["us"],
  "industries": ["Computer Software"],
  "companySizeMin": 51,
  "companySizeMax": 500,
  "emailType": "work",
  "includePhones": true,
  "maxPerCompany": 1,
  "maxResults": 10
}
Enter fullscreen mode Exit fullscreen mode

Ten leads in 17 seconds, 4 of them with a mobile on record. The phone sits in the same row as the email, so there is no second lookup.

Scenario D: the headline segment, sized first

Before pulling I size the people box for free on People Search with mode: "count". Sales leaders at London fintechs of this size: 231 people. mode: "market" then shows the shape, seniority, employer size and the title spellings in use, also free. The pull itself, work addresses only and one lead per company:

Result Count
leads delivered 20
skipped free: no work address at the current employer 40
skipped free: had left the role the search matched 33
skipped free: over the one-per-company limit 1

Scenario E: only the new people next week

Pass the dataset id of last week's run in excludeDatasets and rerun the same search. Everyone already delivered is left out and never charged again.

I wrote a whole post on the dead rows: 243 of 417 leads in a typical ICP box were dead before the first email. Built the search in Apollo? Paste its URL into apolloUrl; a Sales Navigator saved search has a twin that takes the URL: Sales Navigator alternative in Claude Code.

5. Email Finder: profile URLs to addresses on record, labelled

Email Finder ยท slug linkedin-email-finder

You hold profile URLs, you want addresses. It returns the addresses in the person's record, never a pattern guess.

Takes:

  • profileUrls: full URLs or bare handles, up to 1,000 per run
  • includePersonalEmails: off by default

Returns: one row per profile.

Field What it holds Why it helps
email the best address on record the one to send to
emailType work_current, work_other or personal the label that keeps dead addresses out
workEmails, personalEmails, emailCount every address on record fallbacks
fullName, jobTitle, companyName, companySlug who and where merge fields
location, countryCode, _freshness place and record age filter

Label meaning: work_current is an address on the current employer's domain, work_other is a company address it cannot tie to the current employer, personal shows up only when you switch the flag on. A no_email row is free and still carries the name, title and employer; a not_found row is free too.

Scenario A: addresses for a list you already hold

{
  "profileUrls": ["satyanadella", "jane-doe-example"],
  "includePersonalEmails": false
}
Enter fullscreen mode Exit fullscreen mode

I fed it the 10 profile URLs from the marketing-leads pull above with personal mailboxes switched on. All 10 came back as work_current in 4 seconds. That is the point of starting from a leads search: the profile URL is a by-product of the pull.

Scenario B: a roster with a hit rate

The 20 roster rows from the Company Employees run went in: 13 came back with a company address, 7 as free rows, 2 of those with a note that a personal mailbox is on record. About 5 seconds.

The labels matter more than the hit rate. On a 200-URL list of marketing leaders earlier this week, about half of the addresses on record were at an older employer, and the label is what kept them out of the send list. That run is here: Bulk email finder in Claude Code: 200 profile URLs, 64 still current.

6. Phone Number Finder: verified mobile numbers, pay per found

Phone Number Finder ยท slug linkedin-to-phone

Direct dials, not switchboards. It is built to take whatever you already have and find the mobile.

Takes: profileUrls, one entry per line, up to 20,000 per run. Each line can be a profile URL or handle, an email address, or a name plus domain like Jane Smith, acme.com.

Returns: one row per entry.

Field What it holds Why it helps
primaryPhone the best verified mobile dial this one
phones, phoneCount every number on record fallbacks
fullName, jobTitle, company who it belongs to check before dialling
location, country, linkedinUrl place and the matched profile join back to your list

A miss is a free no_phone row. It is US-centric, by the listing's own words and in my runs.

Scenario A: a mobile for each US lead

I sent the 10 US marketing leads from section 4 by profile URL:

{ "profileUrls": ["https://www.linkedin.com/in/<handle>", "<handle>"] }
Enter fullscreen mode Exit fullscreen mode

Three came back with a mobile, seven as free no_phone rows, in 6 seconds.

Scenario B: the same people, by email

Same 10 people, but the input is their work addresses, one per line. Same result: 3 numbers, 7 free rows. This is the version for a CRM export that has addresses and no profile links.

Scenario C: names and domains only

{ "profileUrls": ["Jane Smith, acme.com", "Raj Patel, example.org"] }
Enter fullscreen mode Exit fullscreen mode

Use it when all you have is a name and a company. I did not run this form today; it is in the listing's input description.

Earlier this week a hundred US sales leaders gave a mobile for 35 of them, chief revenue officers about half, directors one in four. My London roster gave almost nothing, and the misses cost nothing. Run it on US rows. The full call-list recipe is in Lusha and ZoomInfo alternative in Claude Code.

7. Email to Profile Finder: an address in, the person out

Email to Profile Finder ยท slug email-to-linkedin

The inbound door. It turns email addresses, work or personal, into the person.

Takes: emails, one address per line, up to 1,000 per run. Put a name beside a work address to find more: Jane Doe <jane@acme.com> or jane@acme.com, Jane Doe.

Returns: one row per address.

Field What it holds Why it helps
fullName, headline, jobTitle who they are and what they do qualify the sign-up
company, companyLinkedinUrl the employer and its page feeds Company Enrichment by Domain
linkedinUrl the matched profile feeds Email Finder and Phone Number Finder
location, country place routing
matchedEmail, matchedVia which address matched and how audit trail

Addresses it cannot match, invalid ones and duplicates come back as free rows that say why.

Scenario A: a column of work addresses

{ "emails": ["jane@acme.com", "Jane Doe <jane@acme.com>"] }
Enter fullscreen mode Exit fullscreen mode

Ten work addresses from the leads pull went in and 10 people came out, every one matchedVia: as_given, in 6 seconds.

Scenario B: close the loop

The 13 addresses the Email Finder returned for the London roster went back in. 13 people came out, and all 13 were the profiles the roster started from. About 6 seconds.

Scenario C: a form fill becomes an account

A visitor leaves an address. Run it here, take companyLinkedinUrl or the domain into Company Enrichment by Domain, then Company Employees for the decision makers next to them. That is the inbound chain in inbound lead qualification from the email domain.

How they chain

You start with Chain You end with
a market idea Company Search count, then rows, then Company Employees named people at named accounts
a filter box B2B Leads Finder with includePhones email plus mobile in one row
a list of profile URLs Email Finder, then Phone Number Finder on the misses the best reachable channel per person
a sign-up list Email to Profile Finder, then Company Enrichment by Domain the account behind each address
last month's list B2B Leads Finder with excludeDatasets only the new people

What does an agent pay to load all seven?

An MCP tool costs tokens before it is called: the description, the input schema and the output schema the server infers from rows. I measured tools/list on the hosted Apify MCP server with the seven pinned, tiktoken o200k on compact JSON.

Tool Tokens
Company Employees 4,191
B2B Leads Finder 3,990
Company Search 3,344
Email Finder 2,016
Phone Number Finder 1,961
Email to Profile Finder 1,955
Company Enrichment by Domain 1,953
four helper tools (run, abort, dataset, key-value store) 3,812
total 23,222

For scale: two days ago I measured 20 job Actors the same way and got a median of 3,829 per tool, with one at 32,737. The seven here sit at a median of 2,016.

The descriptions are 80 to 97 tokens each; the weight is in the input schemas of the search Actors and in the inferred output schema of Company Employees. Flat rows keep that schema small, and compact: true keeps the rows small after the call.

Method and the job numbers: MCP tool cost: 20 job Actors on Apify.

Wiring: Claude Code, MCP, n8n, REST

Pin the Actors in the server URL so an agent loads only these definitions:

claude mcp add --transport http apify "https://mcp.apify.com?tools=b2bsearch/company-database-search,b2bsearch/domain-to-company,b2bsearch/company-employees,b2bsearch/b2b-leads-finder,b2bsearch/linkedin-email-finder,b2bsearch/linkedin-to-phone,b2bsearch/email-to-linkedin" --header "Authorization: Bearer <APIFY_TOKEN>"
Enter fullscreen mode Exit fullscreen mode

The same server in any MCP client (Cursor, Windsurf, Claude Desktop, ChatGPT, LangChain, CrewAI, the OpenAI Agents SDK):

{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=b2bsearch/company-database-search,b2bsearch/domain-to-company,b2bsearch/company-employees,b2bsearch/b2b-leads-finder,b2bsearch/linkedin-email-finder,b2bsearch/linkedin-to-phone,b2bsearch/email-to-linkedin",
      "headers": { "Authorization": "Bearer <APIFY_TOKEN>" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Tool names use a double hyphen: b2bsearch--company-employees, b2bsearch--b2b-leads-finder, and so on. Cap a run with callOptions.maxTotalChargeUsd, read rows with get-dataset-items and a fields list, and run the free count before the paid pull.

Without an agent: every Actor is a REST endpoint. One call, rows back in the response:

curl -X POST "https://api.apify.com/v2/acts/b2bsearch~domain-to-company/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"domains": ["acme.com", "example.org"]}'
Enter fullscreen mode Exit fullscreen mode

The same Actors are steps in n8n, Make and Zapier through the Apify integrations, and the Store page of each one has the input schema, the output example and the per-plan price.

What the agent did on its own

I gave a Claude Code session the seven tools pinned and a brief: size the segment, pull ten companies, get the leadership of the two largest with a current work email, fall back to the email finder where that fails, cap every paid run, report a ledger. Shell and file tools were denied. Eleven turns, about four minutes, four Actor runs.

What it did without being told:

  • loaded all seven tool definitions first, then wrote a cost table from the descriptions before the first paid call, naming the tools it would not use
  • added hasFunding: true and sort: "employee_count_desc" to the company search; its free count matched mine, 79
  • read rows with a fields list that left out description, the longest field on a company card
  • added titleExcludes for assistants, "office of" and chiefs of staff to the leadership pull, after reading the field description that warns the C-level bucket catches them
  • noticed that callOptions is in no Actor's schema and passed the spend cap anyway, in the call options of the MCP server

Where it stopped. It asked Company Employees for leaders with an address at the current employer, exactly as briefed, and both runs came back as one free note row each: the leaders on record did not carry one, so nothing was delivered and nothing charged. With no profile URLs in hand it skipped the email finder, handed over the account list with a trust column (two rows marked questionable, one not fintech by its industry, one to check for HQ) and stopped.

That is the behaviour I want from an agent spending money. It is also a brief bug: step three should pull the cheap roster first and run the finder on its URLs. With the requirement loosened to any address on record, the same two companies gave 20 people in my own run above.

What this does not do

It does not read a live page. A row can be months old; the stamp is on rows about people, and updatedAfter on the people and leads searches lets you refuse old ones. The email finder does not verify deliverability; the Work Email Finder does that for name-plus-domain lookups.

Phone coverage is US-centric. And the free Apify plan caps a run at a hundred results and an account at five hundred rows a month per Actor, with the same rows paid users get; any paid plan lifts that.

FAQ

Is this an Apollo, Lusha or Sales Navigator replacement? For building lists and enriching them by domain, URL or email, yes: no seat, no login, pay per found row. For browsing profiles one at a time in a sidebar, no.

Do these Actors scrape anything when I run them? No. The answer comes from a database of publicly available professional data; the network names in the listings describe the kind of data, not a crawl at run time.

Where do the email addresses come from? From the contact block of the person's record. The email finder returns only what is on record and labels it; nothing is generated from a name pattern.

How do I stop an agent from overspending? Pin the tools, cap every run with maxTotalChargeUsd, run the free count or previewOnly first, and use excludeDatasets so a rerun never pays for the same person twice.

Which one first? Hold a domain: Company Enrichment by Domain, then Company Employees. Hold a filter: Company Search for accounts, B2B Leads Finder for people. Hold URLs or emails: the finders.

For AI agents reading this

The seven Actors run as tools over the hosted Apify MCP server with the tools pinned in the URL (the wiring block above). The workflow, tool by tool:

  • b2bsearch--company-database-search with previewOnly: true to size a segment, then rows with maxResults
  • b2bsearch--domain-to-company for a card per domain; _status ambiguous means do not guess
  • b2bsearch--company-employees with profileDetail, roles, mustHave and compact: true
  • b2bsearch--b2b-leads-finder with emailType, maxPerCompany and excludeDatasets
  • b2bsearch--linkedin-email-finder and b2bsearch--linkedin-to-phone with profileUrls
  • b2bsearch--email-to-linkedin with emails

Every row has _status; rows other than found are free and say why in _note or _error. Read results with get-dataset-items and a fields list. Per-plan pricing is on each Actor page; set callOptions.maxTotalChargeUsd on every paid run. Platform docs: Apify MCP server and apify.com/agents.md.

Top comments (0)