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

How-to guide

How to Run B2B Data Sales With an API (Size, Pull, Enrich, Export)

Four calls take you from a target profile to a clean list. Sizing is free, and the whole recipe spends about 30 records.

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

B2B data sales means picking an audience, checking it is big enough, and pulling only the rows you will contact. This guide does that with four calls against the LeadOcean API.

TL;DR

  • Size the list first with a free count, then spend records only on the page you need.
  • Takes about 30 minutes and spends about 30 records, well inside the Free plan's 1,000 records for life.
  • Sizing, filter lookups and a 404 enrich cost nothing. A search page of 25 costs 25 records.

Prerequisites

  • A LeadOcean API key from app.leadocean.io. The Free plan needs no card.
  • The key exported as an environment variable: export LEADOCEAN_API_KEY=...
  • curl and jq.
  • Free rate limit: 5 requests a second. Agency allows 200. Check pricing for your plan.

Step 1: Define the profile with exact filter values

Write the profile as filters before you touch the API. Enum filters take exact strings, so a typo returns nothing.

bash
curl -s "https://api.leadocean.io/v1/enums" \
  -H "x-api-key: $LEADOCEAN_API_KEY" | jq 'keys'

Our profile: VPs of Sales & Business Development, in the US, at companies with 51-200 employees. In filter terms that is jobLevel: ["VP"], jobFunction: ["Sales & Business Development"], country: ["US"], employeeRange: ["51-200"]. In an MCP client you can ask leadocean_list_enum_values for the same strings.

Step 2: Size the list for free

Add count=true and limit=1 as query parameters. The body stays flat JSON with array filters.

bash
curl -s -X POST "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"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["US"],
    "employeeRange": ["51-200"]
  }' | jq '.meta'

The response has data empty and meta.countOnly true. meta.total is capped at 100,000. If your total is bigger, narrow the filters before you pull.

Step 3: Pull one page

Now spend records. Ask for 25 rows and keep the cursor for the next page.

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": ["US"],
    "employeeRange": ["51-200"],
    "limit": 25
  }' > page1.json
jq '.meta' page1.json

limit runs 1 to 100. Pass meta.nextCursor back as cursor in the next body to get page two. One search pages to 10,000 rows. If meta.depthCapped is true, narrow the filters instead of walking further.

Step 4: Enrich the people you will contact

Search returns the profile, and each row carries its id at meta.source_ids.person_id. Enrich takes exactly one of linkedin_url, email, phone or person_id. Set reveal_email to get the address.

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 '{"person_id": "PERSON_ID_FROM_SEARCH", "reveal_email": true}'

A person LeadOcean holds nothing for returns 404 and costs nothing. Read email_status before you send, because bounced emails are not refunded. Since October 2026 enrich also returns resume_data (past roles, education, certifications) when held.

Step 5: Export when the list is final

For lists over a few hundred rows, use POST /v1/exports. One request takes up to 50,000 rows and the daily cap is 500,000 rows. Bulk CSV export is not on Free, so this step needs Solo ($97 a month) or higher. The app has the same thing with a filter builder, column picker and price preview on its Exports page.

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

Poll GET /v1/exports/{id} until status is done, then fetch GET /v1/exports/{id}/download. Every row costs one record.

What you get

This is a real count from the leadocean_count_leads MCP tool on 2026-10-21, with the filters from Step 1.

json
{
  "total": 18567,
  "totalIsExact": true,
  "totalAll": 60456,
  "distinctCompanies": 12192,
  "credits": 0
}

total counts mailable addresses only (verified, catch_all_valid or catch_all). totalAll is the same filters with no email condition. credits: 0 confirms the count was free.

A search row looks like this. This is the response shape from the API reference, with placeholder values.

json
{
  "success": true,
  "data": [
    {
      "profile_data": {
        "profile_full_name": "Jane Doe",
        "profile_headline": "VP Sales at Acme"
      },
      "contact_data": {
        "has_email": true,
        "email_status": "verified",
        "email_type": "work",
        "contact_current_experiences": [
          { "company_name": "Acme", "company_domain": "acme.com", "job_title": "VP Sales" }
        ]
      },
      "meta": { "source_ids": { "person_id": "1234567890" } }
    }
  ],
  "meta": { "count": 25, "credits": 25, "nextCursor": "eyJ..." }
}

Search rows carry flags, not addresses. Enrich the row by meta.source_ids.person_id to get the email.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCheck $LEADOCEAN_API_KEY is exported and sent as x-api-key
429Above your plan's rate limit (5 a second on Free, 200 on Agency)Honour Retry-After, or move to a plan with a higher limit
402Records spent (Free is 1,000 for life)Upgrade at pricing. Paid plans slow at the fair-use pace instead of stopping
Empty dataEnum value not an exact match, such as Vp or United StatesLook up values with /v1/enums or leadocean_list_enum_values
meta.depthCapped is trueOne search stops at 10,000 rowsAdd filters and run several narrower searches
Export refusedOver 50,000 rows a request or 500,000 a daySplit the export by country or headcount band

FAQ

How many records does this recipe spend?

About 30: 25 for one search page plus up to 5 enrichments. The count, the enum lookup and any 404 enrich are free.

Can I do this without writing code?

Yes. The app at app.leadocean.io has an Exports page with a filter builder and a price preview before you download. It has no sequencer, dialer or CRM.

Is the count a list of emails I can send to?

The default count is mailable: verified, catch_all_valid and catch_all. Pass emailStatus to change it, and label the result by what you filtered.

How fresh is the data?

The dataset is refreshed monthly. Each record also carries its own fetched_at date.

Where does this fit with firmographic and CRM data?

Read our guides on firmographic data providers and what CRM enrichment adds. For agent-driven workflows see B2B sales agents.

Size your first B2B list for free

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

Get your free API key →