An email lookup app takes a person or an address and returns an email plus a deliverability status. This guide does it with a few requests against the LeadOcean API.
You will see the real request, the response shape and the status that decides whether you send.
TL;DR
- You will size a list for free, find one work email, check an address you already hold, and trace an address back to its owner.
- It takes about 15 minutes and spends 6 LeadOcean records. The Free plan has 1,000, one-off, no card.
- Send only to
verifiedandcatch_all_valid. Treat every other status as a decision, not a green light.
Prerequisites
- A LeadOcean account. Start free, no card.
- An API key from the app, exported as
$LEADOCEAN_API_KEY. curl. Optional: the LeadOcean MCP server athttps://api.leadocean.io/mcpif you would rather ask in plain English from Claude.- Optional: the app's Exports page at app.leadocean.io, which covers the bulk case in Step 5.
export LEADOCEAN_API_KEY="your-key-here"Step 1: Size the list for free
Count before you spend. A count costs no records, so you can tune filters until the number looks right.
Over REST, send count=true and limit=1 as query parameters. The body stays flat JSON, and every filter is an array.
curl -s -X POST "https://api.leadocean.io/v1/people/search?count=true&limit=1" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["CA"],
"emailStatus": ["verified", "catch_all_valid", "catch_all"]
}'Over MCP, the same question is one prompt. The leadocean_count_leads tool is free.
How many VPs of Sales & Business Development in Canada have a mailable email?Enum values are exact strings. Run leadocean_list_enum_values (or GET /v1/enums/email_status) if a filter returns nothing.
Step 2: Find the people at one company
Search by company domain and a title keyword. Each person returned costs one record, so keep limit small while you test.
curl -s -X POST "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": ["acme.com"],
"title": ["Head of Sales"],
"emailStatus": ["verified", "catch_all_valid"],
"limit": 3
}'limit runs from 1 to 100, and you page with meta.nextCursor passed back as cursor. Each row carries meta.source_ids.person_id. Keep it: the next step needs it.
Search rows tell you whether an address exists and its status. They do not return the address itself. That is Step 3.
If you want everyone at the company rather than one title, list its people by domain. It returns the same thin rows, one record per person, and pages to 10,000 rows at most.
curl -s "https://api.leadocean.io/v1/companies/acme.com/people?limit=10" \
-H "x-api-key: $LEADOCEAN_API_KEY" | jq '.data[] | .meta.source_ids.person_id'Pick the people you want, then send only their ids to Step 3. You pay for the rows you see, so filter by title before you widen the list.
Step 3: Get the work email
Send the person_id to the work email endpoint. It returns one address, or data: null.
curl -s "https://api.leadocean.io/v2/people/email/work?person_id=1234567890" \
-H "x-api-key: $LEADOCEAN_API_KEY"The endpoint only returns addresses at the person's current employer. It also requires the address to be verified, catch_all_valid or catch_all. So data: null means "none that qualify", not "no work email exists".
This call costs one record, including a call that finds nothing. For a personal address, use GET /v2/people/email/personal. It returns a list with no status field, because we do not verify consumer domains.
Step 4: Verify an address you already hold
You do not need the person first. Enrich by email and add reveal_email to see every address and phone we hold, each with its status.
curl -s -X POST "https://api.leadocean.io/v1/people/enrich" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "jane.doe@acme.com", "reveal_email": true }'Enrich takes exactly one of linkedin_url, email, phone or person_id. A person we hold nothing for returns a 404 and costs nothing.
Gate on the status in the same script, so a person never decides by eye.
curl -s -X POST "https://api.leadocean.io/v1/people/enrich" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "jane.doe@acme.com", "reveal_email": true }' \
| jq -r '.data.contact_data.contact_emails[]
| select(.status == "verified" or .status == "catch_all_valid") | .email'An empty result means no address we hold for that person is safe to send. The enriched status is the one to trust. A search row can read verified while enrichment, which applies the stricter per-address rule, reads untested.
To go the other way, send an address or a phone number and get the owner. Use POST /v2/people/reverse with a JSON body of { "email": "jane.doe@acme.com" }. It costs one record. Our guide to reverse email lookup covers when to use it, and best reverse email lookup tools compares the options.
Step 5: Do it in bulk
For more than a few hundred rows, stop looping over single lookups. Export the filtered list instead.
curl -s -X POST "https://api.leadocean.io/v1/exports" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ca-vp-sales",
"filters": { "jobLevel": ["VP"], "country": ["CA"], "emailStatus": ["verified", "catch_all_valid"] },
"limit": 500,
"columns": ["person_id", "email_N_address", "email_N_status"],
"caps": { "emails": 1 }
}'An export takes up to 50,000 rows a request and 500,000 a day. Poll GET /v1/exports/{id}, then fetch GET /v1/exports/{id}/download. The app's Exports page does the same with a filter builder, a column picker and the record price shown before you start.
Check the column ids with GET /v1/exports/columns first. Numbered columns are requested as email_N_address and come back as email_1_address, email_1_status, and so on. Each row costs one record, so this request spends up to 500. Bulk CSV export is not on the Free plan; it is included from Solo up.
What you get
The free count from Step 1, run through leadocean_count_leads on 21 October 2026.
Filter: jobLevel VP, jobFunction Sales & Business Development, country CA
Default (verified, catch_all_valid, catch_all): 5,574 people credits: 0
emailStatus verified only: 1,854 people credits: 0The second number counts people whose best email is verified. It is not a mailable count, because it leaves out confirmed catch-all mailboxes. Search counts of verified are an upper bound, so confirm each address when you enrich it.
Response shape from the API reference for GET /v2/people/email/work, with placeholder values.
{
"success": true,
"data": {
"email": "jane.doe@acme.com",
"status": "verified",
"verified_batch_date": "2026-09-20"
}
}A date in verified_batch_date means our verifier tested the address. A null means the check was not ours, not that the address is unverified.
Response shape from the API reference for POST /v2/people/reverse, with placeholder values.
{
"success": true,
"data": {
"person_id": "1234567890",
"full_name": "Jane Doe",
"job_title": "Head of Sales",
"company_name": "Acme",
"company_domain": "acme.com",
"query": { "email": "jane.doe@acme.com" },
"matched": { "email": "jane.doe@acme.com", "status": "verified" },
"matched_in_record": true
}
}What each status means
| Status | Meaning | Send? |
|---|---|---|
verified | Our verifier sent to the address and it accepted | Yes |
catch_all_valid | Domain accepts everything, but we confirmed this mailbox | Yes |
catch_all | Domain accepts everything, so the address cannot be confirmed | Your call, expect some bounces |
risky, role, derived | Use with care. derived is built from a pattern and never tested | Test first |
untested, unknown | Not checked, or inconclusive | Test first |
invalid, disposable, spam_trap, abuse | Do not send | No |
There is no refund or credit-back for bounced emails, so read email_status before you send.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key header | Check $LEADOCEAN_API_KEY is set and sent as x-api-key. |
| 429 | Above your plan's rate limit per account (5 a second on Free, 200 on Agency) | Honor the Retry-After header and slow the loop. |
| 402 | Records spent. On Free the 1,000 are one-off | Move to Solo ($97 a month) or Agency ($497 a month). A paid key past its fair-use pace is slowed until the window resets, not refused. |
| Empty results | A filter value is not an exact enum string | List the values with GET /v1/enums/{name} and copy them exactly. |
| 404 on enrich or a v2 lookup | We hold no record for that person | Search by domain first, then enrich by person_id. |
400 export_limit_rows or 429 export_limit_daily | Export over 50,000 rows, or 500,000 in a day | Split the export into smaller requests across days. |
FAQ
Is there a free email lookup app?
Yes, within a limit. The Free plan gives 1,000 records, one-off, with no card, and it includes the same API, data and MCP server as the paid plans. Counts are always free.
Can I look up an email from a name and a company?
Not in one call. There is no name plus domain lookup. Search by domain and title first, then use the returned person_id on the work email endpoint.
How is this priced against other email lookup tools?
LeadOcean paid plans are flat: Solo $97 and Agency $497 a month, with a fair-use pace and no per-lookup price. FullEnrich charges 1 credit for a work email and 1 for a reverse email lookup, and charges 0 for a not-found result (FullEnrich credit docs, September 2026). Our pricing page has the full picture.
How do I verify a list I already have?
Enrich each address by email and read email_status. For a large list, run it in batches under your plan's rate limit (5 a second on Free, 50 on Solo, 200 on Agency). Our guide on how to verify email addresses covers the full process.
Do search results show the email address?
No. A search row shows has_email and email_status. You reveal the address with the work email endpoint or reveal_email on enrich. The blog hub lists the rest of this series.
Find and verify your first email address free
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →