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

How-to guide

How to build a rep prospecting list (territory to first call)

Size a territory for free, pull the people, and enrich one contact before the call. Four requests, about 20 minutes.

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

A rep needs three things: a sized territory, a ranked list of people, and one enriched contact before each call. You can get all three from four API requests, and sizing costs nothing.

Clay pitches this as waterfall enrichment across many providers, a Chrome extension partner (Exportly) and pushes to a CRM or sequencer (Clay rep prospecting page, October 2026). LeadOcean has none of those tools. It is the data layer, so this guide is for the rep or RevOps engineer who wants the list as JSON or CSV.

TL;DR

  • Total time: about 20 minutes. The example territory is IT directors and VPs at German companies with 201-500 employees.
  • Records spent: about 101. The count is free, one search page of 100 is 100 records, and one enrichment is 1 record.
  • The Free plan (1,000 records for life, no card) covers it with 899 records to spare.

Prerequisites

  • A LeadOcean API key from app.leadocean.io/register, exported as $LEADOCEAN_API_KEY.
  • curl and jq.
  • A territory written as filters: country, job level, job function, company size.

Step 1: Size the territory (free)

Send count=true as a query parameter with limit=1. The call returns a total and spends no records. The body is flat JSON and every filter is an array.

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 '{
    "country": ["DE"],
    "jobLevel": ["VP", "Director"],
    "jobFunction": ["Information Technology"],
    "employeeRange": ["201-500"]
  }' | jq '.meta'

meta.total is capped at 100,000. If the number is too big for one rep, add a filter. If it is zero, check the enum spelling (see Troubleshooting).

You can run the same count from an AI client with the leadocean_count_leads MCP tool. For the account side, leadocean_count_companies sizes the company list for free.

Step 2: Pull the first page of people

Now spend records. limit runs 1 to 100, so one page of 100 costs 100 records.

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 '{
    "country": ["DE"],
    "jobLevel": ["VP", "Director"],
    "jobFunction": ["Information Technology"],
    "employeeRange": ["201-500"],
    "limit": 100
  }' > page1.json

jq '.meta, (.data | length)' page1.json
jq -r '.data[].meta.source_ids.person_id' page1.json > ids.txt

Check the length before you read rows. Only people you receive count. This body has no email condition, so it returns people with and without a mailable address. Add "emailStatus": ["verified", "catch_all_valid", "catch_all"] to pull only the mailable ones.

Step 3: Page through with a cursor

Take the cursor from the last response and send it back with the same filters.

bash
CURSOR=$(jq -r '.meta.nextCursor // empty' page1.json)

curl -s -X POST "https://api.leadocean.io/v1/people/search" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"country\": [\"DE\"],
    \"jobLevel\": [\"VP\", \"Director\"],
    \"jobFunction\": [\"Information Technology\"],
    \"employeeRange\": [\"201-500\"],
    \"limit\": 100,
    \"cursor\": \"$CURSOR\"
  }" > page2.json

One search pages to 10,000 rows. The last page sets meta.depthCapped to true and has no cursor. Narrow the filters instead of walking the index. For a CSV of the whole list, use the Exports page in app.leadocean.io (filter builder, column picker, price preview, download). Bulk CSV export is not on Free.

Step 4: Enrich one contact before the call

Enrich takes exactly one of linkedin_url, email, phone or person_id. Take a person_id from ids.txt (each search row carries it at meta.source_ids.person_id). Set reveal_email to get the address back.

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_STEP_2", "reveal_email": true}' \
  | jq '{role: .data.contact_data.contact_current_experiences, history: .data.resume_data, status: .data.contact_data.email_status}'

Since 2026-10-17 the response includes career history: past roles, education, certifications and awards. Past employers carry no company_id yet. An enrichment that finds nobody is a 404 and costs nothing. A phone number is a separate call to GET /v2/people/phone, and v2 contact calls cost one record each, including a miss.

What you get

The territory count, run with the free leadocean_count_leads MCP tool on 2026-10-21 (mailable people only, the tool default of verified, catch_all_valid and catch_all):

json
{
  "filters": "country DE, jobLevel VP or Director, jobFunction Information Technology, employeeRange 201-500",
  "total": 208,
  "totalIsExact": true,
  "totalAll": 679,
  "distinctCompanies": 189
}

So 208 people with a mailable address across 189 employers. totalAll (679) is the same filters with no email condition.

The company side, from the free leadocean_count_companies tool on 2026-10-21: companies headquartered in Germany with 201-500 employees and at least one person with a mailable address number 3,221. The top industry is IT Services and IT Consulting at 193, then Software Development at 115.

A search response has this shape (response shape from the API reference, placeholder values):

json
{
  "success": true,
  "data": [
    {
      "profile_data": { "profile_full_name": "Jane Doe" },
      "contact_data": {
        "has_email": true,
        "email_status": "verified",
        "contact_current_experiences": [{ "company_name": "Acme" }]
      },
      "resume_data": {},
      "meta": { "source_ids": { "person_id": "1234567890" } }
    }
  ],
  "meta": { "count": 1, "limit": 100, "nextCursor": "...", "depthCapped": false }
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCheck $LEADOCEAN_API_KEY is exported and sent in the x-api-key header
429Above the plan's rate limit (5 requests a second on Free, 200 on Agency)Honor the Retry-After header and slow the loop
402Out of records (Free is 1,000 for life)Move to Solo ($97 a month) or Agency ($497 a month). A 402 costs nothing
Empty resultsEnum value spelled wrong, such as "vp" instead of "VP"Check exact values with leadocean_list_enum_values or GET /v1/enums
meta.depthCapped is trueOne search reached 10,000 rowsAdd filters and split the territory
Export refusedOver 50,000 rows a request or 500,000 a day, or on FreeSplit the export; bulk CSV is not on Free

FAQ

How many records does a rep list cost?

One record per person you receive. The example filters match 679 people, 208 of them mailable. Pulling only the mailable ones costs about 208 records. Counts, breakdowns and empty pages are free.

Can a rep use this without writing code?

Yes, partly. The Exports page in app.leadocean.io builds the filter, shows the record price first, and downloads a CSV. The CSV then goes to your own tools.

How is this different from Clay's rep workflow?

Clay chains multiple providers and pushes to a CRM or sequencer from one workspace. LeadOcean is one data source behind one API with flat pricing. If you already have a sending tool and want the list, the API is shorter. See integrations and customization.

How do I find more accounts like my best customers?

Start from the filters your best accounts share and widen one at a time. The lookalike prospecting guide covers it.

Size your territory free, then pull the list

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

Get your free API key →