Enrichment API

Company Headcount API

POST /v1/companies/enrich. One domain in, headcount and size band out. 1 record per company found, a 404 is free.

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

POST /v1/companies/enrich takes a company domain and returns its employee count and size band. It costs 1 record per company found. A 404 costs nothing.

There is no separate headcount endpoint. Headcount is the company_employees block inside the company record. This page is the developer reference. For what the field means and how fresh it is, read Company Headcount. Agents call the same lookup as the leadocean_get_company tool over MCP.

Quick start (curl)

Create a free account, copy a key with the enrich scope and export it as LEADOCEAN_API_KEY.

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"}'

GET works with the same fields as query parameters. No domain to hand? Send the LinkedIn company page as linkedin_url instead.

bash
curl -s -G "https://api.leadocean.io/v1/companies/enrich" \
  --data-urlencode "linkedin_url=https://www.linkedin.com/company/acme" \
  -H "x-api-key: $LEADOCEAN_API_KEY"

Node.js (fetch)

js
const res = await fetch("https://api.leadocean.io/v1/companies/enrich", {
  method: "POST",
  headers: {
    "x-api-key": process.env.LEADOCEAN_API_KEY,
    "content-type": "application/json",
  },
  body: JSON.stringify({ domain: "acme.com" }),
});

if (res.status === 404) {
  console.log("Not in our data. Not billed.");
} else if (!res.ok) {
  throw new Error(`${res.status} ${(await res.json()).error?.message}`);
} else {
  const { data } = await res.json();
  const emp = data.company_data.company_employees;
  console.log(emp?.number_of_employees ?? emp?.number_of_employees_code ?? "no headcount held");
}

Python (requests)

python
import os
import requests

r = requests.post(
    "https://api.leadocean.io/v1/companies/enrich",
    json={"domain": "acme.com"},
    headers={"x-api-key": os.environ["LEADOCEAN_API_KEY"]},
    timeout=10,
)

if r.status_code == 404:
    print("Not in our data. Not billed.")
else:
    r.raise_for_status()
    emp = r.json()["data"]["company_data"].get("company_employees") or {}
    print(emp.get("number_of_employees") or emp.get("number_of_employees_code") or "no headcount held")

Request

Send one of the two inputs. The key needs the enrich scope.

ParameterTypeRequiredMeaning
domainstringOne of the twoWebsite domain, for example acme.com. Preferred key.
linkedin_urlstring (URL)One of the twoLinkedIn company page URL.

There is no lookup by company name. If you only hold a name, search companies first, then send the domain you get back.

Response

Response shape from the API reference. Every value below is a placeholder.

json
{
  "success": true,
  "data": {
    "company_data": {
      "company_name": "Acme",
      "company_domain": "acme.com",
      "company_employees": {
        "number_of_employees": 240,
        "number_of_employees_code": "201-500"
      }
    },
    "company_metrics": { "completion_score": 90, "marketability_score": 80 },
    "meta": { "sources": ["own"], "fetched_at": "2026-09-01", "schema": "leadocean.company.v1" }
  },
  "meta": { "credits": 1, "source": "own" }
}
FieldMeaning
company_data.company_employees.number_of_employeesHeadcount as a number. null when we hold none.
company_data.company_employees.number_of_employees_codeSize band: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000 or 10001+.
company_data.company_employees min and maxBounds of the band, so a range check works when the exact number is missing.
data.meta.fetched_atWhen the record was fetched. Read it before you trust the number.
meta.creditsRecords charged for this call.

Unknown values come back as null, never guessed. The same response carries industry, funding, HQ and website technologies. Only the headcount fields are shown here.

Errors

Every failure is { "success": false, "error": { "message": "...", "details": ... } }. Status codes are from the limits docs, September 2026.

StatusMeaningWhat to do
400Validation failed. Neither domain nor linkedin_url sent, or a field is malformed.Read details and fix the named field.
401Missing, wrong or revoked key.Check the x-api-key header.
402Free plan: the 1,000 records are spent. They do not reset.Upgrade. Not billed.
403The key lacks the enrich scope, or the account is suspended.Create a key with the scope.
404We hold no company for that input.Stop. It costs nothing. Try the other identifier.
429Over 100 requests a second, or 1 a minute on a paid account past its records.Wait for Retry-After, then retry. Not billed.
503The store behind the lookup is unreachable (code: no_source).Retry with backoff. Never billed.

Rate limits and cost

One found company is 1 record, by domain or by LinkedIn URL. That holds even when the record carries no headcount, because you received a company. A 404, 429, 402 or 503 costs nothing.

The limit is 100 requests per second per key, on every plan, with Retry-After: 1 when you exceed it. Free is 1,000 records, one-off, no card. Pro is $499 a month, flat, with no per-record price inside fair use. See pricing.

Reading headcount from a found record takes no second call. Check records left before a big run: GET /v1/account is free.

Bulk

For a few hundred domains, loop this endpoint. For thousands of people at companies of a given size, use POST /v1/exports instead. It is a people export, so each row is one person, 1 record, with the employer's headcount beside them.

The headcount columns are current_company_employees, current_company_employees_range, current_company_employees_min and current_company_employees_max. Repeated blocks are numbered: email_N_address comes back as email_1_address, email_2_address and so on, and caps sets how many (default 3 emails).

bash
curl -X POST https://api.leadocean.io/v1/exports \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d '{
    "name": "VP Sales at 201-500 staff companies",
    "filters": { "title": ["VP Sales"], "country": ["US"], "employeeRange": ["201-500"] },
    "limit": 5000,
    "columns": ["person_id", "current_company_domain", "current_company_employees",
                "current_company_employees_range", "email_N_address"],
    "caps": { "emails": 1 }
  }'

The reply is a 202 with a job id. Poll GET /v1/exports/{id}, then fetch /v1/exports/{id}/download. An export takes up to 50,000 rows and needs the search scope plus enrich for columns from the full record. Prefer clicks? The Exports page at app.leadocean.io builds the same file.

FAQ

Is there a separate employee count endpoint?

No. Call the company lookup and read company_data.company_employees. That is the whole headcount API, and it is also where industry, funding and tech stack come from.

What does a call cost, and what does a miss cost?

A found company costs 1 record, even with null headcount. A company we hold nothing for is a 404 and costs nothing. Free is 1,000 records, one-off. Pro is $499 a month, flat.

Can I look up headcount from a company name?

Not directly. Search companies by name, take the domain from the row and send it here. For the related fields, see company enrichment APIs compared and the best company data APIs.

Get your company headcount API key free

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

Get your free API key →