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

How-to guide

How to Get B2B Data for GTM Teams (with the LeadOcean API)

Four requests: size the list for free, pull a small batch, reveal emails for the best rows and export the rest. Real queries, real output shape.

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

TL;DR

  • GTM teams need four things from a data source: a free size check, a small test pull, verified emails for the best rows and a bulk export. Each is one request below.
  • It takes about 30 minutes. The example spends about 35 of your 1,000 free records: 25 for the pull, 10 for email reveals.
  • Counts, filter lookups and enum lookups cost nothing. Only people you receive count as records.

Prerequisites

  • A LeadOcean account. The free plan has 1,000 records for life, no card and 5 requests a second.
  • An API key from app.leadocean.io, exported as $LEADOCEAN_API_KEY.
  • curl and jq. Python 3 is optional for the loop in step 3.
  • A written ICP: job level, function, country and company size.
  • A paid plan only for step 4. Bulk CSV export is not on Free. It is included on Solo ($97 a month) and Agency ($497 a month).
bash
export LEADOCEAN_API_KEY="paste-from-app-leadocean-io"
curl -s https://api.leadocean.io/v1/account -H "x-api-key: $LEADOCEAN_API_KEY"

The account call is free. It shows your plan and the records you have left.

Step 1: Size the list before you spend anything

A people search with count=true and limit=1 returns a total and no rows. It costs nothing. Send count as a query parameter, not in a JSON body.

bash
curl -s -G https://api.leadocean.io/v1/people/search \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "jobLevel=VP" \
  --data-urlencode "jobFunction=Sales & Business Development" \
  --data-urlencode "country=US" \
  --data-urlencode "emailStatus=verified,catch_all_valid,catch_all" \
  --data-urlencode "count=true" \
  --data-urlencode "limit=1" | jq '.meta | {total, totalIsExact, countOnly, distinctCompanies}'

meta.total stops at 100,000. If totalIsExact is false, treat the number as a floor. The same filters in the MCP tool leadocean_count_leads return an uncapped count with breakdowns.

Sizing companies works the same way. GET /v1/companies/count takes the company-search filters and returns an exact total with breakdowns by industry, headcount band, HQ country, HQ state and NAICS.

bash
curl -s -G https://api.leadocean.io/v1/companies/count \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "industry=Software Development" | jq '.data | {total, facets}'

Enum filters are exact strings. Look them up first with GET /v1/enums/job_function or the leadocean_list_enum_values tool.

Step 2: Pull a small batch of people

Pull 25 rows to check fit before you commit volume. The search body is flat JSON, filters are arrays, limit runs 1 to 100 and paging uses a cursor.

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": ["US"],
    "emailStatus": ["verified", "catch_all_valid", "catch_all"],
    "limit": 25
  }' > people.json

jq '{rows: (.data | length), nextCursor: .meta.nextCursor}' people.json

Search rows are thin: profile, current role and email flags. Each row carries a person_id at meta.source_ids.person_id. Step 3 uses it.

To start from a target account instead, call GET /v1/companies/acme.com/people. It lists people at one domain and stops at 10,000 rows.

Step 3: Reveal work emails for the best rows

Enrich takes exactly one of linkedin_url, email, phone or person_id. There is no name plus domain lookup, so search first and enrich by person_id. Set reveal_email to true to get the address. It costs no extra record.

python
import json, os, requests

H = {"x-api-key": os.environ["LEADOCEAN_API_KEY"]}
rows = json.load(open("people.json"))["data"][:10]

with open("enriched.jsonl", "a") as out:
    for r in rows:
        pid = r["meta"]["source_ids"]["person_id"]
        res = requests.post("https://api.leadocean.io/v1/people/enrich",
                            headers=H, json={"person_id": pid, "reveal_email": True})
        if res.status_code == 404:   # nobody matched, costs nothing
            continue
        res.raise_for_status()
        out.write(json.dumps(res.json()) + "\n")

Ten reveals spend 10 records. An enrichment that finds nothing is a 404 and costs nothing. Since October 2026 the response also carries career history: past roles, education and certifications. Past employers have no company_id yet.

Read email_status before you send. LeadOcean does not refund or credit back bounced emails.

Step 4: Export the full list for your sequencer or CRM

Once the 25-row sample looks right, export. POST /v1/exports takes the same filters as search. It takes up to 50,000 rows a request and 500,000 a day. This needs Solo or Agency.

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 VPs, mailable",
    "filters": {
      "jobLevel": ["VP"],
      "jobFunction": ["Sales & Business Development"],
      "country": ["US"],
      "emailStatus": ["verified", "catch_all_valid", "catch_all"]
    },
    "limit": 5000
  }'

You can also run the same export in the app at app.leadocean.io. The Exports page has a filter builder, a column picker, the record price before you start and a CSV download. Load the file into your own sequencer or CRM. LeadOcean supplies the data. It has no sequencer, dialer, CRM or Chrome extension.

Step 5: Let the team ask in plain language

Ops and sales people who do not write curl can use the hosted MCP server. It uses OAuth sign-in, so no key is pasted. Add it in Claude Code with one command (Claude Code MCP docs).

bash
claude mcp add --transport http leadocean https://api.leadocean.io/mcp

Then ask for a count first. This prompt spends no records.

text
Use leadocean_count_leads for VPs in Sales & Business Development in the US.
Do not search or look up any person. Return the total and the top 5 industries.

leadocean_count_leads, leadocean_list_filters and leadocean_list_enum_values are free. leadocean_search_leads, leadocean_get_lead and leadocean_export_leads spend records, so tell the agent to stop and ask before it calls them.

Choosing the route

Use the API when a script or an enrichment job calls the data. Use the app Exports page when a RevOps person needs a CSV today and wants the record price shown first. Use MCP when the question is "how big is this segment" and a person is typing it.

Keep one rule across all three: size first, sample 25, then scale. A bad enum value or a wrong country filter costs you 25 records at the sample stage, not 5,000 at the export stage.

What you get

This is a live free count run on 2026-10-21 with leadocean_count_leads (jobLevel VP, jobFunction Sales & Business Development, country US). It filters on mailable addresses (emailStatus verified, catch_all_valid or catch_all) and spent 0 records.

json
{
  "total": 129494,
  "totalIsExact": true,
  "totalAll": 350517,
  "distinctCompanies": 58121,
  "credits": 0
}

totalAll is the same filters with no email filter. Pulling 25 of those rows plus 10 reveals is 35 records, 3.5% of the free allowance.

A search row has this shape (response shape from the API reference, placeholder values):

json
{
  "success": true,
  "data": [
    {
      "profile_data": {
        "profile_full_name": "Jane Doe",
        "profile_headline": "VP of 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 of Sales" }
        ]
      },
      "meta": { "source_ids": { "person_id": "1234567890" } }
    }
  ],
  "meta": { "count": 25, "credits": 25, "nextCursor": "eyJ..." }
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCheck $LEADOCEAN_API_KEY is set in the shell that runs the call
429Above the plan's rate limit (5 a second on Free, 200 on Agency)Wait for Retry-After, then slow the loop
402Out of records on the free planCheck GET /v1/account, then move to a paid plan
Empty dataEnum value spelled wrong, such as vp for jobLevelLook up exact values with GET /v1/enums
404 on enrichNobody matched the inputNothing is charged. Skip the row
Export refusedOver 50,000 rows a request or 500,000 a day, or you are on FreeSplit the export or use a paid plan

FAQ

How many records does a GTM team need?

Start with the free 1,000 to test fit. Paid plans have a fair-use pace instead of credits, so there is no per-record price or overage invoice. Solo is $97 a month for one person. Agency is $497 a month for teams, with 5 keys.

Can I use this without writing code?

Yes. The app at app.leadocean.io has an Exports page with a filter builder and CSV download. The MCP server at https://api.leadocean.io/mcp also exposes 13 tools to Claude and other MCP clients.

Does LeadOcean replace our sequencer or CRM?

No. It is a data source. Export a CSV or call the API from your own tools.

How fresh is the data?

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

Where do I go next?

For tool picks by team type, see data providers for GTM engineers, for RevOps teams and for enterprise teams. Plans are on the pricing page.

Size your GTM list before you pay for it

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

Get your free API key →