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

How-to guide

How to Do B2B Prospecting for Highest Response Rates (with the LeadOcean API)

Response rate is mostly a list problem. Size a tight ICP for free, keep only mailable rows, pull a small batch and read the output before you send.

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

TL;DR

  • Response rate follows list quality. Narrow the ICP, keep only mailable emails, and send small batches so you can read the results.
  • The recipe takes about 15 minutes and spends about 25 of your 1,000 free records. Counts are free.
  • You end with a sized ICP, a 25-row pull and a rule for when to widen or stop.

Prerequisites

  • A LeadOcean account and API key from app.leadocean.io. The free plan has no card and 1,000 records, one-off.
  • The key in your shell as $LEADOCEAN_API_KEY.
  • curl and jq.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"

Step 1: Write the ICP as filters, not adjectives

A good ICP is a query. "Mid-market sales leaders" is a mood. jobLevel VP, jobFunction Sales & Business Development, country US, employeeRange 51-200 is something you can run and count.

Enum values are exact strings, so look them up before you trust a zero. The REST route is GET /v1/enums/{name}, and the MCP tool is leadocean_list_enum_values.

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

Job levels are C-Team, VP, Director, Manager, Staff and Other. Seniority is lowercase (c_suite, vp, director).

Step 2: Size it for free

Count before you pull. A count spends no records, however often you run it. Send count=true as a query parameter, with limit at 1.

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": ["US"],
    "employeeRange": ["51-200"],
    "emailStatus": ["verified"],
    "limit": 1
  }' | jq '.meta | {total, totalIsExact, countOnly}'

meta.total is capped at 100,000. If your total is far above what one rep can work in a month, the ICP is too wide. Add a filter. A list you cannot personalise is a list that does not reply.

Step 3: Keep only mailable rows

Bounces and spam traps hurt your sender reputation, and a damaged domain lowers every later reply rate. Filter on emailStatus at pull time. LeadOcean does not refund or credit back bounced emails, so read the status before you send.

SettingCountsUse when
["verified"]Verified addresses onlyYour domain is new or reputation matters most
["verified", "catch_all_valid", "catch_all"]The default mailable setYou accept some catch-all risk for volume
["verified", "risky", "unknown"]Adds unconfirmed addressesDo not send to these cold

The first two rows are the ones worth sending to. Compare the counts and pick on purpose.

Step 4: Pull 25 people and read them

Pull a small batch first. Each person returned costs one record, so 25 rows is a cheap test of whether your title filter matches real buyers. The body is flat JSON, filters are arrays, and limit runs from 1 to 100.

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"],
    "excludeTitle": ["assistant", "intern", "associate"],
    "country": ["US"],
    "employeeRange": ["51-200"],
    "emailStatus": ["verified"],
    "limit": 25
  }' > people.json

jq '{rows: (.data | length), credits: .meta.credits, nextCursor: .meta.nextCursor}' people.json

Read all 25 rows. If more than a few titles are wrong, tighten title and excludeTitle and pull again. Fix the filter, not the copy.

Step 5: Add one reason to write now

A reply needs a reason to reply today. Pick one filterable signal per batch and put it in the first line. Tech stack is the cheapest one: technologies matches companies with a detected tool, and detection covers about 7.8M crawled sites. Treat a match as a strong hint, not a census.

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 '{
    "technologies": ["HubSpot"],
    "jobLevel": ["VP"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["US"],
    "emailStatus": ["verified"],
    "limit": 1
  }' | jq '.meta | {total, distinctCompanies}'

Run the count with and without the signal. If the signal list is under a few hundred people, you have a segment worth a custom message. If it is empty, drop the signal and keep the rest of the ICP.

Write the opener from fields you hold: title, company, tech. If a field is empty, leave it out. A wrong detail costs more replies than a plain line.

Step 6: Split into small batches and send

Send 25 to 50 contacts per variant, not 2,000 at once. A small batch lets you see which segment replies, and it protects the domain if the copy misses. Page through the same query with cursor to get the next batch.

bash
CURSOR=$(jq -r '.meta.nextCursor' people.json)
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\": [\"US\"],
    \"employeeRange\": [\"51-200\"],
    \"emailStatus\": [\"verified\"],
    \"limit\": 25,
    \"cursor\": \"$CURSOR\"
  }" > batch2.json

