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

How-to guide

How to get phone numbers at scale for cold calling (API recipe)

Size the segment for free, filter to people with a number on file, then pay only for the rows you will dial.

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

Getting phone numbers at scale takes four calls: size the segment, filter to people who have a number, look up the numbers, export the list. Sizing is free. You pay one record for each person you actually pull.

TL;DR

  • Use hasPhone: true in a search so you never pay for people without a number. Size the segment first with a free count.
  • Takes about 20 minutes. The test pass spends about 110 records of the 1,000 on the Free plan. Bulk CSV export needs Solo ($97 a month) or above.
  • Pull one number with GET /v2/people/phone, or pull thousands at once with POST /v1/exports (up to 50,000 rows a request, 500,000 a day).

Prerequisites

  • A LeadOcean API key in $LEADOCEAN_API_KEY. The Free plan gives you one, with 1,000 records for life and no card.
  • curl and jq.
  • A number to start from: a job level, a function and a country.

Step 1: Size the segment for free

Count first. A count spends no records, so run it as often as you like.

bash
curl -s "https://api.leadocean.io/v1/people/search?count=true&limit=1" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jobLevel": ["VP", "Director"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["US"],
    "hasPhone": true
  }' | jq '.meta'

count=true goes in the query string, not the body. meta.total is capped at 100,000 on this route, so use the MCP tool leadocean_count_leads when you want the exact figure. Filters are flat arrays. Enum values are exact strings, so check them with leadocean_list_enum_values before you guess.

Step 2: Search for people who have a number

Add limit (1 to 100) and page with cursor. Each person returned is one record.

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", "Director"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["US"],
    "hasPhone": true,
    "limit": 100
  }' > page1.json

jq '.meta.nextCursor' page1.json

Pass nextCursor back as cursor for the next page. One search pages to 10,000 rows. When meta.depthCapped is true, narrow the filters (add a title, a company size or a city) instead of walking deeper. Test with 100 rows before you scale.

Step 3: Look up the numbers

A search row says a number exists. The phone endpoint returns it. Send the person id from the search row.

bash
curl -s "https://api.leadocean.io/v2/people/phone?person_id=PERSON_ID" \
  -H "x-api-key: $LEADOCEAN_API_KEY"

It costs one record per call, including a call that finds nothing, so filter with hasPhone first. Numbers come back best first, and the array position is the priority. Each number has a phone and a type such as mobile, direct or office. Treat an unfamiliar type as unknown.

The v2 response carries no do-not-call flag. Scrub every number against your own DNC lists before you dial.

Step 4: Export the whole list as CSV

For thousands of rows, skip the per-person loop. One export call writes the CSV for you.

bash
curl -s https://api.leadocean.io/v1/exports \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "us-sales-leaders-with-phone",
    "filters": {
      "jobLevel": ["VP", "Director"],
      "jobFunction": ["Sales & Business Development"],
      "country": ["US"],
      "hasPhone": true
    },
    "limit": 5000,
    "preset": "full",
    "reveal": "email_phone"
  }'

The full preset has phones 1 and 2 as phone_1_number and phone_2_number. Poll GET /v1/exports/{id}, then fetch GET /v1/exports/{id}/download. Each row written is one record. The ceilings are 50,000 rows an export and 500,000 a day. You can run the same export from the Exports page in the app (app.leadocean.io), which shows the record price before you start.

Step 5: Feed the dialer

LeadOcean has no dialer or sequencer. Load the CSV into the tool your reps already use. Keep the phone_1_number column as the first dial and phone_2_number as the fallback. Re-run the export on a schedule, since the dataset refreshes monthly and each record carries its own fetched_at date.

What you get

Here is a free count run on 2026-10-21 with the MCP tool leadocean_count_leads. It filtered on job level VP or Director, job function Sales & Business Development, country US and hasPhone true. It spent no records.

json
{
  "total": 864742,
  "totalIsExact": true,
  "distinctCompanies": 296626,
  "credits": 0
}

That is a count of people with a phone number on file, not a mailable count and not a promise that every number connects.

The phone lookup returns this shape (response shape from the API reference, placeholder values):

json
{
  "success": true,
  "data": {
    "person_id": "1234567890",
    "found": true,
    "phones": [
      { "phone": "+1 415 555 0133", "type": "mobile" },
      { "phone": "+1 415 555 0199", "type": "office" }
    ],
    "best": { "phone": "+1 415 555 0133", "type": "mobile" }
  }
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-keyCheck $LEADOCEAN_API_KEY is exported and sent in the header.
429Above your plan's rate limit (5 a second on Free, 50 on Solo, 200 on Agency)Honour Retry-After, or slow the loop. Use an export for volume.
402Out of recordsFree is 1,000 for life. Move to a paid plan, or shrink the limit.
Empty resultsA bad enum value, such as "vp" instead of "VP"List the exact strings with leadocean_list_enum_values.
400 on exportOver 50,000 rows, or a filter that cannot be appliedSplit into several exports. Drop the unsupported filter.
429 on exportDaily or period export ceilingWait for resetsAt in the response.

FAQ

How many phone numbers can I get in one go?

One export holds up to 50,000 rows, and an account can export 500,000 rows a day. A single search pages to 10,000 rows.

Do I pay for people without a phone number?

Not if you filter with hasPhone: true. Counts are free. A phone lookup that finds nothing still costs one record, so filter first.

Can I do this on the Free plan?

You can size, search and look up numbers inside the 1,000 records. Bulk CSV export is not on Free. Solo at $97 a month includes it. See pricing.

Are the numbers safe to dial?

The v2 phone response has no do-not-call field. Scrub against your own lists and the rules for the countries you call.

Where do I go next?

To compare vendors, read best phone number finder tools. For a bought list, see how to buy a phone numbers list. For LinkedIn profiles without an extension, see how to get phone numbers from LinkedIn safely.

Pull your first 100 phone numbers free

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

Get your free API key →