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

How-to guide

How to Build Longlists for Executive Search (With Live People Data)

Size the candidate pool for free, page the search, pull career history for the people worth a call, and write a CSV you can load into your ATS.

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

You can build an executive search longlist with four calls: count, search, enrich, then write a CSV. This guide runs a CFO search end to end against LeadOcean and shows the counts we measured on 21 October 2026. It is the short, technical version, and it says where LeadOcean stops.

TL;DR

  • Size the pool with a free count, narrow it until a human can read it, then page the search and enrich only the names you would call.
  • It takes about 30 minutes. The example spends about 40 of your 1,000 free records: 20 for the search, 20 for enrichment.
  • Counts, filter lookups and enum lookups cost nothing. Every person returned costs one record. The dataset refreshes monthly, and each record carries its own fetched_at date.

Prerequisites

  • A LeadOcean account and API key from app.leadocean.io. The free plan has no card and 1,000 records, one-off. Free keys get both the search and enrich scopes.
  • The key in your shell as $LEADOCEAN_API_KEY.
  • curl and jq. Free keys are limited to 5 requests a second, which is plenty here.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"

Step 1: Turn the role brief into filters

Write the role as filter values before you touch the API. Filter values are exact strings, so look them up instead of guessing.

The example brief: a CFO for a US software company with 201 to 5,000 staff, ideally someone who has taken a company through an IPO.

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

These calls are free. The same lookup is the MCP tool leadocean_list_enum_values. Job levels are C-Team, VP, Director, Manager, Staff and Other. A mistyped value such as c-team returns an error or an empty page, so copy the strings exactly.

Step 2: Size the pool for free

Count first. Add one filter at a time and watch the pool shrink. A retained search wants 30 to 80 names, so stop narrowing when you are near that range.

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 '{
    "title": ["Chief Financial Officer"],
    "country": ["US"],
    "jobLevel": ["C-Team"],
    "employeeRange": ["201-500", "501-1000", "1001-5000"],
    "industry": ["Software Development"],
    "keywords": ["IPO"],
    "limit": 1
  }' | jq '.meta | {total, totalIsExact, distinctCompanies, credits}'

count=true goes in the query string, not the JSON body, and limit stays at 1. The response has no rows and costs nothing. In Claude or any MCP client, ask for leadocean_count_leads with the same filters.

We ran this ladder with the free MCP count on 21 October 2026. For executive search we counted everyone we hold, with emailStatus set to all 13 values on the last row. The first three rows use the tool's default, which counts only people with a verified, catch_all_valid or catch_all email.

FiltersPeopleBasis
title CFO, country US, jobLevel C-Team80,634Mailable only
plus employeeRange 201 to 5,00026,509Mailable only
plus industry Software Development1,199Mailable only
same filters, no email filter2,276Everyone we hold
plus keywords IPO, no email filter20Everyone we hold

Do not filter on email status for a longlist. A candidate with no verified address is still a candidate, and you may reach them through a referral. The mailable rows are for outreach. The unfiltered rows size the search.

The keywords filter matches the person's own headline, summary, skills and job descriptions. It is a phrase match, not a judgement that the person led an IPO. Read the profiles before you trust it.

Pull the 20 names. Search returns one page of up to 100 rows, and meta.nextCursor points to the next page. Save each person's person_id, because enrichment keys on it.

bash
curl -s "https://api.leadocean.io/v1/people/search" \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d '{
    "title": ["Chief Financial Officer"],
    "country": ["US"],
    "jobLevel": ["C-Team"],
    "employeeRange": ["201-500", "501-1000", "1001-5000"],
    "industry": ["Software Development"],
    "keywords": ["IPO"],
    "limit": 100
  }' | tee page1.json \
  | jq -r '.data[] | [.profile_data.profile_full_name, .profile_data.profile_headline, .meta.source_ids.person_id] | @tsv'

jq '.meta | {total, nextCursor, depthCapped}' page1.json

If nextCursor is set, send it back as "cursor" with the same filters to get the next page. One search pages to 10,000 rows. The last capped page has meta.depthCapped true and no cursor. For a search longlist you should never get near it. If you do, narrow the filters instead of walking the index.

Search rows are thin: identity, headline, current role and company, location and email flags. They carry no addresses and no career history.

Step 4: Enrich the names worth a call

Enrich only the people you would pick up the phone for. One enrich call is one record, and a person we hold nothing for is a 404 that costs nothing. Career history comes from this call, not from search.

bash
PERSON_ID="paste-a-person_id-from-page1.json"
curl -s https://api.leadocean.io/v1/people/enrich \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d "{\"person_id\": \"$PERSON_ID\", \"reveal_email\": true}" | tee person.json \
  | jq '.data | {
      current: .contact_data.contact_current_experiences,
      past_roles: .resume_data.experiences,
      education: .resume_data.educations,
      certifications: .resume_data.certifications,
      still_at_company: .contact_data.contact_still_at_company_status
    }'

Since 17 October 2026 the enrich response includes resume_data: past roles, education, certifications, awards and more, each when we hold it. Past roles carry a title, company name, dates and job level. Past employers have no company_id yet, so you cannot join them to the company endpoints.

