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

How-to

How to Add Emails and Phone Numbers to LinkedIn Prospects (API)

Six calls take you from a LinkedIn URL or a filter to a mailable, callable list. Each one has a request you can paste.

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

TL;DR

  • Six API calls cover the job: size a list, search it, enrich a LinkedIn URL, pull a phone, export in bulk, check status.
  • It takes about 20 minutes. Sizing costs 0 records. Each enrichment or returned row costs 1 record, and the free plan has 1,000.
  • Send the linkedin_url to POST /v1/people/enrich with reveal_email set to true. The email and phones come back in one record.

This is the short version. For a wider tool comparison, read 8 contact enrichment tools that find emails and phone numbers fast.

Prerequisites

  • A LeadOcean account. The free plan needs no card: 1,000 records, 5 requests a second.
  • An API key from app.leadocean.io, exported as $LEADOCEAN_API_KEY.
  • curl and jq, or any HTTP client.
  • A list of LinkedIn profile URLs, or a target audience you can describe with filters.

Step 1: Size the audience for free

Count before you spend. A count call returns the total and costs 0 records.

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}'

count=true goes in the query string, not the JSON body. limit 1 goes in the body. meta.total is capped at 100,000, and the data array comes back empty with meta.countOnly true. Enum values are exact strings. Check them with GET /v1/enums if a filter returns nothing.

Step 2: Search for the people

Search returns profiles and email flags, not addresses. The body is flat JSON, filters are arrays, and limit runs from 1 to 100.

bash
curl -s 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":25}' \
  | jq '.meta.nextCursor'

Pass the returned nextCursor back as cursor to get the next page. One search pages to 10,000 rows. Past that, meta.depthCapped is true, so narrow the filters. Each returned person costs 1 record.

Step 3: Enrich one LinkedIn URL

This is the call most LinkedIn prospecting needs. Send exactly one identifier: linkedin_url, email, phone or person_id.

bash
curl -s 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}'

reveal_email returns every email and phone held for the person at no extra record. The enrichment costs 1 record. A person we hold nothing for returns 404 and costs nothing. There is no name plus domain lookup: search by domain first, then enrich by person_id.

Step 4: Pull a phone number on its own

If you have a profile URL or a person_id and only want the phone, call the phone endpoint. It takes exactly one of linkedin_url or person_id.

bash
curl -s -G "https://api.leadocean.io/v2/people/phone" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "linkedin_url=https://www.linkedin.com/in/jane-doe-example"

The answer is data.phones, best first, each with phone and type, and found: false when we hold none.

The v2 contact endpoints cost one record per call, including a call that finds nothing. Use them when you know the person is in the data. Use enrich when you are not sure. For the reverse direction, see find email from phone number.

Step 5: Export the whole list as CSV

For hundreds or thousands of rows, export instead of looping. An export takes up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on the free plan.

bash
curl -s https://api.leadocean.io/v1/exports \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"filters":{"jobLevel":["VP"],"jobFunction":["Sales & Business Development"],"country":["CA"]},"limit":5000,"preset":"full"}'

The body takes the people search filters under filters, a row limit and a column preset (full includes emails and phones). Poll GET /v1/exports/{id}, then download from GET /v1/exports/{id}/download.

You can also do this in the app at app.leadocean.io: the Exports page has a filter builder, a column picker and a price preview before you start. Numbered columns come back as email_1_address, email_1_status and phone_1_number.

Step 6: Check email status before you send

Read email_status on every row. The mailable values are verified, catch_all_valid and catch_all. LeadOcean does not refund bounced emails, so filter before the sequencer sees the list.

bash
curl -s https://api.leadocean.io/v1/people/search \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"jobLevel":["VP"],"country":["CA"],"emailStatus":["verified"],"hasPhone":true,"limit":25}'

Your outreach tool (a sequencer, a CRM, a dialer) is separate. LeadOcean supplies the data and does not run the sequence.

What you get

A free sizing run through the MCP tool leadocean_count_leads on 2026-10-21, filters jobLevel VP, jobFunction Sales & Business Development, country CA:

json
{
  "total": 5574,
  "totalIsExact": true,
  "totalAll": 18800,
  "distinctCompanies": 3873,
  "credits": 0
}

total counts mailable people (verified, catch_all_valid or catch_all). totalAll is the same filters with no email condition. The call spent 0 records.

An enrichment response has this shape (response shape from the API reference, placeholder values):

json
{
  "success": true,
  "data": {
    "profile_data": { "...": "name, headline, location" },
    "contact_data": { "...": "emails, contact_phones[].phone" },
    "resume_data": { "experiences": [], "educations": [] }
  },
  "meta": { "credits": 1, "key_hash": "..." }
}

Since October 2026, resume_data carries past roles, education and certifications when held. Past employers have no company_id yet.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-keyCheck $LEADOCEAN_API_KEY is exported and the header name is exact
429Above the plan's rate limit (5 a second on Free, 200 on Agency)Honor Retry-After, or move to a higher plan
402The 1,000 Free records are spentUpgrade at pricing. Paid plans slow down at their pace instead of stopping.
Empty resultsEnum value has the wrong case or spellingLook it up in GET /v1/enums, for example VP, not vp
404 on enrichNothing held for that identifierFree. Try email or search by domain and use person_id
Export refusedOver 50,000 rows a request or 500,000 a day, or on FreeSplit the request, or use a paid plan

FAQ

Can I get a phone number from a LinkedIn URL?

Yes. Enrich the linkedin_url with reveal_email true, and phones come back in contact_phones[].phone when held. Use GET /v2/people/phone for the phone alone.

How many records does this spend?

Sizing is free. Enrichment and each returned search row cost 1 record. A 404 costs nothing. Enriching 50 profiles spends at most 50 of your 1,000 free records.

Does LeadOcean scrape LinkedIn live?

No. It answers from its own dataset, which is refreshed monthly. Each record carries its own fetched_at date. For removal of your own number from LinkedIn, see the privacy guide.

Can an AI agent run these calls?

Yes. The hosted MCP server at https://api.leadocean.io/mcp exposes 13 tools, including free leadocean_count_leads and leadocean_list_enum_values.

What does it cost at volume?

Solo is $97 a month, Agency is $497 a month. Paid plans have a fair-use pace, not credits. See pricing.

Turn your LinkedIn list into emails and phones

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

Get your free API key →