Pre-Black Friday: 20% off, for as long as you stayEARLYBFon Solo and AgencyEnds Nov 28Start free

How-to guide

How to Get Verified Emails with Six Enrichment Calls (LeadOcean API)

Count the list free, filter to verified addresses, enrich the rows you will contact, and export the rest. Real requests, real output shape.

Get your free API key →Free to start. No credit card. 1,000 records to spend whenever you like.

TL;DR

  • Verified email is a filter, not a separate product. Set emailStatus on a search, then use one of six calls to count, find, enrich or export the addresses.
  • It takes about 20 minutes and spends about 21 LeadOcean records: 20 for a sample search and 1 for a single enrichment. The count costs 0.
  • Pick the call by the job. Count to size, search to list, enrich to reveal, the two v2 lookups to fill gaps, export to move a file.

Prerequisites

  • A LeadOcean account from app.leadocean.io. The free plan has no card and 1,000 records, one-off. Free runs at 5 requests a second.
  • An API key exported as $LEADOCEAN_API_KEY, plus curl and jq.
  • A target audience written as filters. The example is VP-level sales leaders in Canada.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"

Step 1: Count the verified audience (free)

Size the list before you spend anything. Send count=true as a query parameter with limit at 1. The body takes flat JSON, and every filter is an array.

bash
curl -s "https://api.leadocean.io/v1/people/search?count=true" \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d '{
    "jobLevel": ["VP"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["CA"],
    "emailStatus": ["verified"],
    "emailType": ["work"],
    "limit": 1
  }' | jq '.meta'

This costs 0 records. meta.total is capped at 100,000, and meta.distinctCompanies tells you how many employers the people span. In an MCP client, leadocean_count_leads runs the same count.

Step 2: Search with an email status filter

emailStatus is the verification gate. verified is the strictest value. catch_all_valid means we confirmed the mailbox on a catch-all domain. catch_all means the domain accepts everything.

bash
curl -s https://api.leadocean.io/v1/people/search \
  -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"],
    "emailType": ["work"],
    "limit": 20
  }' > sample.json
jq -r '.data[] | [.meta.source_ids.person_id, .contact_data.email_status] | @csv' sample.json

This spends 20 records, one per person returned. Search rows carry email flags, not addresses. Page further with the cursor from meta.nextCursor. One search pages to 10,000 rows, then meta.depthCapped turns true.

Step 3: Enrich one person and reveal the email

Enrichment takes exactly one of linkedin_url, email, phone or person_id. Use a person_id from the sample. reveal_email returns the addresses and costs no extra record.

bash
curl -s https://api.leadocean.io/v1/people/enrich \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d '{"person_id": "<person_id from sample.json>", "reveal_email": true}' | jq .

A person we hold nothing for is a 404 and costs nothing. Reveal only for rows you will contact.

Step 4: Fill gaps with the two v2 email lookups

Two single-purpose endpoints fill gaps. The work endpoint returns one address. The personal endpoint returns a list, with known-bad addresses withheld. Both take linkedin_url, contact_id or person_id.

bash
curl -s "https://api.leadocean.io/v2/people/email/work?person_id=<person_id>" \
  -H "x-api-key: $LEADOCEAN_API_KEY" | jq .

curl -s "https://api.leadocean.io/v2/people/email/personal?person_id=<person_id>" \
  -H "x-api-key: $LEADOCEAN_API_KEY" | jq .

The work endpoint returns an address at the person's current employer's domain, or data: null. Null means none that qualify, not no email. Each call costs one record, including a call that finds nothing.

Step 5: Export the verified list

Bulk CSV export is on Solo ($97 a month) and above, not on Free. An export takes up to 50,000 rows a request and 500,000 a day. Free users page the search with cursor instead.

bash
curl -s https://api.leadocean.io/v1/exports \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d '{
    "name": "CA sales VPs, verified work email",
    "filters": {
      "jobLevel": ["VP"],
      "jobFunction": ["Sales & Business Development"],
      "country": ["CA"],
      "emailStatus": ["verified"],
      "emailType": ["work"]
    },
    "limit": 500,
    "preset": "full"
  }' | jq '.data'

The export queues. Poll GET /v1/exports/{id}, then fetch /v1/exports/{id}/download. The CSV headers come back as email_1_address, email_1_status and so on. The app has the same export on its Exports page, with a price preview before you start.

Step 6: Check the status before you send

Read email_status on every row before it goes into a sequencer. We give no refund for bounced emails. LeadOcean has no sequencer, so the file goes into the tool you already use.

bash
jq -r '.data[] | .contact_data.email_status' sample.json | sort | uniq -c

Drop risky, unknown, role, disposable and spam_trap rows from the send list.

What you get

The count from Step 1, run with the free leadocean_count_leads tool on 2026-10-21. Filters: jobLevel VP, jobFunction Sales & Business Development, country CA, emailStatus verified, emailType work.

json
{
  "total": 1602,
  "totalIsExact": true,
  "distinctCompanies": 1209,
  "distinctCompaniesIsExact": true,
  "credits": 0,
  "unsupportedFilters": []
}

That is the count of people with a verified work email, not everyone matching the other filters. A search row looks like this (response shape from the API reference, placeholder values):

json
{
  "success": true,
  "data": [
    {
      "meta": { "source_ids": { "person_id": "1234567890" } },
      "profile_data": { "profile_full_name": "Jane Doe" },
      "contact_data": { "has_email": true, "email_status": "verified", "email_type": "work" }
    }
  ],
  "meta": { "nextCursor": "..." }
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCheck $LEADOCEAN_API_KEY is exported and sent as x-api-key.
429Above the plan's rate limit (5 a second on Free, 200 on Agency)Back off for the Retry-After seconds.
402Out of recordsCheck GET /v1/usage. Move to a paid plan or narrow the pull.
Empty resultsA filter value is not an exact stringLook it up with leadocean_list_enum_values. jobLevel is VP, not vp.
data: null from a v2 lookupNo qualifying address heldTry enrich with reveal_email, or accept there is none.
400 on exportMore than 50,000 rows, or a filter the export cannot applySplit into several exports and narrow the filters.

FAQ

Is a verified email guaranteed to deliver?

No. verified means the mailbox was checked, not that it will never bounce. We give no refund for bounced emails, so read email_status first.

What is the difference between verified and catch_all_valid?

verified is a checked address. catch_all_valid is a mailbox we confirmed on a domain that accepts all mail. catch_all means the domain accepts all mail, so the single mailbox could not be confirmed.

Which call should I start with?

Start with the free count. Then run a 20-row search and read the statuses. Enrich or export only after the numbers look right.

How many records does this spend?

About 21 on the example: 20 for the search and 1 for the enrichment. Counts, 404s and empty pages cost nothing. See pricing.

Where can I read more on enrichment tools?

Get verified emails from one API call

Free to start. No credit card. 1,000 records to spend whenever you like.

Get your free API key →