TL;DR
- Go API-first if your data feeds code: enrichment on signup, scoring, your own tables, agents. Go platform-first if humans work lists in a UI every day.
- The test takes about 30 minutes: one free count, one 5-row search, one enrichment, one export price preview.
- It spends about 6 LeadOcean records, well inside the 1,000 on the Free plan.
Prerequisites
- A LeadOcean account on the Free plan:
https://app.leadocean.io/register. No card. - An API key from the app, exported as
$LEADOCEAN_API_KEY. curlandjq.- Optional: an MCP client such as Claude Code, to run the same count as a tool call.
- A target list in one sentence. Example: VPs of Engineering in the US.
Step 1: Size the list before you pick anything
Your list size and refresh rate decide the architecture, so measure them first. A count is free on every plan.
curl -s -X POST "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":["Engineering"],"country":["US"],"limit":1}' | jq .metacount=true goes in the query string, not the JSON body; limit 1 goes in the body. The body is flat, and every filter is an array. meta.total is capped at 100,000.
Write down two numbers: rows now, and rows you will pull each month. Under a few thousand rows a month that nobody edits in code, a platform is fine. Above that, or when code reads the result, lean API.
Step 2: Pull a 5-row sample through the API
An API-first flow is a loop your code owns: filter, page, store. Test the loop with five rows.
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": ["Engineering"],
"country": ["US"],
"limit": 5
}' | tee page1.json | jq '.meta'This spends 5 records. Page size runs from 1 to 100. To get the next page, pass meta.nextCursor back as cursor.
One search pages to 10,000 rows. When meta.depthCapped is true, there is no nextCursor. Narrow the filters instead of walking further.
Check what your code would need to handle here: pagination, the depth cap, retries on 429. If that list feels like a chore, that is a signal for a platform. If it feels like twenty lines, stay API-first.
Step 3: Enrich one person by ID
Enrichment is the call most pipelines hit first. It takes exactly one of linkedin_url, email, phone or person_id.
PID=$(jq -r '.data[0].meta.source_ids.person_id' page1.json)
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\":\"$PID\",\"reveal_email\":true}" | jq 'keys'This spends 1 record. A person we hold nothing for returns 404 and costs nothing. Since October 2026 the response also carries career history (resume_data): past roles, education, certifications and awards.
There is no name plus domain lookup. Search by domain first, then enrich by person_id.
Step 4: Price the platform path with an export
Platform-first means a person picks filters in a UI and downloads a file. LeadOcean's app has this on its Exports page: filter builder, column picker, record price before you start, CSV download.
- Sign in at
https://app.leadocean.ioand open Exports. - Set the same three filters: job level VP, function Engineering, country US.
- Pick columns. Email columns are
email_N_addressandemail_N_status. - Read the price preview. Do not download on the Free plan: bulk CSV export is not included there.
The same job over the API is POST /v1/exports. It takes up to 50,000 rows a request and 500,000 a day.
LeadOcean is not a rep workspace. It has no sequencer, dialer or CRM. If your team needs those, pair LeadOcean with a tool that has them. To work lists in a table instead, see LeadOcean + Clay.
Step 5: Apply the decision rule
Score your answers from steps 1 to 4. Do not average them. One hard "code reads this" outweighs three soft platform wins.
| Question | Answer says API-first | Answer says platform-first |
|---|---|---|
| Who touches the list? | A service, a cron job or an agent | A rep or marketer in a UI |
| How often does it change? | Daily or on every signup | Weekly or per campaign |
| Where does the data end up? | Your database or product | A CSV, then a sequencer |
| Who maintains it? | An engineer on your team | Nobody wants to |
| What must be auditable? | Request logs and your own schema | A saved view someone can reopen |
My rule: three or more rows in the left column, go API-first. Two or fewer, start with exports and add the API when a script appears.
Most technical teams end up hybrid. Exports for the one-off list, the API for anything a user triggers. Both draw from the same data on the same plan, so you do not choose once.
On cost, LeadOcean has one data set on every plan. Free is 1,000 records for life. Solo is $97 a month (50 requests a second). Agency is $497 a month (200 requests a second, 5 keys). Platform is $1,997 a month for embedding and reselling. Paid plans use a fair-use pace, not credits. See pricing.
What you get
Step 1 as an MCP count on 2026-10-21, using leadocean_count_leads with jobLevel VP, jobFunction Engineering, country US. The count defaults to mailable addresses (verified, catch_all_valid or catch_all):
{
"total": 25784,
"totalIsExact": true,
"totalAll": 54103,
"distinctCompanies": 11896,
"credits": 0
}So 25,784 mailable people at 11,896 companies, out of 54,103 matching people with no email condition. It cost 0 records.
Step 2 returns this shape (response shape from the API reference, placeholder values):
{
"data": [
{
"profile_data": { "profile_full_name": "Jane Doe" },
"contact_data": { "has_email": true, "email_status": "verified" },
"resume_data": { "<current role and company>": "<values>" },
"meta": { "source_ids": { "person_id": "<digits>" } }
}
],
"meta": { "count": 5, "limit": 5, "credits": 5, "nextCursor": "<cursor>" }
}For more on what these APIs return, read what a B2B data API is.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key header | Re-copy the key from the app. Check $LEADOCEAN_API_KEY is exported in this shell. |
| 429 | Above the plan's rate limit (5 a second on Free, 200 on Agency) | Wait for Retry-After, or throttle the loop. |
| 402 | Out of records on the Free plan | Upgrade, or narrow the test. A 404 and an empty page cost nothing. |
| Empty results on a valid filter | Enum value is not an exact string, such as vp for jobLevel | Use VP, C-Team, Director. Check leadocean_list_enum_values or GET /v1/enums. |
| 400 on the count call | count=true sent in the JSON body | Move it to the query string. The body rejects unknown fields. |
| Export refused | Over 50,000 rows a request, or 500,000 a day | Split by filter, for example by country, and run again the next day. |
FAQ
Is API-first cheaper than platform-first?
Not by default. The API saves engineer time only when code consumes the data. For a list a marketer reviews weekly, an export is cheaper to run. Price both with your real row counts from step 1.
Can I start platform-first and move to the API later?
Yes. Keep the filters you used in the Exports page and send them as a flat JSON body to the search endpoint. The data is the same, so nothing needs re-cleaning.
Does LeadOcean replace my CRM or sequencer?
No. LeadOcean is data: search, enrichment, exports and an MCP server with 13 tools. Pair it with the CRM or sequencer you already run.
How do I compare providers before committing?
Run steps 1 to 3 against each one on the same list and compare counts, fill rate and cost per row. Our roundups cover providers with an API and the best B2B data APIs.
Test your data strategy on a real list. Start free.
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →