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

How-to guide

How to Build a Company Search (With the LeadOcean API)

Size the list for free, pull pages with a cursor, enrich one domain, and handle the errors you will hit.

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

Size the list first, then pull it. A company search is one POST /v1/companies/search call with flat JSON filters, a limit from 1 to 100 and a cursor for the next page.

TL;DR

  • Time: about 20 minutes from an empty terminal to a paged list and one enriched company.
  • Cost: about 106 LeadOcean records on the example. Counting is free, so size the list before you spend anything.
  • Result: a script that walks a filtered company list page by page and writes it to a file, plus an agent prompt for the same query.

Prerequisites

  • A LeadOcean account. The free plan gives you 1,000 records, one-off, no card. Sign up at app.leadocean.io/register.
  • An API key from the app, exported as $LEADOCEAN_API_KEY. Free keys carry both the search and enrich scopes.
  • curl and Python 3 with requests installed.
  • Optional: Claude Code or Claude Desktop, if you want the MCP version in Step 6.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"

Step 1: Check the key and your balance

Call GET /v1/account first. It is free, and it tells you the plan, the records left on Free or the fair-use pace on a paid plan, and your rate.

bash
curl -s "https://api.leadocean.io/v1/account" \
  -H "x-api-key: $LEADOCEAN_API_KEY"

A 401 here means the key is wrong. A 403 later means the key lacks the scope an endpoint needs. Fix both in the app before you go on.

Step 2: Pick filters from the closed lists

Enum filters take exact strings. Guessing a value does not fail loudly: you get an empty page.

Company search has 34 filters. Industry has 534 values and headcount comes in eight brackets. Resolve a value before you use it:

bash
curl -s "https://api.leadocean.io/v1/enums/industry?q=software" \
  -H "x-api-key: $LEADOCEAN_API_KEY"

curl -s "https://api.leadocean.io/v1/enums/employee_range" \
  -H "x-api-key: $LEADOCEAN_API_KEY"

The industry lookup for "software" returns seven values, among them Computer Software and Software Development. The brackets are 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000 and 10001+.

The example search is software companies headquartered in the US with 51 to 200 employees. Use employeeRange rather than minEmployees and maxEmployees when a bracket will do. The docs call it broader and cheaper. A numeric range only returns companies where we hold a figure, so a company with no headcount on file never appears.

Start with the filters that are always filled in, then add the thin ones. Industry, headcount bracket and headquarters country are the safe core. Other filters worth knowing:

  • keywords matches across company description, specialties and categories. Several values OR together.
  • technologies and technologyCategories filter on what a website runs. They cover about 7.8M crawled sites, so they narrow hard.
  • hqContinent and hqSalesRegion set a wide net. Use hqCountry for a single market.
  • minFounded and maxFounded use the founding year. Like every numeric range, they skip companies with no year on file.
  • excludeName and excludeIndustry cut out noise after your first test page.

Funding, revenue, investor and NAICS filters work in search. Size the list on the core filters first, then expect those filters to narrow it further.

Step 3: Size the list before you pull it

A count is free when you send count=true as a query parameter with limit set to 1. The answer is in meta.total, and data comes back empty.

bash
curl -s -X POST "https://api.leadocean.io/v1/companies/search?count=true&limit=1" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "industry": ["Computer Software"],
    "employeeRange": ["51-200"],
    "hqCountry": ["US"]
  }'

Put count in the query string, not the JSON body. The body rejects unknown fields, and the query string is where the free sizing call is documented.

meta.total stops at 100,000. If meta.totalIsExact is false, the total is a floor and you should narrow the filters. If meta.totalWithheld is set, one filter could not be counted and the number is hidden on purpose.

For an exact company total with breakdowns, call GET /v1/companies/count. It takes the same filters as query parameters, returns no rows and costs nothing.

bash
curl -s -G "https://api.leadocean.io/v1/companies/count" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "industry=Computer Software" \
  --data-urlencode "employeeRange=51-200" \
  --data-urlencode "hqCountry=US"

Step 4: Pull a test page

Spend a few records to check the shape before you page through hundreds. Each company returned counts one record.

bash
curl -s -X POST "https://api.leadocean.io/v1/companies/search" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "industry": ["Computer Software"],
    "employeeRange": ["51-200"],
    "hqCountry": ["US"],
    "limit": 5
  }'

This costs 5 records. Check meta.credits: it reports the records counted for the call, and it should read 5.

Filters are arrays of strings, even for one value. The body is flat. There are no nested and or or blocks.

Step 5: Page through the results with the cursor

Each response carries meta.nextCursor. Send it back unchanged as cursor with the same filters to get the next page. When it is null, the walk is over.

python
import json, os, requests

URL = "https://api.leadocean.io/v1/companies/search"
HEADERS = {
    "x-api-key": os.environ["LEADOCEAN_API_KEY"],
    "content-type": "application/json",
}
FILTERS = {
    "industry": ["Computer Software"],
    "employeeRange": ["51-200"],
    "hqCountry": ["US"],
}
PAGE_SIZE = 50
MAX_PAGES = 2  # 100 records. Raise it once you trust the filters.

