Waterfall Email Enrichment API, Any Identifier avatar

Waterfall Email Enrichment API, Any Identifier

Pricing

from $3.00 / 1,000 contact matcheds

Go to Apify Store
Waterfall Email Enrichment API, Any Identifier

Waterfall Email Enrichment API, Any Identifier

Waterfall email enrichment from any identifier: LinkedIn URL, email, or name and company domain. Chains profile match, email find and verification, and stops where you choose. No login. Free plan: 100 inputs per run. Pay per result, misses free. No phone numbers.

Pricing

from $3.00 / 1,000 contact matcheds

Rating

0.0

(0)

Developer

Open Enrich

Open Enrich

Maintained by Community

Actor stats

0

Bookmarked

6

Total users

5

Monthly active users

8 days ago

Last modified

Features

Limited permissions

Share

Pay per result: $3.963/1k on the Free plan down to $2.996/1k on Gold. Free Apify plan: up to 100 per run, as many runs as your credit covers. Misses and notices are free.

Waterfall email enrichment from any identifier: give a LinkedIn URL, an email, or a name and company domain, and get back the person, a work email, and a mailbox check. The waterfall runs one step at a time and stops where you tell it to. No login, no cookies, no start fee. You pay only for the steps that deliver.

No login | LinkedIn URL, email or name + domain in | Person, work email, status and confidence out | Stop at person, email or verified | Misses are free | JSON/CSV export

Not a phone finder. This actor returns people and work emails. It does not return phone numbers. For those, use phone-number-finder.

See all actors by b2bdata


How the waterfall works

input (any identifier)
|
v
[1] person match the profile -> event: contact
| stopAt: person ends here
v
[2] email find a work email on the -> event: email-found
| company domain (skipped when you gave an email, or the profile already holds one)
| stopAt: email ends here
v
[3] verified check the mailbox -> event: email-verified
  • Give a LinkedIn URL: the person is matched, the employer's domain is looked up, a work email is found and checked.
  • Give an email: the person behind it is matched and the address is checked. The email step is skipped, you gave it.
  • Give First Last @ domain: the person is matched, the work email is found on that domain and checked.

A step that finds nothing ends that input. It is listed in MISSES with a reason and costs nothing.


Pricing and plans

Three events, each charged once per row only when that step delivered something. Prices per 1,000 (draft, set on the Pricing tab):

EventWhen it is chargedFree planGold plan
contactThe input is matched to a person and the row is delivered$3.963$2.996
email-foundA work email is found for the person and delivered$0.963$0.696
email-verifiedThe work email gets a valid or catch-all verdict$1.963$1.496

Bronze and Silver prices are on the Pricing tab. Higher Apify plans only lower the price. Empty runs, failed lookups, unreadable input lines and notices are free, and there is no start fee.

Plan-credit math. The free plan's $5 monthly credit covers about 1,260 matched contacts, or about 5,190 emails found, or about 2,540 emails verified, at the Free price.

What a row costs. stopAt: person costs one contact. stopAt: email costs contact plus email-found. stopAt: verified costs all three at most. A row where the verdict is unclear is not charged as verified.

The free plan

Free Apify accounts get up to 100 inputs looked up per run, and as many runs as their Apify credit covers. Nothing is stored on our side. When a list is longer, the first 100 are looked up and one free notice row (reason: "free_plan_limit") says how many were not looked up. They are not charged. Run again with the rest, or use a paid Apify plan for no per-run limit.

Keep a run small while you test

limit caps the inputs looked up. The default is 25, the maximum is 500, 0 means all lines up to 500. Start with 1 to 3 inputs, read the rows, then scale up. Use maxChargeUsd (advanced input) to stop a run at a spend you choose.


Quick start

1. One person, full waterfall

{ "items": ["Patrick Collison @ stripe.com"], "limit": 1 }

2. Mixed identifiers in one list, stop at the email

{
"items": [
"https://www.linkedin.com/in/patrickcollison",
"patrick@stripe.com",
"Satya Nadella, microsoft.com",
{ "first": "Sam", "last": "Altman", "domain": "openai.com" }
],
"stopAt": "email"
}

3. Match people only

{ "items": ["https://www.linkedin.com/in/patrickcollison"], "stopAt": "person" }

Inputs

KeyTypeDefaultWhat it does
itemsarrayrequiredOne person per entry: a LinkedIn URL or slug, an email, First Last @ domain or First Last, domain, or an object {first,last,domain} / {fullName,domain} / {linkedin} / {email}. Duplicates are collapsed.
stopAtstringverifiedperson, email or verified. The waterfall ends at that step.
limitinteger25Maximum inputs looked up. 0 = all lines. Maximum 500; a higher number stops the run with a message before any charge.
includeAuditbooleanfalseAdds an audit object to each row: steps that ran, upstream units used, cleaned input.
maxChargeUsdnumbernoneAdvanced. Stops new lookups once the run has charged this much.
sourceTagstringnoneAdvanced. Up to 64 characters, copied into each row and RUN_SUMMARY.

Any other field stops the run before a lookup with remove unsupported fields: .... Nothing is charged. A name needs both first and last name; a single name is an invalid line.


Output

One row per input that reached at least the step you asked for. Rows keep input order. Empty values are left out of the row.

