Playbooks

Lead generation with AI agents: a step-by-step playbook

A working playbook for agent-driven lead gen: find companies, enrich people, verify emails and build a qualified list from one prompt, with real per-lead costs.

Bogdan Carbune

Bogdan Carbune

9 min read

Cover illustration for a playbook on building lead lists with AI agents

An AI agent can build a qualified lead list end to end: find the companies that match your ICP, find the right people inside them, pull the full record on each one, dig out a contact address, and hand back a sheet with a personalization line per row. The playbook below does that for about $0.18 a lead in tool costs, in one pass, from one prompt. The two parts still worth a human are the ICP at the front and the copy at the end.

What do you need before you start?

Two things. An agent that can call tools over MCP, and an ICP written tightly enough to turn into filters. Everything between those two is a tool call, and every tool call in this playbook costs less than a nickel.

The agent half is the easy half. A model on its own cannot see a job board or a company website, so it needs tools, and MCP is the standard way to hand it some. If that part is new, the explainer on MCP covers it in about five minutes. Once your agent is connected it can list what is available, read the price of a call before making it, and run the stages below without you approving each one.

The ICP half is the half people skip. "Mid-market SaaS companies that care about revenue efficiency" is a positioning statement, not a filter. "UK B2B software companies with 50 to 500 people that posted a revenue operations role in the last 30 days, where the buyer is a VP or head of sales" is a filter: every clause in it maps to a parameter on a real call.

If a clause in your ICP does not map to a filter, or to a check your agent can run on a returned row, it is not a filter. It is a hope.
The one rule before you spend anything
PipelineOne pass, five stages
A five stage lead generation pipeline. LinkedIn job search finds 130 companies, LinkedIn company employees turns those into named people, LinkedIn profile enriches the 140 that survive a manual read, the contact and email finder runs on 118 company domains, and the agent compiles 100 rows at no extra cost.1linkedin.jobsjob postings that match a role and a market$0.003 per postingthe cheapest company finder in the catalog130 companies, deduped by hiring employer2linkedin.company_employeesnamed people at those companies, with titles$0.024 per profilefiltered at the call, not after it140 profile urls that pass your own read3linkedin.profilethe full record: history, tenure, sometimes contact$0.03 per profileruns on the shortlist only118 domains, one per surviving company4email.finderaddresses and phones published on each domain$0.06 per domaindomains with nothing found cost nothing100 rows with a name, a title and a way in5your agentjoins, dedupes, scores, writes the sheetno call, no chargethe only stage that is free
Each stage hands the next one a key: a company, a profile url, a domain. Nothing gets enriched before it has survived a filter.

Step 1: find the companies

Start from a signal, not from a directory. A company that just posted a revenue operations role is telling you it has a revenue operations problem, and LinkedIn job search reads that signal at $0.003 per posting. Two hundred and fifty postings costs $0.75 and dedupes down to roughly 130 employers, because one company usually posts several roles at once.

stage 1, find companies with intent
linkedin.jobs
{
  "jobTitles":  ["revenue operations", "sales operations"],
  "locations":  ["United Kingdom"],
  "postedLimit": "month",
  "maxItems": 250
}

Pick the discovery call that matches how your buyers exist in the world. Hiring signals suit software and services. For anything with a street address, dentists, gyms, garages, Google Maps placesreturns name, website, phone and rating for $0.009 a place, which is the fastest way to turn a city plus a category into a company list. For everything else there is plain web search at $0.0075 per results page, which is what you want when the list you need already exists as somebody's directory page.

Whatever you use, the output of stage one is not leads. It is a company list with a reason attached to each row, and the reason is the thing you will still be using in the first line of the email three steps later.

Step 2: find the people inside them

LinkedIn company employees turns a list of companies into a list of named humans with titles, at $0.024 per profile. Filter at the call rather than after it: job titles, seniority, location and headcount are all parameters, and every person you exclude in the request is a person you do not pay for.

stage 2, find the buyer inside each company
linkedin.company_employees
{
  "companies": ["acme-analytics", "northwind-labs", "..."],
  "jobTitles": ["vp sales", "head of sales", "sales director"],
  "locations": ["United Kingdom"],
  "maxItemsPerCompany": 2,
  "maxItems": 260
}

The parameter that saves the most money is maxItemsPerCompany. Without it, one 4,000-person enterprise in your list will happily eat the entire run. Set it to two or three and 130 companies produce a predictable 260 to 390 people.

When you do not know the employer, search by what the person does instead. LinkedIn profile search by keyword takes a free-text role like "fractional CFO" and returns matching profiles at $0.012 each, half the price of the roster call, which makes it the right opener for talent-shaped ICPs where the employer is irrelevant.

