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

How-to guide

How to Prospect in B2B (Five Essentials, Run as API Calls)

The essentials of B2B prospecting reduced to five requests you can run today. Sizing is free.

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

B2B prospecting comes down to five moves: define the list, size it, pull the people, check the contact data, and hand it to whatever sends. Do them in that order and you waste few records.

TL;DR

  • Size the audience first with a free count, then spend records only on the people you will contact.
  • The whole walkthrough takes about 30 minutes and spends about 30 records, inside the 1,000 on the Free plan.
  • Read email_status before you send. Bounced emails are not refunded.

Prerequisites

  • A LeadOcean account. The free plan has no card and gives 1,000 records for life, with 5 requests a second.
  • An API key from app.leadocean.io, exported as $LEADOCEAN_API_KEY.
  • curl and jq.
  • An ICP in one sentence. Ours for this guide: VPs of sales in Canada.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"

Step 1: Write the ICP as filters

An ICP is only useful when it maps to filter fields. Pick a job level, a job function, a geography and, if it matters, a company size.

Enum values are exact strings, so resolve them before you guess. The leadocean_list_enum_values MCP tool does this for free, and so does GET /v1/enums.

bash
curl -s "https://api.leadocean.io/v1/enums" \
  -H "x-api-key: $LEADOCEAN_API_KEY" | jq -r '.data.enums[] | "\(.name) \(.count)"'

Job level takes C-Team, VP, Director, Manager, Staff or Other. Job function takes values such as Sales & Business Development. Country is a two-letter code.

Step 2: Size the list before you pull it

A free count tells you whether the ICP is too narrow, too wide or empty. Send count=true as a query parameter with limit=1. It spends no records.

bash
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"]
  }' | jq '.meta'

meta.total is capped at 100,000 and data comes back empty. If the total is under a few hundred, loosen a filter. If it is in the millions, add one.

Company lists have their own free sizing call, GET /v1/companies/count, with breakdowns by industry, headcount band and HQ country.

Step 3: Pull a page of people

Search returns one record per person. Start with a small page, check the quality, then page on.

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

The body is flat JSON and every filter is an array. limit runs from 1 to 100. Pass meta.nextCursor back as cursor to get the next page. One search pages to 10,000 rows, and a capped page has meta.depthCapped set to true. Narrow the filters instead of walking the index.

To list the people at one account, use the domain route.

bash
curl -s "https://api.leadocean.io/v1/companies/acme.com/people?limit=10" \
  -H "x-api-key: $LEADOCEAN_API_KEY" | jq '.meta'

Step 4: Enrich and check the email

Enrich takes exactly one of linkedin_url, email, phone or person_id. There is no name plus domain lookup, so search by domain first and enrich by person_id.

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": "per_0000000", "reveal_email": true}'

An enrichment that finds nobody is a 404 and costs nothing. A hit costs one record. Since October 2026 the response also carries career history: past roles, education and certifications, which is useful for an opener. Past employers carry no company_id yet.

Read email_status on every address. Send to verified, and treat catch_all_valid and catch_all as a judgement call for your own bounce tolerance. Skip risky, invalid, role, disposable and spam_trap.

For a phone number, use GET /v2/people/phone. It costs one record per call, including a call that finds nothing.

Step 5: Export the list and hand it off

For more than a few hundred rows, stop paging and export. POST /v1/exports takes up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on Free; it starts on Solo at $97 a month.

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": "ca-sales-vps",
    "filters": {
      "jobLevel": ["VP"],
      "jobFunction": ["Sales & Business Development"],
      "country": ["CA"],
      "emailStatus": ["verified"]
    },
    "limit": 500,
    "preset": "full"
  }' | jq '.data | {id, status, requested}'

Each row costs one record, so this spends up to 500. Poll GET /v1/exports/{id} until status is done, then download from downloadUrl.

You can also build the same export in the app: filter builder, column picker, the record price before you start, then Download. LeadOcean has no sequencer, dialer or CRM. The CSV goes into whatever you already send from.

What you get

A free count through the MCP tool leadocean_count_leads, run on 2026-10-21 for VP, Sales & Business Development, country CA:

json
{
  "total": 5574,
  "totalIsExact": true,
  "totalAll": 18800,
  "distinctCompanies": 3873,
  "credits": 0
}

total counts only mailable addresses (verified, catch_all_valid or catch_all). totalAll is the same filters with no email condition. Cost: zero records.

A person record from search looks like this. This is the response shape from the API reference, with placeholder values.

json
{
  "success": true,
  "data": [
    {
      "profile_data": { "profile_full_name": "Jane Doe" },
      "contact_data": {
        "email_status": "verified",
        "contact_current_experiences": [
          { "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com" }
        ]
      },
      "meta": { "source_ids": { "person_id": "per_0000000" }, "fetched_at": "2026-10-01" }
    }
  ],
  "meta": { "count": 1, "nextCursor": "abc123" }
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-keyCheck $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
402Records are spent (1,000 on Free)Move to a paid plan, or narrow the pull
Empty dataA filter value is not an exact enum stringResolve it with GET /v1/enums or leadocean_list_enum_values
404 on enrichNobody matched the inputNo charge. Try another identifier
Export refusedOver 50,000 rows a request or 500,000 a daySplit the export by country or level

FAQ

What are the essentials of B2B prospecting?

A defined ICP, a sized list, verified contact data, a way to reach people, and a feedback loop on replies. This guide covers the first three and the export that feeds the fourth.

How many records does a first run cost?

About 30 in this walkthrough: one 25-person page plus a few enrichments. Counts and empty enrichments are free.

Can I do this without code?

Yes. The Exports page in the app has the filter builder, column picker and price preview. The API is for when you want it repeatable.

Can an AI agent run the same steps?

Yes. LeadOcean has a hosted MCP server with 13 tools, including free leadocean_count_leads and leadocean_count_companies.

For more techniques, see 10 sales prospecting techniques that convert, rep prospecting and B2B prospecting software with the best integrations. Plans are on /pricing. More guides are in the blog hub.

Size your own ICP with a free count

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

Get your free API key →