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

How-to guide

How to Build a Better Outbound Prospect List (With 8 Enrichment Calls)

Eight LeadOcean calls, in order: two free sizing calls, then search, roster, enrich, phone and export. Each one has a real query.

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

A better outbound list comes from eight calls in a fixed order. Size the audience for free, search, pull the roster, enrich, add phones, then export. This guide runs all eight against the LeadOcean API with real queries.

TL;DR

  • Two of the eight calls are free: a people count and a company count. Run them before you spend a record.
  • The whole recipe takes about 40 minutes and spends about 130 records, well inside the 1,000 on the free plan.
  • Every call below is a plain HTTP request to https://api.leadocean.io, so a script or an MCP client can run it.

Prerequisites

  • A LeadOcean account on the free plan (no card). The app is at app.leadocean.io.
  • An API key in your shell: export LEADOCEAN_API_KEY=.... Free keys carry both scopes, search and enrich.
  • curl and jq. The MCP route needs only the server URL https://api.leadocean.io/mcp and an OAuth sign-in.
  • An ICP written as filters. The example here: Directors in sales, United States, companies of 51 to 200 people.

Step 1: Size the people list (free)

Send count=true as a query parameter with limit=1. It returns the total and spends nothing.

bash
curl -s -G "https://api.leadocean.io/v1/people/search" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "count=true" \
  --data-urlencode "limit=1" \
  --data-urlencode "jobLevel=Director" \
  --data-urlencode "jobFunction=Sales & Business Development" \
  --data-urlencode "country=US" \
  --data-urlencode "employeeRange=51-200" | jq '.meta'

Read meta.total. It is capped at 100,000, so narrow the filters if you hit that. Enum values are exact strings: check them with GET /v1/enums or the leadocean_list_enum_values tool before you guess.

Step 2: Size the company list (free)

Count companies with the same ICP at the account level. GET /v1/companies/count is free and breaks the total down by industry, headcount band and HQ country.

bash
curl -s -G "https://api.leadocean.io/v1/companies/count" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "employeeRange=51-200" \
  --data-urlencode "hqCountry=US" \
  --data-urlencode "hasMailableContacts=true" | jq

In an MCP client the same call is the leadocean_count_companies tool. Ask: "Count US companies with 51 to 200 employees that have a mailable contact."

Step 3: Pull the first page of people

Search returns one record per person. Ask for 25 first, not 100, to check the filters on a small page.

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": ["Director"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["US"],
    "employeeRange": ["51-200"],
    "limit": 25
  }' | jq '.meta'

The body is flat JSON and filters are arrays. Page with meta.nextCursor, passed back unchanged. One search pages to 10,000 rows, then meta.depthCapped turns true and no cursor is issued.

Step 4: Pull the roster of a target account

When a company is already on your list, get its people directly. GET /v1/companies/{domain}/people returns thin records, one record per person.

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

Use it to find a second or third contact at an account where the first one bounced. Contact points are not in this response. Enrich a person for those.

Step 5: Enrich one person

Enrich takes exactly one of linkedin_url, email, phone or person_id. There is no name plus domain lookup, so search first, then 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": "PERSON_ID_FROM_SEARCH", "reveal_email": true}'

reveal_email returns the address at no extra record. A person we hold nothing for is a 404 and costs nothing.

Step 6: Read the career history

Person enrich returns resume_data since October 2026: past roles, education, certifications and awards, each when held. Use the past roles to write one true line in the opener.

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"}' \
  | jq '.data.resume_data.experiences'

Past employers carry no company_id yet, so match them by name, not by ID. The current role is in contact_current_experiences[].

Step 7: Add a phone number

Phones come from GET /v2/people/phone. It takes linkedin_url, contact_id or person_id and costs one record per call, even when it finds nothing. So filter first with hasPhone=true in the search.

bash
curl -s -G "https://api.leadocean.io/v2/people/phone" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "person_id=PERSON_ID_FROM_SEARCH" | jq '.data'

Numbers come best first. Each has a phone and a type, the source's own label (mobile, office and so on). Treat an unfamiliar label as unknown.

Step 8: Export the list

For more than a few hundred people, stop calling one by one and run a bulk export. POST /v1/exports takes up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on the free plan, so this step needs Solo ($97 a month) or higher.

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": "sales-directors-us-51-200",
    "filters": {
      "jobLevel": ["Director"],
      "jobFunction": ["Sales & Business Development"],
      "country": ["US"],
      "employeeRange": ["51-200"],
      "emailStatus": ["verified"]
    },
    "limit": 5000,
    "preset": "full"
  }'

The export is async. Poll GET /v1/exports/{id}, then download from /v1/exports/{id}/download. Every row costs one record whatever the columns. The app does the same on its Exports page: filter builder, column picker, price preview, CSV download.

What you get

The free count for the ICP above, from the leadocean_count_leads tool on 2026-10-21. It counts mailable people by default (verified, catch_all_valid or catch_all):

json
{
  "total": 36453,
  "totalIsExact": true,
  "totalAll": 119788,
  "distinctCompanies": 20473
}

total counts mailable people. totalAll is the same filters with no email condition. The gap between them is the people you would pay a record for and not be able to email.

A person-enrich record has this shape (response shape from the API reference, placeholder values). profile_data holds identity, headline and location; the reference leaves its fields untyped, so print one real response before you map them.

json
{
  "success": true,
  "data": {
    "profile_data": { },
    "contact_data": {
      "has_email": true,
      "email_status": "verified",
      "email_type": "work",
      "contact_emails": [{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }],
      "contact_current_experiences": [ { } ]
    },
    "resume_data": {
      "experiences": [{ "job_title": "Sales Manager", "company_name": "Acme", "start_date": "2019-01", "end_date": "2022-06" }],
      "educations": []
    },
    "meta": { }
  }
}

The phone endpoint returns data with no meta: person_id, found, phones (best first, each { "phone": "+14155550133", "type": "mobile" }) and best.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCheck $LEADOCEAN_API_KEY is exported and sent in the header x-api-key.
429Above the plan's rate limit (5 requests a second on Free, 200 on Agency)Honor Retry-After, or slow the loop.
402Out of records (1,000 on Free)Upgrade, or narrow the list. Counts and 404s never spend records.
Empty resultsA bad enum value, such as director for jobLevelUse the exact string Director. Check GET /v1/enums.
400 export_limit_rowsMore than 50,000 rows in one exportSplit the filters into several exports.
429 export_limit_dailyPast 500,000 export rows in a dayWait for resetsAt in the response.

FAQ

Which of the eight calls spend records?

Search, roster, enrich, phone and export. The two counts are free, and so is an enrichment that finds nothing. Phone calls cost one record even on a miss.

Why size the list before searching?

A count tells you if the ICP is 300 people or 300,000, before you spend a record. It also shows the gap between mailable and total people.

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

Yes. The hosted MCP server at https://api.leadocean.io/mcp has 13 tools, including both counts. Sign in with OAuth, no key pasted.

Is a bounced email refunded?

No. Read email_status before sending, and filter to verified for the cleanest list. See pricing for what each plan includes.

Where do I go next?

Start with how to build a targeted prospect list. For tech filters see the tech stack version, and for dialing see the cold calling list. More guides are on the blog.

Build your outbound list with eight calls

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

Get your free API key →