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

How-to guide

How to Find Someone's LinkedIn Profile From a Phone Number (API Reverse Lookup)

Send a phone number, get back a name, a title, a company and a LinkedIn URL. One call, one record, and a free miss when you use enrich.

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

You find a LinkedIn profile from a phone number by looking the number up in a database that links phones to profiles. This guide does not use LinkedIn's own search. The lookup runs in a separate dataset that stores the link between a phone and a profile.

This guide uses the LeadOcean reverse lookup. You send the number and get back the person it belongs to, including the linkedin_url.

TL;DR

  • Send the number to GET /v2/people/reverse and read linkedin_url from the response. It takes about 5 minutes the first time.
  • Each lookup spends 1 LeadOcean record, including a lookup that finds nobody. Enrich with phone spends 1 record per match and nothing on a 404.
  • It only works for numbers LeadOcean holds. A miss is a normal result, not an error in your request.

Prerequisites

  • A LeadOcean account from app.leadocean.io. The free plan has no card and 1,000 records for life.
  • curl and jq.
  • An API key in your shell as $LEADOCEAN_API_KEY. Free keys get both scopes, search and enrich.
  • The phone number, with a country code. The endpoint accepts common formats, and +14155550133 is the safest.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"

Step 1: Look up the number

Send the number as the phone query parameter. Send phone or email, never both. The response is the person who holds that number.

bash
curl -s -G "https://api.leadocean.io/v2/people/reverse" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "phone=+14155550133" \
  | jq '.data | {full_name, job_title, company_name, company_domain, linkedin_url, person_id}'

The + must be URL-encoded, which --data-urlencode does for you. A bare + in a query string turns into a space and the lookup fails.

This returns identity only. It costs 1 record, and it costs 1 record when nobody is found.

Step 2: Check that the match is real

A returned name is not proof that the number is theirs. Read two fields before you act on it.

bash
curl -s -G "https://api.leadocean.io/v2/people/reverse" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "phone=+14155550133" \
  | jq '{matched_in_record: .data.matched_in_record, matched: .data.matched, person_group_id: .data.person_group_id}'

matched_in_record is true when the record lists your exact number. It is false when we matched the person on the number upstream but the record does not carry it in its list. That is a weaker match: confirm the title and company before you trust it.

matched holds the number as the record stores it, with its own type, status and check date. A null there does not mean nobody was found. No person at all would have been a 404.

Step 3: Pull the full profile with enrich

Use enrich when you want more than identity: current role, career history, and the email or phone points. It takes exactly one of linkedin_url, email, phone or person_id, so send the number alone.

bash
curl -s https://api.leadocean.io/v1/people/enrich \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d '{"phone": "+14155550133"}' \
  | jq '.data | {profile_data, current: .contact_data.contact_current_experiences}'

A person we hold nothing for is a 404 and costs nothing. A match costs 1 record.

Pick one call, not both. Reverse and enrich answer from the same cached record at the same price, so running both on one number spends 2 records for the same person. Use reverse when you only need the LinkedIn URL. Use enrich when you want the profile, or when you want misses to be free.

Step 4: Run a list of numbers

Loop the same call over a file called numbers.txt, one number per line, each with a country code. Keep the loop under your plan's rate: 5 requests a second on Free, 50 on Solo, 200 on Agency.

bash
while read -r NUM; do
  printf '%s,' "$NUM"
  curl -s -G "https://api.leadocean.io/v2/people/reverse" \
    -H "x-api-key: $LEADOCEAN_API_KEY" \
    --data-urlencode "phone=$NUM" \
    | jq -r '.data.linkedin_url // "no_match"'
  sleep 0.25
done < numbers.txt > results.csv

The sleep 0.25 holds the loop near 4 requests a second, inside the Free limit. On a paid plan, shorten it or run the loop in parallel.

Because reverse bills a miss, a list of 1,000 numbers spends 1,000 records whatever the hit rate. To pay only for matches, swap the call for POST /v1/people/enrich with {"phone": "$NUM"} and read profile_data instead.

