A lead enrichment API takes one identifier you already hold (an email, a LinkedIn URL, a phone number) and returns the full record for that person: title, employer, location, career history and contact points. You send one request. You get one record back.
That is the whole idea. The rest of this page shows the calls, the output and what each one costs in LeadOcean records.
TL;DR
- Enrichment is a lookup. You give one identifier, the API returns one person. In LeadOcean that is
POST /v1/people/enrich. - The full loop takes about 20 minutes: size a list for free, search it, enrich the rows you want.
- It spends about 3 records. Counts are free, and an enrich call that finds nobody returns a 404 and costs nothing.
Prerequisites
- A LeadOcean account on the Free plan: 1,000 records for life, no card, 5 requests a second. Register at
https://app.leadocean.io/register. - An API key from the app, exported as
$LEADOCEAN_API_KEY. curlandjq. Any HTTP client works the same way.
export LEADOCEAN_API_KEY="paste-your-key-here"Step 1: Understand what goes in and what comes out
An enrichment API has one job: map a thin input to a rich record. LeadOcean accepts exactly one of four inputs per call.
| Input | Parameter | Use it when |
|---|---|---|
| Work or personal email | email | You have a form fill or a CSV of addresses |
| LinkedIn profile URL | linkedin_url | You scraped or exported profiles |
| Phone number, any format | phone | You have an inbound call or a dialer log |
| LeadOcean person ID | person_id | You found the person with search first |
There is no name plus domain lookup. If you only have a name and a company, search by domain first, then enrich by person_id. Steps 2 and 3 do that.
Step 2: Size the list before you spend anything
Count first. A count call is free and tells you how many people match before you pull a single row.
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"],
"country": ["US"],
"limit": 1
}' | jq '.meta | {total, totalIsExact, distinctCompanies}'count=true goes in the query string, not the JSON body, because the body rejects unknown fields. meta.total is capped at 100,000, and data comes back empty with meta.countOnly true.
The MCP tool leadocean_count_leads does the same thing from Claude or ChatGPT. For companies, GET /v1/companies/count and the tool leadocean_count_companies are also free.
Step 3: Search to get identifiers
Search returns rows that carry a person_id. The body is flat JSON, filters are arrays, and limit runs from 1 to 100.
curl -s -X POST "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": ["acme.com"],
"jobLevel": ["VP", "C-Team"],
"limit": 2
}' | jq '{rows: (.data | length), person_id: .data[0].meta.source_ids.person_id}'This costs 2 records, one per person returned. To page further, pass the cursor from the previous response. One search pages to 10,000 rows. The last page sets meta.depthCapped to true and has no nextCursor, so narrow the filters instead of walking the index.
Enum values are exact strings. Check them with leadocean_list_enum_values or GET /v1/enums before you filter, or the query returns nothing.
Step 4: Enrich one person
Now send the ID back to the enrich endpoint. This is the call the whole page is named after.
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_3",
"reveal_email": true
}'You can also enrich from an email you already hold:
curl -s -X POST "https://api.leadocean.io/v1/people/enrich" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "jane.doe@acme.com"}'An enrich call costs one record. reveal_email returns every email and phone we hold at no extra record. Without it you still get has_email and has_phone flags, so you can see what exists before you ask for it. If nobody matches, the answer is a 404 and it costs nothing.
Step 5: Know what the response holds
The enrich response has four blocks: profile_data, contact_data, resume_data and meta. Since October 2026 resume_data carries career history: past roles, educations, certifications, awards and more, each when held. Past employers do not carry a company_id yet.
Contact fields to read before you send anything:
contact_data.email_statusis the deliverability of the best address. Values includeverified,catch_all_valid,catch_all,riskyandinvalid.contact_data.email_typetells you whether the address iswork,work_other(a former employer) orpersonal.contact_data.contact_current_experiences[]holds the current role.
LeadOcean does not refund bounced emails. Read email_status first.
Step 6: Put it in a loop
For a list, run enrich per row and stop on the first 429. Keep the pace under your plan's limit: 5 requests a second on Free, 50 on Solo, 200 on Agency.
while read -r id; do
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\": \"$id\", \"reveal_email\": true}" >> enriched.jsonl
sleep 0.25
done < person_ids.txtFor thousands of rows, skip the loop. POST /v1/exports takes up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on Free, but it is included from Solo at $97 a month.
What you get
A live free count, run on 2026-10-21 through the leadocean_count_leads MCP tool, filtered to VP-level people in the US. The default counts only addresses worth sending to (verified, catch_all_valid or catch_all).
{
"total": 1242801,
"totalIsExact": true,
"totalAll": 3102417,
"distinctCompanies": 226527,
"credits": 0
}So 1,242,801 VP-level people in the US have a mailable address (verified, catch-all valid or catch-all). Without any email filter the same filters match 3,102,417. That count cost nothing.
The record shape, response shape from the API reference, with placeholder values:
{
"success": true,
"data": {
"profile_data": { "profile_full_name": "Jane Doe", "profile_headline": "VP Sales at Acme" },
"contact_data": {
"has_email": true,
"has_phone": true,
"email_status": "verified",
"email_type": "work",
"contact_emails": [{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }],
"contact_phones": [{ "phone": "+1 415 555 0133", "type": "mobile" }],
"contact_current_experiences": [
{ "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com" }
]
},
"resume_data": {
"experiences": [{ "job_title": "Director of Sales", "company_name": "Example Co" }],
"educations": [],
"certifications": []
},
"meta": { "schema": "leadocean.person.v1", "fetched_at": "2026-10-01" }
},
"meta": { "credits": 1, "source": "own" }
}contact_emails and contact_phones appear only when you send reveal_email. The names and numbers above are placeholders, not a real person.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key header | Re-copy the key from the app and check $LEADOCEAN_API_KEY is exported |
| 402 | The 1,000 free records are spent | Move to Solo at $97 a month or Agency at $497 a month |
| 404 on enrich | Nobody in the data matches the identifier | Costs nothing. Try another identifier or search by domain first |
| 429 | Requests above the plan's rate limit (5 a second on Free) | Wait for the Retry-After header, then slow the loop |
| Empty search results | A bad enum value, such as "vp" where the filter expects "VP" | List the allowed values with GET /v1/enums |
| Export refused | The request is over 50,000 rows or the 500,000 a day ceiling | Split the export across requests or days |
FAQ
What is the difference between lead enrichment and a lead search?
Search finds people who match filters. Enrichment fills in one person you already know. In LeadOcean search spends one record per person returned, and enrich spends one per match.
How much does an enrichment call cost?
One record per person found. A miss is a 404 and is free. The Free plan holds 1,000 records for life. Paid plans use a fair-use pace instead of credits.
Can I run this from Claude instead of curl?
Yes. LeadOcean runs a hosted MCP server at https://api.leadocean.io/mcp with 13 tools and OAuth sign-in, so no key is pasted. Counting is free there too.
How fresh is the data?
The dataset is refreshed monthly. Each record also carries its own fetched_at date.
What should I read next?
Read the company version in what company enrichment is, the field-level view in profile enrichment, and the tool roundup in best lead enrichment tools. Plans are on pricing.
Enrich your first lead with a free API key
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →