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

How-to guide

How to Improve Email Deliverability (With Email Status Filters)

Most bounces are decided before you send. Filter on email status, size the list for free, then pull only what is sendable.

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

Most deliverability damage is done before you write the first email: you send to addresses that were never checked. Fix the list and the rest gets easier.

This guide covers the data side only. Authentication, warm-up and copy are in email deliverability best practices for B2B and building for email deliverability.

TL;DR

  • Filter by emailStatus before you pull a single row. Send to verified first, treat catch-all as a second tier, never send to invalid, spam_trap, abuse or disposable.
  • Sizing the list is free. Pulling 25 people costs 25 records. Total time: about 15 minutes.
  • Read status and verified_batch_date on every address, and re-check anything old before a big send.

Prerequisites

  • A LeadOcean API key in $LEADOCEAN_API_KEY (the Free plan works: 1,000 records for life, no card, 5 requests a second).
  • curl and jq.
  • A sending domain with SPF, DKIM and DMARC already set. This guide does not cover them.

Step 1: Learn the email status values

Thirteen statuses exist, and each means a different send decision. Ask the API for the list instead of guessing, because enum values are exact strings.

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

Use this table as the policy:

StatusSend?
verifiedYes. Start here.
catch_all_validYes. Mailbox confirmed on a catch-all domain.
catch_allSecond tier. Domain accepts everything, so bounces are hidden.
risky, unknown, untestedNot in a cold send.
invalid, disposable, spam_trap, abuseNever.
role, derived, noneSkip for personal outreach.

Step 2: Size the list for free

Counting spends no records. Run the same filters with two email conditions and compare.

bash
curl -s -X POST "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"],
    "limit": 1
  }' | jq '.meta | {total, distinctCompanies}'

meta.total is capped at 100,000. The MCP tool leadocean_count_leads does the same job from Claude or any MCP client, and meta.distinctCompanies tells you how many employers the list spans.

Step 3: Pull only the tier you will send

Search returns one record per person. Put the status filter in the body so unsendable rows never reach you.

bash
curl -s -X POST "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": 25
  }'

Page with cursor. One search pages to 10,000 rows, then meta.depthCapped is true: narrow the filters instead.

For a file, POST /v1/exports takes the same filters and up to 50,000 rows a request (500,000 a day). Bulk CSV export is not on Free.

Step 4: Check the age of each verdict

Search rows carry only the email_status flag. The addresses, each with its own status and verified_batch_date, come from enrichment with reveal_email. Take the ID from meta.source_ids.person_id on a search row. Enrichment costs one record per person found.

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":"PERSON_ID_FROM_SEARCH","reveal_email":true}' \
  | jq '.data.contact_data.contact_emails'

The date is the verification run, shared by a whole batch, not a timestamp for one address. A null date means our own verifier did not run the check; the status came from a source held to the same standard. Search applies the status rule per person, enrichment per address, so a search verified can come back untested on enrich. Trust the enriched answer.

Re-verify anything you plan to send months after you pulled it. The dataset itself is refreshed monthly.

Step 5: Split the send by tier

Send verified and catch_all_valid first, at your normal pace. Put catch_all in a separate, smaller campaign and watch its bounce rate before scaling. A catch-all domain accepts every address at the door, so the bounce arrives later or never shows up as a bounce at all.

Keep each tier in its own campaign so one bad tier cannot drag down the domain reputation of the whole send.

What you get

Real output from the free leadocean_count_leads tool on 2026-10-21. Filters: jobLevel VP, jobFunction Sales & Business Development, country CA.

Email filterMatching peopleEmployers
None (totalAll)18,800not reported
Default: verified, catch_all_valid or catch_all5,5743,873
emailStatus: ["verified"]1,8541,392

Only 1,854 of 18,800 (about 10%) are verified. The rest is the audience you would otherwise mail blind. These are counts of people matching the filters, not a promise of inbox placement.

A contact in the response, shape from the API reference, placeholder values:

json
{
  "email": "jane.doe@acme.com",
  "type": "work",
  "status": "verified",
  "verified_batch_date": "2026-09-20"
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key.Check $LEADOCEAN_API_KEY is exported and sent in the header.
429Above the plan's rate limit (5 a second on Free, 200 on Agency).Honor Retry-After, or slow the loop.
402The 1,000 free records are spent.Move to a paid plan; see pricing.
Empty dataBad enum value, such as Verified or VP Sales in jobLevel.Values are exact strings. Look them up at /v1/enums/{name}.
meta.depthCapped is trueOne search pages to 10,000 rows.Narrow the filters and run more searches.
Export refusedOver 50,000 rows a request or 500,000 a day.Split the export by country or seniority.

FAQ

Does a verified status guarantee no bounces?

No. It lowers the odds. Mailboxes get deleted, people change jobs and servers change rules. LeadOcean gives no refund or credit-back for bounced emails, so read status before sending.

Should I ever send to catch-all addresses?

Only as a separate, smaller tier. catch_all_valid means we confirmed the mailbox on a catch-all domain, so it is safer than plain catch_all.

How is a work email different from a personal one?

Use emailType to ask for a work address. Our verifier has not tested personal addresses, so verified on a personal address comes from a supplier. See the email deliverability benchmarks for context.

Does sizing a list cost records?

No. A count, a breakdown and an enrichment that finds nothing cost nothing. A search page of 25 is 25 records.

Send only to addresses worth sending to

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

Get your free API key →