cursor, pages, rows = None, 0, 0
with open("companies.jsonl", "w") as out:
    while pages < MAX_PAGES:
        body = {**FILTERS, "limit": PAGE_SIZE}
        if cursor:
            body["cursor"] = cursor
        r = requests.post(URL, headers=HEADERS, json=body, timeout=30)
        if r.status_code == 429:
            raise SystemExit("rate limited: wait for Retry-After and rerun")
        r.raise_for_status()
        payload = r.json()
        for company in payload["data"]:
            out.write(json.dumps(company) + "\n")
            rows += 1
        pages += 1
        meta = payload["meta"]
        cursor = meta.get("nextCursor")
        if not cursor:
            break

print(f"wrote {rows} companies in {pages} pages")

Three rules for the cursor. Pass back exactly the string you were given: an edited or hand-built cursor is refused with 400 Invalid cursor. Do not reuse a cursor with different filters. Do not store one: it is a position in one walk, so restart the query instead.

One search pages through at most 10,000 rows by default. At that point meta.depthCapped is true and nextCursor stays null. To cover a bigger market, split it into several narrower searches, for example one per headcount bracket.

Now enrich one company from the list. Enrichment takes a domain or a LinkedIn company URL. It does not take a name, so search first and enrich the domain you got back.

bash
curl -s -X POST "https://api.leadocean.io/v1/companies/enrich" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"domain":"acme.com"}'

A hit costs 1 record. A company we hold nothing for is a 404 and costs nothing.

Step 6: Run the same search from an agent

The hosted MCP server at https://api.leadocean.io/mcp has 13 tools and signs in with OAuth 2.1, so no key is pasted. The company tools are leadocean_count_companies (free), leadocean_search_companies and leadocean_get_company. Add the server to Claude Code with one command.

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

Then give the agent the same query in plain words:

text
Find US software companies with 51 to 200 employees.
Size the list first and tell me the number before you pull anything.
Then pull the first 10 and list name, domain and headcount.

The agent resolves the enum values with leadocean_list_enum_values and sizes the list with leadocean_count_companies. Both are free. It then pulls the 10 companies, which costs 10 records. If you want contacts at those companies rather than the companies themselves, use best people search APIs for the next step.

What you get

Sizing runs through the free leadocean_count_companies MCP tool, the same count as GET /v1/companies/count. Run on 21 October 2026 with industry: Computer Software, employeeRange: 51-200 and hqCountry: US. The breakdowns are trimmed to the top five states:

json
{
  "total": 460,
  "totalIsExact": true,
  "facets": {
    "hq_state": [
      { "value": "California", "count": 136 },
      { "value": "New York", "count": 36 },
      { "value": "Texas", "count": 26 },
      { "value": "Massachusetts", "count": 25 },
      { "value": "Florida", "count": 24 }
    ]
  },
  "credits": 0,
  "source": "leadocean",
  "unsupportedFilters": []
}

Read it as 460 companies. credits is 0 because sizing is free. unsupportedFilters is empty, so every filter was applied. Computer Software is one of seven industry values that match "software". Add Software Development and the others for the wider market.

A company record comes back as leadocean.company.v1. This is the response shape from the API reference, with placeholder values:

json
{
  "success": true,
  "data": [
    {
      "company_data": { "...": "name, domain, description, industries, company_employees, address" },
      "company_detected_technologies": [],
      "company_metrics": { "...": "completion_score, marketability_score" },
      "meta": { "...": "sources, fetched_at, schema" }
    }
  ],
  "meta": {
    "source": "leadocean",
    "count": 1,
    "limit": 50,
    "credits": 1,
    "nextCursor": "opaque-string-from-the-api"
  }
}

A value LeadOcean does not hold is null, never guessed. Technology data covers about 7.8M crawled sites, so that list is empty for many companies. Revenue and funding are thin, so do not build a filter on either alone.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCopy the key again from the app and check $LEADOCEAN_API_KEY is set in this shell
403The key lacks the search or enrich scopeCreate a key with the scope the endpoint needs
429Above your plan's rate on this key (5 a second on Free, 200 on Agency)Wait for the Retry-After header, then retry. Run the walk in sequence, not in parallel
402Free plan only: the 1,000 one-off records are spentCheck GET /v1/account. Move to Solo at $97 a month or Agency at $497 on pricing
Empty data with no errorAn enum value that is not an exact string, or filters that are too narrowResolve each value with /v1/enums/{name}, and drop filters one at a time
meta.depthCapped is true, nextCursor is nullThe search paged through 10,000 rowsSplit the market into narrower searches, or ask support if you have a genuine large export

FAQ

How much does a company search cost?

Each company returned is one record. Counting with count=true and limit=1 costs nothing. Free gives you 1,000 records once. Solo is $97 a month and Agency $497 a month, with a fair-use pace instead of credits. See pricing.

Can I search by company name?

Yes. Use the name filter for name keywords, or q for free text over name and description. Enrichment is different: it needs a domain or a LinkedIn company URL.

How do I get more than 100 rows?

Page with the cursor. limit is capped at 100 per page, and one search walks at most 10,000 rows. For more, run several narrower searches.

Does this return contacts at the company?

No. Company search returns companies. For the people at one company, call GET /v1/companies/{domain}/people, which stops at 10,000 rows. For enrichment details, read the company enrichment API guide.

Is there a ranked comparison of tools?

Yes. Best company search engines compares the options with sourced prices.

Run your first company search with a free API key

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

Get your free API key →