Run a dry batch of 10 numbers first. Open results.csv, count the no_match rows, and use that hit rate to decide whether the full list is worth its records. The file has two columns, the number and the profile URL, so it opens in any spreadsheet.

Before you contact anyone, check the profile URL by opening it. A phone-to-profile link is a lead, not a fact. Confirm the name, the title and the company against what you already know about the account.

Step 5: Size your list before you spend

If you are deciding whether a phone-led workflow is worth running, count the audience first. A people search with count=true as a query parameter and limit at 1 is a free sizing call. The body stays flat JSON, with arrays for filters.

bash
curl -s "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"],
    "hasPhone": true,
    "limit": 1
  }' | jq '.meta | {total, totalIsExact, credits}'

meta.total is capped at 100,000 and credits is 0. The hasPhone flag says a number exists on the record. It does not say the number is a mobile, or that it is safe to dial. Enum values are exact strings, so check them with GET /v1/enums before you filter.

Coverage is the real limit on this method. LeadOcean holds 166M people with a phone out of 693M (measured 2026-09-23). A number outside that set returns no match, whatever you do with the request.

When a lookup will miss

Most misses come from three causes. Knowing them saves records.

  • The number is a switchboard, a desk line or a personal number the person never shared with a business. These rarely link to a profile.
  • The number is old. People change numbers and jobs, and the dataset is refreshed monthly. Each record carries its own fetched_at date, so read it.
  • The format is wrong. Drop punctuation you cannot explain and always include the country code.

A miss is cheap on enrich and costs 1 record on reverse. If your hit rate is low, move the batch from Step 4 to enrich so misses are free.

What you get

The reverse lookup returns the identity block below. This is the response shape from the API reference, with placeholder values. No real person is shown.

json
{
  "success": true,
  "data": {
    "person_id": "1234567890",
    "person_group_id": "9876543210",
    "full_name": "Jane Doe",
    "job_title": "VP Sales",
    "company_name": "Acme",
    "company_domain": "acme.com",
    "linkedin_url": "https://www.linkedin.com/in/jane-doe-example",
    "query": { "phone": "+14155550133" },
    "matched": { "phone": "+14155550133", "type": "mobile" },
    "matched_in_record": true
  },
  "meta": { "credits": 1 }
}

person_id names a record. person_group_id names the person. We hold more than one record for some people, so the same human can come back under different person_id values through different contact points. Compare person_group_id to de-duplicate, and never look it up.

A number nobody holds returns a 404 with no data.

Troubleshooting

ErrorCauseFix
401Missing, wrong or revoked keyRe-copy the key from app.leadocean.io and export $LEADOCEAN_API_KEY again.
429Above the plan's rate limit: 5 requests a second on Free, 200 on AgencyWait for the Retry-After header, then slow the loop.
402The 1,000 free records are spentCheck your balance with GET /v1/account, or move to a paid plan on pricing. Free records do not reset.
404No person holds that numberTry another format with a country code, or enrich by email or linkedin_url if you have one. On enrich a 404 costs nothing.
400Both phone and email sent, or a body field the endpoint rejectsSend exactly one identifier. Enrich takes one of linkedin_url, email, phone or person_id.
linkedin_url is nullWe matched a person but hold no profile URLEnrich by person_id for the rest of the record, or search by company domain and title.

FAQ

Do I need LinkedIn's own search for this?

This guide does not cover LinkedIn's own search. The method here uses a database that stores the link between a phone and a profile, so it works from a script.

How many records does one lookup cost?

One record per reverse lookup, including a lookup that finds nobody. Enrich with phone costs one record per match and nothing on a 404. Counts and filter lookups are free.

What if I only have a name and a company?

Search by company domain and title, then enrich by person_id. There is no name plus domain lookup. The cell phone guide covers that route in full.

Does this work in the other direction?

Yes. Enrich takes a linkedin_url and returns the contact points we hold when you set reveal_email to true. The find phone number enrichment page shows the call.

Can Claude run this lookup for me?

Yes, through the hosted MCP server. The find phone number Claude skill wraps the phone tools and spends 1 record a run.

Look up a LinkedIn profile from a phone number, free

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

Get your free API key →