One search pages to 10,000 rows. Past that, meta.depthCapped is true and there is no nextCursor. Narrow the filters instead of walking the index.

Sending itself happens in your own sequencer. LeadOcean has no sequencer, so export the rows or pipe them into your tool of choice. For an export, POST /v1/exports takes up to 50,000 rows a request and 500,000 a day, and it is not on the Free plan.

Set a stop rule before the first send. If a batch of 50 gets no replies and the bounce rate is above 2 percent, stop. Check the email status filter and the title match before you touch the copy.

Measure by segment: reply rate per title, per company size and per email status. Widen only the segment that replied. For the measurement side, see cold email response rate.

Where most lists go wrong

Three mistakes account for most weak lists. Each one is a filter you can fix before you write a word of copy.

  • Titles by keyword. A title match on "sales" returns assistants and interns. Use jobLevel and jobFunction for the band, then title for the exact role, and add excludeTitle.
  • Company size by guess. employeeRange is a fixed band such as 51-200. Pick one band per batch so the pain in your message fits the whole batch.
  • Unchecked email status. The default count only counts verified, catch_all_valid and catch_all addresses. Set emailStatus yourself so you know what you are sending to.

Fix these in the query, then rerun the free count. The total should drop. That is the goal.

What you get

The count in Step 2 comes back as a meta block. This is a real run of the free leadocean_count_leads MCP tool on 2026-10-21. The filters line is added here as a label.

json
{
  "filters": "jobLevel VP, jobFunction Sales & Business Development, country US, employeeRange 51-200, emailStatus verified",
  "total": 4552,
  "totalIsExact": true,
  "distinctCompanies": 3463,
  "credits": 0
}

The same filters without employeeRange and with the default mailable statuses (verified, catch_all_valid, catch_all) counted 129,494 US VPs in sales and business development, on the same date. Adding the size band and the verified-only rule cut the list to 4,552. That is a list one team can personalise.

A search row from Step 4 has this shape, with placeholder values. This is the response shape from the API reference.

json
{
  "success": true,
  "data": [
    {
      "profile_data": { "profile_full_name": "Jane Doe", "profile_headline": "VP Sales at Acme" },
      "contact_data": {
        "has_email": true,
        "email_status": "verified",
        "contact_current_experiences": [
          { "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com" }
        ]
      },
      "meta": { "source_ids": { "person_id": "1234567" } }
    }
  ],
  "meta": { "count": 25, "limit": 25, "credits": 25, "nextCursor": "..." }
}

Search rows are thin: profile and current role, with email flags rather than addresses. To get an address, enrich by the row's meta.source_ids.person_id with reveal_email set to true. The enrichment is one record, and reveal_email adds nothing on top.

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)Wait for Retry-After, then slow the loop
402Out of records on the Free planMove to Solo ($97 a month) or Agency ($497 a month), or narrow the pull
Empty data on a filter that should matchA bad enum value, such as Sales instead of Sales & Business DevelopmentResolve the value with GET /v1/enums or leadocean_list_enum_values
meta.depthCapped is true with no nextCursorOne search reached 10,000 rowsNarrow the filters and run a new query
Export refusedOver 50,000 rows a request or 500,000 a day, or you are on FreeSplit the export, or upgrade (bulk CSV export is not on Free)

FAQ

What is a good B2B cold email response rate?

LeadOcean does not publish a benchmark, and we will not invent one. Track your own reply rate by segment and compare it with your last send. See cold email response rate for how to measure it.

Does list size or list quality matter more?

Quality. A small list with exact titles and verified emails beats a large list with guessed titles. Count first, then decide how many rows you can actually personalise.

How many records does this recipe spend?

About 25, for one search page of 25 people. Counts, enum lookups and filter lookups are free. Enrichment that finds nothing is free too.

Can I run this from an AI assistant instead of curl?

Yes. LeadOcean has a hosted MCP server with 13 tools, and leadocean_count_leads is free. See prospecting tools with the best integrations for the tools that connect.

Does a rep need a tool for this?

The data side does not. Sending and follow-up live in your sequencer or CRM. For the rep workflow around the data, see rep prospecting. Plans start free and are listed on pricing. The section hub is the blog.

Size your ICP before you send a single email

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

Get your free API key →