The fastest route is one API call that takes a LinkedIn URL and returns a checked email and the phone numbers held. Eight tools do some version of this. They differ most in what a find costs and what happens when it finds nothing.
TL;DR
- Pick a tool by cost per find. Emails run 0.2 to 3 credits and phones 5 to 10 credits across the tools below, all from vendor docs.
- The LeadOcean recipe takes about 15 minutes and spends 1 record per person: enrich with
reveal_emailreturns emails and phones. A separate phone call is 1 more. - Count your list first. The count is free, and a person we hold nothing on is a 404 that costs nothing.
Prerequisites
- A LeadOcean API key from the free plan: 1,000 records for life, no card, 5 requests a second. Export it as
$LEADOCEAN_API_KEY. curlandjq.- One LinkedIn profile URL to test with. The examples use a placeholder.
Step 1: Compare the eight tools on cost per find
Cost per find is the number that matters at volume. This table uses each vendor's own docs, checked in September 2026. Monthly list price comes first, billed-yearly figure after it.
| Tool | Email find | Phone find | Entry paid plan |
|---|---|---|---|
| LeadOcean | 1 record (enrich, email revealed) | Same record as the email; 1 record on its own | Solo $97 a month; Free is 1,000 records for life |
| Hunter | 1 credit per email found | Not covered here | Starter $49 a month, $34 billed yearly (pricing) |
| Apollo | 1 credit | 8 credits | Basic $65 per seat a month, $49 billed yearly |
| Prospeo | 1 credit | 10 credits (email included) | Starter $49 a month, $37 billed yearly (pricing) |
| FullEnrich | 1 credit work, 3 personal | 10 credits for a mobile | Pro from $29 a month for 500 credits, $26 billed yearly (pricing) |
| Lusha | 1 credit | 5 credits | Starter $49.90 a month, $37.45 billed yearly (pricing) |
| Kaspr | Unlimited B2B email on paid plans, fair use | 100 phone credits a month on Starter | Starter $65 per user a month |
| Clay | 0.5 credit in Clay's worked example | Not on Free | Launch $185 a month, $167 billed yearly (pricing) |
Three reading notes. Apollo's 8-credit phone is why its API enrichment runs 1 to 9 credits. Hunter and Prospeo charge nothing when a find returns nothing. FullEnrich charges nothing for a miss or a landline.
LeadOcean has no per-credit price. Paid plans have a fair-use pace, so the number to watch is records, not credits. A search page of 25 is 25 records.
Two things the table hides. Credits are not comparable across vendors: a Clay credit, a Lusha credit and a LeadOcean record each buy different things. And a phone find is the expensive step everywhere, so run it last, only on people whose email you kept.
Which one wins? For a developer with a list and an API, LeadOcean or Hunter. For a rep who lives in a prospecting UI, Apollo or Lusha. For spreadsheet workflows, Clay.
Step 2: Size the list before you spend a record
Count the audience first. A count is free however often you send it. In an MCP client, leadocean_count_leads does the same job. Over REST, send count=true and limit=1 as query parameters.
curl -s -G "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
--data-urlencode "count=true" \
--data-urlencode "limit=1" \
--data-urlencode "jobLevel=VP" \
--data-urlencode "jobFunction=Sales & Business Development" \
--data-urlencode "country=CA" \
| jq '.meta'meta.total is capped at 100,000, and data comes back empty with meta.countOnly true. Enum values are exact strings, so check them with leadocean_list_enum_values before you filter.
Step 3: Enrich one person with the email revealed
Send exactly one identifier to POST /v1/people/enrich: linkedin_url, email, phone or person_id. Set reveal_email to true to get the address. There is no name plus domain lookup, so search by domain first when you only have a company.
curl -s -X POST https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"linkedin_url": "https://www.linkedin.com/in/jane-doe", "reveal_email": true}'This costs 1 record. If nobody matches, you get a 404 and spend nothing. Reading the email status before you send matters, and the next step shows how.
Step 4: Keep only an email you can send to
Filter contact_emails to the work type and a safe status. verified and catch_all_valid are the ones to send to. Skip work_other, which is an address at a former employer.
curl -s -X POST https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"linkedin_url": "https://www.linkedin.com/in/jane-doe", "reveal_email": true}' \
| jq '[.data.contact_data.contact_emails[]
| select(.type == "work"
and (.status == "verified" or .status == "catch_all_valid"))]
| first'Step 5: Add the phone number
The enrich call in Step 3 already returns contact_phones when reveal_email is true, at no extra record. Use GET /v2/people/phone only when you want numbers alone. It takes linkedin_url, or the person_id from a search row, and costs 1 record per call, including a call that finds nothing.
curl -s -G "https://api.leadocean.io/v2/people/phone" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
--data-urlencode "linkedin_url=https://www.linkedin.com/in/jane-doe"The same step works from an AI client. The leadocean_find_phone MCP tool is the equivalent call and also costs 1 record. The MCP server lives at https://api.leadocean.io/mcp and signs in with OAuth, so no key is pasted.
Step 6: Run it on a list
For one person, one call is fine. For a list, export instead of looping. POST /v1/exports takes up to 50,000 rows a request and 500,000 a day, and bulk CSV export is not on the Free plan.
In the app at app.leadocean.io, the Exports page gives you a filter builder, a column picker and the record price before you start. It then downloads a CSV. It is an export tool, not a rep workspace: there is no sequencer, dialer or CRM.
A short loop covers a few hundred people without an export. It writes email and phone to a CSV, skips misses, and stops on a key or balance error.
#!/usr/bin/env bash
## urls.txt: one LinkedIn profile URL per line
echo "url,email,phone" > out.csv
while read -r u; do
r=$(curl -s -w '\n%{http_code}' -X POST https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d "$(jq -n --arg u "$u" '{linkedin_url:$u, reveal_email:true}')")
code=$(echo "$r" | tail -n1); body=$(echo "$r" | sed '$d')
case "$code" in
200) echo "$body" | jq -r --arg u "$u" '[$u,
([.data.contact_data.contact_emails[]? | select(.type=="work")] | first | .email // ""),
(.data.contact_data.contact_phones[0].phone // "")] | @csv' >> out.csv ;;
404) echo "\"$u\",," >> out.csv ;;
429) sleep 1 ;;
401|402) echo "stopped on $code at $u" >&2; exit 1 ;;
esac
done < urls.txtOn Free, keep the loop under 5 requests a second. A sequential loop already does. Read your remaining records from GET /v1/usage, which is free, before you start a large run.
What you get
This is the sizing result from the free leadocean_count_leads MCP tool, run on 21 October 2026. The filters were jobLevel VP, jobFunction Sales & Business Development, country CA.
total: 5,574 (exact) mailable: verified, catch_all_valid or catch_all
totalAll: 18,800 same filters, any email status
distinctCompanies: 3,873
credits: 0A record-level enrich response has this shape. It is the response shape from the API reference, with placeholder values, not a real record.
{
"success": true,
"data": {
"profile_data": { "...": "name, title, company and LinkedIn URL" },
"contact_data": {
"has_email": true,
"email_status": "verified",
"contact_emails": [
{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }
],
"contact_phones": [
{ "phone": "+14155550133", "type": "mobile", "priority": 1 }
]
}
},
"meta": {}
}Since 17 October 2026 the enrich response also carries career history in resume_data: past roles, education, certifications and awards. Past employers have no company_id yet.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing, wrong or revoked key | Check that x-api-key carries $LEADOCEAN_API_KEY and the key is active in the app. |
| 402 | The 1,000 free records are spent | The allowance does not reset. Move to Solo at $97 a month, or Agency at $497 a month for teams. |
| 429 | Above the plan's rate limit | Honour Retry-After. Free allows 5 requests a second, Agency 200. |
| 404 on enrich | We hold nobody for that identifier | Costs nothing. Try email or phone as the identifier instead. |
| Empty results | A filter value that is not an exact enum string | Pull valid values from leadocean_list_enum_values. VP works, vp as a job level does not. |
| Export refused | Over 50,000 rows a request or 500,000 a day | Narrow the filters and split the export across requests or days. |
FAQ
Which contact enrichment tool is cheapest per find?
It depends on what you need. For email alone, Hunter charges 1 credit per email found, and its API enrichment endpoints use 0.2 credit on all-in-one plans (Hunter help center). For phones, Lusha charges 5 credits and Apollo 8. LeadOcean charges 1 record for either.
Do I pay when a lookup finds nothing?
It varies. LeadOcean enrich is free on a 404, but the v2 phone and email endpoints cost 1 record even on a miss. Prospeo and FullEnrich charge nothing for a miss, per their docs.
Can an AI client run this?
Yes. The hosted MCP server has 13 tools, and leadocean_find_phone and leadocean_get_lead cover the two steps. Counting is free through leadocean_count_leads.
How many people can I find per day?
Agency allows 1M enrichments a day and 200 requests a second, per the pricing page. Free allows 5 requests a second and 1,000 records in total.
Where do I find a phone number from an email?
Use the find phone number endpoint. To go the other way, read how to find an email from a phone number or the contact discovery guide. More guides live in the blog.
Find the email and phone for your next prospect
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →