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

How-to guide

How to Enrich a Profile (Search, Enrich and Verify With the LeadOcean API)

Profile enrichment is one identifier in, one full person record out. Here are the three calls, the output shape and what each one costs.

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

TL;DR

  • Profile enrichment takes one identifier (a LinkedIn URL, an email, a phone number or a person_id) and returns the person's role, employer, contact points and career history.
  • It takes about 15 minutes and spends about 4 records. Sizing the list first, and any enrichment that finds nobody, cost nothing.
  • You will count a list, search it, enrich one person by person_id and read the fields you can trust.

Prerequisites

  • A LeadOcean account. The free plan gives you 1,000 records for life, no card, 5 requests a second. Start free.
  • An API key from app.leadocean.io, exported as $LEADOCEAN_API_KEY.
  • curl and jq.
  • Placeholder values below (Acme, acme.com, Jane Doe) stand in for your own data.

What profile enrichment is

Profile enrichment is a lookup. You hold a thin record, such as a name on a LinkedIn URL, and the API fills in the rest: current title, employer, seniority, email status, phones and past roles.

The identifier is the key. LeadOcean takes exactly one of linkedin_url, email, phone or person_id. There is no name plus domain lookup. If you only have a company and a job title, search first, then enrich the hit.

That makes the workflow three steps: size the list, search it, enrich the people you actually want. Counting is free. Search and enrich cost one record per person, so you pay only for the people you pick.

Step 1: Size the list for free

Count before you spend. Send count=true as a query parameter, never in the JSON body, and limit 1 in the body.

bash
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": ["Sales & Business Development"],
    "country": ["CA"],
    "limit": 1
  }' | jq '.meta | {total, totalIsExact, distinctCompanies, countOnly}'

The data array comes back empty and meta.countOnly is true. meta.total is capped at 100,000, so check totalIsExact before you quote it. meta.distinctCompanies tells you how many employers the matches span.

Enum values are exact strings. If you are unsure of one, call GET /v1/enums or the free MCP tool leadocean_list_enum_values first.

Step 2: Search for the people to enrich

Search returns a thin row per person and costs one record per row. Keep limit small while you test.

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": ["VP"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["CA"],
    "limit": 3
  }' > search.json

jq '.meta.nextCursor' search.json

The body is flat JSON and filters are arrays. limit runs 1 to 100, and you page with cursor: pass back exactly the meta.nextCursor string. One search pages to 10,000 rows, then meta.depthCapped is true. Narrow the filters instead of walking the index.

Each row carries meta.source_ids.person_id. About a fifth of the people search finds have no LinkedIn URL, and search rows carry email flags, not addresses. The person_id lets you enrich them anyway.

Step 3: Enrich one person by person_id

Send the id from the search row. Add reveal_email to get the addresses and phones we hold. It costs no extra record.

bash
PERSON_ID=$(jq -r '.data[0].meta.source_ids.person_id' search.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\": \"$PERSON_ID\", \"reveal_email\": true}" \
  | jq .

You can enrich from the identifier you already hold instead:

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 '{"linkedin_url": "https://www.linkedin.com/in/jane-doe-example", "reveal_email": true}'

Send one identifier per call. A person we hold nothing for returns a 404 and costs nothing.

Step 4: Read the fields you can trust

Check contact_data.email_status before you send anything. LeadOcean does not refund bounces.

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 '{"email": "jane.doe@acme.com", "reveal_email": true}' \
  | jq '.data.contact_data | {has_email, has_phone, email_status, email_type}'

Treat verified as sendable. catch_all_valid and catch_all are mailable but riskier. risky, unknown, invalid, role, disposable and spam_trap are not.

Since October 2026 the same call returns resume_data: past roles, education, certifications and awards, each when held. Past employers do not carry a company_id yet, so you cannot join them to company records.

When to enrich, and when not to

Enrich late. A search row is enough to qualify a person by title, level, country and employer. Spend the enrichment record only on people who pass that filter.

Enrich on a trigger, not on a schedule. A new signup, a form fill or a CRM record with only an email are good triggers. Re-enriching a whole table every week spends records on people who did not change.

Do not expect a lookup from a name alone. The call needs an identifier. A name without a LinkedIn URL, email, phone or person_id gets you nothing.

How the three calls differ

CallInputReturnsRecords
Count (count=true, limit 1)FiltersA total and breakdowns0
SearchFiltersThin rows with a person_id1 per row
EnrichOne identifierThe full person record1 per person found

The pattern is count, search, enrich. Count tells you whether the list is worth building. Search gives you the ids. Enrich reads the people you picked.

What you get

This is the response shape from the API reference, with placeholder values. It is not a real person.

json
{
  "success": true,
  "data": {
    "profile_data": { "...": "name, headline, location" },
    "contact_data": {
      "contact_emails": [ { "...": "address, status" } ],
      "contact_phones": [ { "phone": "+1 415 555 0133" } ],
      "has_email": true,
      "has_phone": true,
      "email_status": "verified",
      "email_type": "work",
      "contact_current_experiences": [ { "...": "title, company, dates" } ]
    },
    "resume_data": { "...": "past roles, educations, certifications, awards" },
    "meta": {}
  },
  "meta": { "source": "leadocean" }
}

contact_emails and contact_phones appear only when you send reveal_email. has_email and has_phone always appear, so you can see whether a contact exists before you ask for it. The current role sits in contact_current_experiences, past roles in resume_data.

Doing it from an AI client

The hosted MCP server at https://api.leadocean.io/mcp signs in with OAuth, so no key is pasted. It exposes 13 tools. For this workflow:

  • leadocean_count_leads sizes a people list for free.
  • leadocean_search_leads returns rows, one record each.
  • leadocean_get_lead enriches one person, one record. A miss costs nothing.

Ask your client for "count VPs of sales in Canada, then enrich the first three". It will count first, because the count is free. For companies, leadocean_count_companies does the same for free.

Doing it in bulk

For thousands of profiles, do not loop enrich calls. Export instead. POST /v1/exports takes up to 50,000 rows a request and 500,000 a day. The Exports page in app.leadocean.io has a filter builder, a column picker and a price preview before you start. Bulk CSV export is not on the Free plan. See plans.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCheck $LEADOCEAN_API_KEY is exported and the header is x-api-key.
402Records spent. Free is 1,000 for lifeUpgrade to Solo ($97 a month) or Agency ($497 a month). A 402 costs nothing.
429Above the plan's rate limit: 5 a second on Free, 200 on AgencyWait for Retry-After, then retry. Space calls out or move up a plan.
404 on enrichWe hold nothing for that identifier, or nothing we can enrich byTry another identifier. A 404 is free and will not change on a retry.
Empty search resultsA bad enum value, such as VP spelled as vpCall GET /v1/enums and copy the exact string.
Invalid cursor (400)Edited, stored or reused cursorPass back meta.nextCursor unchanged, or restart the query.

FAQ

What is the difference between profile enrichment and company enrichment?

Profile enrichment adds person-level data: title, seniority, contact points, career history. Company enrichment adds firmographics: industry, headcount, HQ. See company enrichment. LeadOcean has a separate endpoint for each: /v1/people/enrich and /v1/companies/enrich.

Can I enrich from a name and a company?

No. There is no name plus domain lookup. Search by domain or filters first, then enrich by person_id.

How many records does an enrichment cost?

One, when it finds a person. A 404 costs nothing. reveal_email adds every email and phone we hold at no extra record. See pricing.

How is this different from a lead enrichment API?

It is the same idea at a narrower scope: a lead enrichment API may append firmographics, scores and intent as well. See lead enrichment APIs.

Can an agent run this?

Yes, through the MCP tools above. See RevOps AI agents. Keep the free count call first in the loop so the agent sizes before it spends. More guides are on the blog.

Enrich your first profile with a free API key

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

Get your free API key →