Check contact_still_at_company_status before you write to anyone. The enrichment docs list the still-at-company status under contact_data. For a name you are about to send to a client, also check the profile yourself. We do not offer live change alerts.

To enrich the whole list, loop over the saved ids and keep the output.

bash
jq -r '.data[].meta.source_ids.person_id' page1.json | while read -r id; do
  curl -s https://api.leadocean.io/v1/people/enrich \
    -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
    -d "{\"person_id\": \"$id\", \"reveal_email\": true}" >> enriched.jsonl
  sleep 0.3
done

Step 5: Write the longlist CSV

Flatten the enriched records into one row per candidate. Your ATS or spreadsheet reads it directly.

bash
jq -r '[.data.profile_data.profile_full_name,
        .data.profile_data.profile_headline,
        .data.profile_data.profile_url,
        .data.contact_data.email_status,
        .data.contact_data.contact_still_at_company_status,
        (.data.resume_data.experiences | length? // 0)] | @csv' enriched.jsonl > longlist.csv
sed -i.bak '1i\
"name","headline","profile_url","email_status","still_at_company","past_roles"' longlist.csv

For a search above a few hundred rows, use POST /v1/exports instead of a paging loop. It takes the same filters, up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on the free plan. You can also start an export from the Exports page in the LeadOcean app, which shows the record price before you run it.

What you get

You get a CSV with one row per candidate, plus a free count that sized the search. This is the raw output of the last row of the Step 2 table, run on 21 October 2026 with leadocean_count_leads. It cost 0 records.

json
{
  "total": 20,
  "totalIsExact": true,
  "distinctCompanies": 20,
  "credits": 0,
  "facets": {
    "seniority": [{ "value": "c_suite", "count": 20 }],
    "company_size": [
      { "value": "201-500", "count": 9 },
      { "value": "1001-5000", "count": 7 },
      { "value": "501-1000", "count": 4 }
    ]
  }
}

Twenty people across 20 different employers. No candidate shares a company with another, which is what you want when a client asks for a spread.

An enrich call returns one person. This is the response shape from the API reference, with placeholder values.

jsonc
{
  "success": true,
  "data": {
    "profile_data": {
      "profile_full_name": "Jane Doe",
      "profile_headline": "<headline>",
      "profile_url": "https://www.linkedin.com/in/janedoe"
    },
    "contact_data": {
      "contact_emails": [{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }],
      "email_status": "verified",
      "contact_still_at_company_status": "<status>",
      "contact_current_experiences": [ /* current role at Acme */ ]
    },
    "resume_data": {
      "experiences": [ /* past roles, each when held */ ],
      "educations": [ /* each when held */ ],
      "certifications": [ /* each when held */ ]
    },
    "meta": { "source_ids": { "person_id": "<person_id>" }, "fetched_at": "<date>", "schema": "leadocean.person.v1" }
  },
  "meta": { "credits": 1 }
}

Fields we do not hold come back null, so expect gaps. Senior executives with a thin public profile may return little in resume_data.

Where LeadOcean stops

LeadOcean finds and describes people. It does not run the search for you.

  • It has no job-change alerts or watchers. Crustdata's guide adds change monitoring to its longlist workflow (Crustdata blog, September 2026). If you need alerts mid-search, pair this recipe with a tool that has them.
  • The dataset refreshes monthly. It is not a live scrape of each profile.
  • The app has an Exports page but no candidate workspace, sequencer or CRM. Bring your own ATS.
  • There is no years-of-experience filter. Use resume_data after enrichment to read tenure.

Troubleshooting

ErrorCauseFix
401Missing, wrong or revoked keyRe-copy the key from app.leadocean.io and re-export $LEADOCEAN_API_KEY.
429Above the plan's rate limit: 5 requests a second on Free, 200 on AgencyWait the Retry-After seconds. The enrich loop above sleeps 0.3 seconds between calls.
402The free plan's 1,000 records are spentCheck GET /v1/account. Free records do not reset. See pricing for Solo at $97 a month.
Empty results or 400A filter value outside the catalogue, such as jobLevel: "CFO"Resolve it with leadocean_list_enum_values or GET /v1/enums/job_level and pass the exact string (C-Team).
Count returns unsupported_filters or a total of exactly 1,000The count tool does not support a filter such as fundingType or minRevenueCount without it. The filter still narrows the search at search time.
400 or 429 on an export400: limit is above 50,000 rows for one export. 429: the day's 500,000 rows are spentSplit the pool by country or headcount band, or wait for resetsAt.

FAQ

How many records does a longlist cost?

One record per person returned. The example spends about 40: 20 for the search page, 20 for enrichment. Sizing is free, so you know the cost before you start. Paid plans have a fair-use pace instead of a per-record price. See pricing.

How fresh is the data?

The dataset refreshes monthly, and each record has its own fetched_at date. That is not live. For a name you will put in front of a client, confirm the current role yourself.

Can I get career history for a longlist?

Yes, after enrichment. resume_data returns past roles, education, certifications and awards, each when we hold it. Search rows do not include it.

Can I run this from Claude?

Yes. The hosted MCP server has 13 tools, and counts and filter lookups are free. Read the B2B database MCP guide for setup.

What else should I compare?

Build your first executive search longlist, free

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

Get your free API key →