Step 3: enrich only the people who survive the cut

Enrichment is where the price per record roughly triples, so it belongs after your filter and never before it. Read the roster, drop the mismatches, then run LinkedIn profile at $0.03 a record on what is left. In the worked example that is 140 records out of 260, which is $4.20 instead of $7.80 for a list of exactly the same quality.

stage 3, enrich the shortlist
linkedin.profile
{
  "profileUrls": [
    "https://www.linkedin.com/in/first-survivor",
    "https://www.linkedin.com/in/second-survivor"
  ]
}

The full profile gives you work history, tenure, education and, when the source resolves one, a contact email or phone. Tenure is the underrated field: somebody eleven months into a VP role is a different prospect from somebody eleven years in, and that single number will change your first line more than anything else on the record.

One honest caveat. If your stage two call already returned complete profiles, skip this stage entirely. You would be paying twice for the same data, and the whole build drops from $17.55 to $13.35.

Cost controlThe price ladder
A bar chart of unit prices, ascending. LinkedIn job search at $0.003 per posting and Google Maps places at $0.009 per place are marked run on everything. LinkedIn company employees at $0.024, LinkedIn profile at $0.03 and the contact and email finder at $0.06 are marked run only on what survived.$0.003linkedin.jobsper posting$0.009maps.placesper place$0.024linkedin.company_employeesper profile$0.03linkedin.profileper profile$0.06email.finderper domainrun these on everythingrun these only on what survived
Twenty times between the widest call and the narrowest. Order the pipeline so the dear calls only ever see records that already passed a filter.

Step 4: find the email, then verify it somewhere else

Contact and email finder takes company domains and returns the addresses and phone numbers published on those sites, at $0.06 per domain. Domains where it finds nothing return no row and cost nothing, which is why the worked example sends 118 domains and pays for 96.

stage 4, find a way in
email.finder
{
  "domains": ["acme-analytics.com", "northwind.io", "..."]
}

It is a finder, not a verifier. The addresses come back exactly as the site publishes them, with no deliverability test attached, and Goro does not sell a verification tool that would change that. Treat verification as a separate step you run in your sending stack before any volume goes out. Skipping it is how a fresh domain gets burned in an afternoon.

Expect a mix of role inboxes and personal addresses, and label them in the sheet rather than pretending they are the same thing. A message to hello@ at a 60-person company is a different play from a message to the VP directly, and your reply rates will not survive being averaged across both.

Step 5: compile the list

The last stage is the only one that is free, because it is your agent doing joins rather than calling anything. It matches people to companies, drops rows missing a name, a title or an address, dedupes by email, and writes one row per lead with the source url for every claim in it.

Add the personalization fact here, not earlier. Web page scrape pulls the cleaned text of an about or careers page for just under $0.006 a url, and one specific sentence from that page is what separates a lead from a row in a spreadsheet. The broader mechanics of pulling structured data out of sites are in web scraping for AI agents.

Ship the sheet with a kill rule attached: a row without a reason to send is not a lead, and it should be deleted rather than mailed. Ten rows you can defend beat a hundred you cannot.

What does 100 qualified leads cost?

$17.55 in tool calls, or about $0.18 a lead, for the funnel above. The expensive stages are the two narrow ones at the end, which is exactly the right place for cost to sit, because by then every record has already survived a filter.

Cost per 100 qualified leads

StageCallBilled unitsRateCost
1. Find companieslinkedin.jobs250 postings$0.003 each$0.75
2. Find peoplelinkedin.company_employees260 profiles$0.024 each$6.24
3. Enrich the shortlistlinkedin.profile140 profiles$0.03 each$4.20
4. Find emailsemail.finder96 of 118 domains$0.06 each$5.76
5. Personalization factweb.scrape100 pages$0.006 each$0.60
Totalfive calls846 units$0.021 average$17.55
Billed on actual usage, with a $0.002 minimum per call. Nothing is charged for calls you do not make.

Two numbers move that total. Skipping stage three when your roster call already returns full records takes it to $13.35, or $0.13 a lead. Loosening maxItemsPerCompany from two to four takes stage two from $6.24 to $12.48 and gives you a longer list of worse-fitting people, which is usually a trade in the wrong direction.

The reason this arithmetic is even possible is that every call is priced on its own. There is no seat and no annual contract to amortize across runs, just a plan that includes credit every month, spent one call at a time. Build a list in March and a leaner one in April, and the included credit stretches accordingly, since only the calls you make draw it down. The full catalog with prices is on the tools pages, and the plans are on the pricing page.

The prompt, in full

Here is the whole playbook as one message. Paste it into an agent with the catalog connected, change the three ICP lines, and it will run the five stages in order and hand back the sheet.

