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

How-to guide

How to Enforce B2B Data Accuracy Before You Send (Verified Emails Only)

Accuracy is the one data property you cannot fix after the send. Filter on it up front, count it for free, and check it again before the first email goes out.

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

Data accuracy matters most because a bad address does damage you cannot undo. A bounce hurts your sender reputation, and no later fix gives it back. Everything else about a list (coverage, freshness, filters) can be improved after the fact.

This guide shows the cheap way to enforce accuracy: filter on email_status, count the result for free, then verify the rows you pull.

Coverage is a volume problem. Accuracy is a reputation problem. You can always buy more rows, but you cannot buy back a domain that mailbox providers have learned to distrust.

Three things go wrong when you skip the filter:

  • Hard bounces from invalid and disposable addresses push your bounce rate up, and inbox providers score you on it.
  • spam_trap and abuse addresses are worse than a bounce. They mark you as a sender who does not clean lists.
  • role addresses such as a shared inbox rarely reach a person, so they burn volume for no reply.

Competitors cover this at length (Leadmagic's take, checked September 2026). The part they skip is the query. The rest of this page is the query.

TL;DR

  • Accuracy is enforced by one filter (emailStatus) and one field (email_status), not by a clean-up pass after the send.
  • It takes about 15 minutes and about 25 LeadOcean records. Counts are free.
  • Nothing is refunded for a bounce, so read email_status before you send.

Prerequisites

  • A LeadOcean API key in $LEADOCEAN_API_KEY. The Free plan (1,000 records for life, no card, 5 requests a second) is enough.
  • curl and jq.
  • Optional: the hosted MCP server at https://api.leadocean.io/mcp if you would rather run the counts from Claude.

Step 1: Know what the statuses mean

Every email carries a status, and the default for "mailable" is not the same as "safe". Our count tool counts verified, catch_all_valid and catch_all unless you say otherwise.

The full list of 13 values: verified, catch_all_valid, catch_all, risky, unknown, untested, invalid, role, disposable, spam_trap, abuse, derived, none.

Pull the live list instead of trusting a blog post:

bash
curl -s https://api.leadocean.io/v1/enums/email_status \
  -H "x-api-key: $LEADOCEAN_API_KEY"

My rule: send to verified first. Treat catch_all as a second tier at a lower daily volume, because a catch-all domain accepts every address and tells you nothing about the mailbox.

Step 2: Count how much accuracy costs you, for free

The accurate slice is smaller than the mailable slice. Measure the gap before you commit to a list. A count spends no records.

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

With the MCP server connected, ask Claude for the same thing. It calls leadocean_count_leads:

text
Count VPs in Sales & Business Development in Canada. Give me the total
with no email filter, with the default mailable filter, and with
emailStatus verified only.

Step 3: Pull only the accurate rows

Once the count looks right, search with the same body. The search body is flat JSON, filters are arrays, and limit runs 1 to 100. Each person returned costs one record.

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"],
    "limit": 20
  }' | jq '.meta.nextCursor'

Page with cursor. One search pages to 10,000 rows. If meta.depthCapped is true, narrow the filters instead of walking further.

Step 4: Verify the rows before you send

A list goes stale between the pull and the send. Enrich a sample by person_id and read the status again. Enrichment costs one record, and a person we hold nothing for is a 404 that costs nothing.

bash
curl -s -X POST https://api.leadocean.io/v1/people/enrich \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"person_id": "1234567890", "reveal_email": true}' \
  | jq '.data.contact_data | {email_status, email_type, contact_emails}'

Gate your sender on the result. A minimal rule keeps only verified work addresses:

bash
jq -r 'select(.email_status=="verified" and .email_type=="work") | .contact_emails[0].email'

A search count of verified is an upper bound. Enrichment applies the stricter per-address rule, so a row can come back untested when enriched, and the enriched answer wins.

The dataset is refreshed monthly and each record carries its own fetched_at date. Skip rows whose date is older than your tolerance.

Step 5: Tier the list and export it

Do not treat all mailable rows the same. Build two tiers from the same filter and send them at different paces.

TieremailStatusHow to send
1["verified"]Full daily volume
2["catch_all_valid", "catch_all"]Small batches, watch bounces
Leave outrisky, unknown, untested, invalid, role, disposable, spam_trap, abuse, derived, noneNot in this list. Never send to invalid, spam_trap, abuse or disposable

Export tier 1 with one request. Exports take up to 50,000 rows a request and 500,000 a day, and bulk CSV export is not on Free (Solo and above). Check the record price first on the Exports page in the app, which shows it before you start.

bash
curl -s -X POST https://api.leadocean.io/v1/exports \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VP Sales CA, verified",
    "limit": 1854,
    "filters": {
      "jobLevel": ["VP"],
      "jobFunction": ["Sales & Business Development"],
      "country": ["CA"],
      "emailStatus": ["verified"]
    }
  }'

The filters go inside filters, and limit is required. Poll GET /v1/exports/{id}, then download from GET /v1/exports/{id}/download.

Run the tier 2 export separately and load it into a different campaign. When bounce rates on tier 2 climb, you can stop it without touching tier 1.

What you get

Live result from leadocean_count_leads, run 21 October 2026 for VPs in Sales & Business Development, country CA. Counts only, no records spent.

FilterTotal
No email condition (totalAll)18,800
Default mailable (verified, catch_all_valid, catch_all)5,574
emailStatus: ["verified"] only1,854

Only 1,854 of 18,800 people are verified. That is the honest size of the list you can send to with confidence. The 5,574 figure is mailable, not verified.

Response shape from the API reference (placeholder values):

json
{
  "success": true,
  "data": {
    "contact_data": {
      "has_email": true,
      "email_status": "verified",
      "email_type": "work",
      "contact_emails": [{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }]
    }
  },
  "meta": { "credits": 1, "source": "own" }
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCheck $LEADOCEAN_API_KEY is exported and the header name is exact
429Above the plan's rate limit (5 a second on Free, 200 on Agency)Honour Retry-After and slow the loop
402The 1,000 free records are spentMove to Solo ($97 a month) or Agency ($497 a month)
Empty resultsA bad enum value, such as "VP Sales" for jobLevelResolve it with GET /v1/enums or leadocean_list_enum_values; levels are C-Team, VP, Director, Manager, Staff, Other
404 on enrichNobody matched the person_idFree; pick another row
Export refused (400 or 429)Over 50,000 rows an export or 500,000 a daySplit the filter into smaller exports

FAQ

Is a verified email the same as a deliverable email?

No. On a business address, verified means our own verifier sent to it and it accepted. It can still go dead later, which is why Step 4 re-reads the status before you send.

Should I send to catch-all addresses?

Only as a second tier. A catch-all domain accepts any address, so the check cannot tell you the mailbox exists. Send in small batches and watch the bounce rate.

Do bounced emails get refunded?

No. LeadOcean does not refund or credit back bounced emails. Read email_status first, which is the point of this guide.

How often is the data refreshed?

The dataset is refreshed monthly, and each record carries its own fetched_at date. See why legacy data providers fail for what stale data costs and why AI enrichment matters for revenue teams.

Does a waterfall improve accuracy?

It improves coverage. It does not make a bad address good. See what waterfall enrichment is and always re-check status at the last hop. Plans are on pricing. More guides are in the blog.

Send to people who can receive it

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

Get your free API key →