KeyTypeMeaning, and when it is missing
reachedstringFurthest step with a result: person, email or verified
fullName, firstName, lastNamestringAs matched. Missing when only an email was checked
jobTitle, company, headlinestringCurrent, when on file
location, countrystringFree-text location and ISO-2 country, when on file
profileUrl, slugstringProfessional profile, when matched
emailstringWork email, lower case. Missing at stopAt: person
emailSourcestringfound (we found it), profile (already on the person record) or provided (you gave it)
emailStatusstringvalid, catch_all or unknown. A row with an invalid email is not delivered
confidencenumber0-1, see the rule below
inputQuerystringYour input, as you gave it
scrapedAtstringISO time the row was produced
sourceTagstringYour tag, only if you set one
auditobjectOnly with includeAudit
{
"fullName": "Patrick Collison",
"jobTitle": "CEO",
"company": "Stripe",
"profileUrl": "https://www.linkedin.com/in/patrickcollison",
"email": "patrick@stripe.com",
"emailSource": "found",
"emailStatus": "valid",
"confidence": 1,
"reached": "verified",
"inputQuery": "Patrick Collison @ stripe.com",
"scrapedAt": "2026-11-02T10:00:00.000Z"
}

Illustrative row. Which fields appear depends on what is on file for the person.

Confidence rule

Base by status: valid 0.95, catch_all 0.6, unknown 0.5. Add 0.05 when the input was matched to a person. Maximum 1. A catch-all domain accepts any address, so even a good verdict there is a weaker signal.

Other records in the run

  • MISSES (key-value store): [{input, reason}] for every input without a row: not_found, no_email, invalid_email, invalid_input, no_result or Upstream HTTP <code>.
  • errors-waterfall-contact-enrichment: lookups that failed for a technical reason, so you can re-run only those.
  • RUN_SUMMARY: counts, events charged by name, stop reason, your sourceTag.
  • Notice rows (type: "notice") appear for invalid input, a free-plan list longer than 100, or a reached spend cap. Notices are never charged.

What is NOT returned

  • No phone numbers
  • No personal email addresses
  • No several alternative addresses per person

Reliable results

Our data promise. We work to keep every contact current, and we stand behind it. If a record is outdated, an email bounces or a person has moved on, open the Issues tab with your run link. We review every report and sort it out with you, case by case.

  • Misses are free and visible. Every input without a row is in MISSES with a reason and is never charged.
  • You pay per step delivered. A step that does not deliver is not charged.
  • Duplicates are collapsed. The same person written two ways is looked up once.
  • Each row is saved as it is delivered. A run that stops keeps what it already produced.
  • Bounded pace. Lookups run at 60 requests per minute. Each row needs one to three requests, so 500 rows take about 20 minutes.
  • Typos fail early. An unsupported input field or a limit above 500 ends the run before any charge.
  • Check before you send. emailStatus and confidence are signals, not a guarantee.

Use with AI agents (MCP)

This actor runs through the Apify MCP server. Prompt to copy:

"Use b2bdata/waterfall-contact-enrichment with items=["Patrick Collison @ stripe.com"], stopAt="verified" and limit=1. Return email, emailStatus, confidence and reached."

When to use it. You hold a LinkedIn URL, an email, or a name and a company domain, and need the person and a checked work email in one call. When not to. You need phone numbers (use phone-number-finder), or you hold only a company (use a decision-maker actor first). Input contract. items array of strings or objects; stopAt person, email or verified; limit 1-500 (0 = all). Output contract. One row per resolved input with reached, email, emailStatus, confidence. Output is deterministic and schema-stable, rows keep input order. Inputs that resolve to nothing are absent from the dataset and listed in MISSES. Smoke test. limit: 1 on a well-known person returns one row. Error cases. No valid items means no line was a LinkedIn URL, an email, or a full name with a domain. remove unsupported fields means a misspelled input key. Both end the run SUCCEEDED with one free invalid-input notice row and nothing charged.


Integrations

  1. API. Fetch rows from the run's default dataset: GET /v2/datasets/{datasetId}/items?format=csv.
  2. Webhook on run success to push rows to your own endpoint.
  3. n8n, Make, Zapier. Use the native Apify nodes: run the actor, then read the dataset.
  4. Google Sheets, Airtable, HubSpot, Salesforce, Clay. Map email to the email field and emailStatus to a status column.

  • b2bdata/email-finder: you have a name and a domain and only need the email. Open
  • b2bdata/contact-enrich-csv: enrich a spreadsheet and keep your own columns. Open
  • b2bdata/bulk-linkedin-profile-enrichment: you have LinkedIn URLs and need the full profile. Open
  • b2bdata/phone-number-finder: you need phone numbers from a LinkedIn URL. Open

See all actors by b2bdata


FAQ

What is waterfall email enrichment? It tries one step after another: match the person, find a work email, check the mailbox. Each step runs only if the one before delivered, and it stops at the step you choose.

Can I find a work email from a LinkedIn URL? Yes. Add the URL as an item. The person is matched, the employer's domain is looked up, and a work email is found on it. If no domain or email can be found, the input is listed in MISSES and is free.

Can I enrich a mixed list of emails, LinkedIn URLs and names? Yes. Every line is read on its own, in any of the accepted forms, and the results keep your order.

Do I need a LinkedIn account or cookies? No. It works without LinkedIn login, cookies or an account to ban.

What do I pay when nothing is found? Nothing. There is no start fee. A step is charged only when it delivers: a matched contact, a found email, a clear verdict.

Why is the status sometimes unknown? A mailbox check does not always give a clear answer. An unclear verdict is delivered as unknown and is not charged as verified.


Support

Use the Issues tab on this actor's Apify page for bugs, questions and feature requests. We answer within 48 hours on working days. Please include the run ID and the input you used.

Published on Apify by b2bdata as proprietary software. Not affiliated with, endorsed by, or sponsored by any company or person named in the examples above.