paste into your agent
Build me a lead list. Do not contact anyone. Just produce the sheet.

ICP
- UK B2B software companies, 50 to 500 people
- posted a revenue operations or sales operations role in the last 30 days
- the person I want is a VP of sales, head of sales, or sales director

Plan
1. linkedin.jobs: jobTitles ["revenue operations", "sales operations"],
   locations ["United Kingdom"], postedLimit "month", maxItems 250.
   Dedupe by hiring company. Drop recruiters and staffing agencies.
2. linkedin.company_employees over the companies from step 1:
   jobTitles ["vp sales", "head of sales", "sales director"],
   locations ["United Kingdom"], maxItemsPerCompany 2, maxItems 260.
3. Read every title yourself. Drop anyone whose title does not match the
   three above, anyone who has left, and any company that is not B2B
   software. Report the count you dropped and why.
4. linkedin.profile on the survivors only, never on the full roster.
5. email.finder on one domain per surviving company.
6. web.scrape the /about or /careers page of each surviving company and
   pull one specific fact I could reference in a first line.
7. Write a CSV: company, domain, hiring signal, person, title,
   linkedin url, email, email type (personal or role inbox),
   personalization fact, source url for that fact.

Rules
- Check the price of a call before you run it. Stop and ask me if the
  whole run will cost more than $30.
- Never guess an email address. If nothing is found for a domain, leave
  the cell empty and keep the row.
- Every personalization fact needs the url you read it on.
- Report how many rows you dropped at each step.

The rules block at the bottom is doing more work than it looks. A price ceiling stops a runaway loop, banning guessed emails stops the model inventing firstname.lastname@ patterns it cannot support, and demanding a source url per fact makes hallucinated personalization visible the moment you spot-check five rows.

Where this goes wrong

Four failure modes account for most bad agent-built lists, and three of them are cheap to design out before the first run.

Stale data

Every profile record describes the day it was scraped, not today. People change jobs, titles get renamed, companies get acquired, and a list you built in January and mailed in June will contain a slice of people who are not there any more. Rebuild rather than reuse: at $17.55 a hundred leads, a fresh pull is cheaper than one sequence bouncing hard enough to hurt your sending domain.

Over-filtering

Six filters joined with AND will take a pool of 4,000 people down to eleven, and the eleven will not be better, just fewer. Relax one filter at a time and watch what comes back. A useful floor: if any stage returns less than 40% of what you asked for, the filter is wrong, not the market.

Personalization that is not personal

A first line that says "I saw you are hiring" is a merge field wearing a costume. The signal you found in stage one is a real fact about a real company, so use the specific version of it: the role, the team it sits in, the third product on their pricing page. If the agent cannot produce a source url for the fact, it invented it.

Compliance

This is not legal advice, and the honest summary is short. A named person's work email is still personal data under GDPR, so a European B2B list needs a lawful basis, which in practice means legitimate interest plus a balancing test you could actually show someone: the message has to be relevant to that person's job, you have to say who you are and where the data came from, and opting out has to be one click and permanent. Some member states are stricter than others on unsolicited email to individuals. US rules are looser but still require a real postal address and a working unsubscribe. Platform terms of service are a separate question from data protection law, and the size of the list is the thing that decides how much any of this matters, so scale carefully and keep records of where each row came from.

Common questions

Can an AI agent replace a lead database like Apollo or ZoomInfo?

For building a list against a specific ICP, largely yes: an agent pulls the companies, people and contact details on demand and hands back a sheet. What you give up is a maintained database with deliverability scores and intent data already attached. What you get back is data pulled the day you use it, a per-lead cost around $0.18, and no seat fees in the months you are not prospecting.

How accurate are the emails an agent finds?

Accuracy varies by how much a company publishes. The finder returns addresses exactly as they appear on the site, tests none of them for deliverability, and returns nothing at all for domains that publish nothing. Expect a healthy share of role inboxes rather than personal addresses, label the two differently in your sheet, and run a verification pass in your sending stack before any volume goes out.

Is lead generation with AI agents legal under GDPR?

It can be, and this is not legal advice. B2B contact data about a named person is personal data, so you need a lawful basis, and legitimate interest is the usual one. That means the message must be genuinely relevant to that person's role, you must identify yourself and say where the data came from, and unsubscribing must be immediate and honoured. Rules on unsolicited email to individuals vary by member state, so check the ones you are actually mailing into.

How long does one run take?

The search stages return in seconds to a couple of minutes. The profile enrichment stage is the slow one, because it scales with the length of your shortlist rather than with the size of your query. A 100-lead build like the one above is a coffee, not an afternoon, and the agent can report progress stage by stage while it works.