Company enrichment turns a domain into a company record: headcount, industry, HQ, funding and website technologies. This guide runs it end to end against LeadOcean in five steps.
TL;DR
- Send a domain to
POST /v1/companies/enrich. You get one record back. A miss is a 404 and costs nothing. - Size the list first with the free count call, so you know what a batch will spend before you run it.
- Total time is about 15 minutes. The sample run spends about 35 records, inside the 1,000 on the Free plan.
Prerequisites
- A LeadOcean account on the Free plan: sign up. No card.
- An API key from app.leadocean.io, exported as
$LEADOCEAN_API_KEY. curlandjq. Any HTTP client works the same way.- A list of domains. We use placeholders like
acme.com.
export LEADOCEAN_API_KEY="paste-your-key-here"Step 1: Size the list for free
Count the companies that match your filters before you pull any. The count endpoint is free and returns an exact total with breakdowns.
curl -s -X POST "https://api.leadocean.io/v1/companies/count" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"hqCountry":["US"],"employeeRange":["51-200"],"industry":["Software Development"]}' \
| jq '.data | {total, totalIsExact}'Filters are arrays of exact strings. If a value is rejected, list the allowed ones with GET /v1/enums, or call the leadocean_list_enum_values MCP tool. The same count is available to an agent as leadocean_count_companies.
Step 2: Pull a sample with company search
Search returns companies that match filters, 1 record per company returned. Use it when you have a segment and no domains yet.
curl -s -X POST "https://api.leadocean.io/v1/companies/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"hqCountry":["US"],"employeeRange":["51-200"],"industry":["Software Development"],"limit":25}' \
| jq '.meta'The body is flat JSON and limit runs 1 to 100. Page with the cursor value from the previous response. One search pages to 10,000 rows; past that, meta.depthCapped is true and there is no nextCursor, so narrow the filters instead.
Step 3: Enrich one domain
Enrichment takes a domain or a LinkedIn company URL and returns the full record. There is no lookup by company name: search first, then enrich the domain you get back.
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"}' | jq .GET works too, with domain or linkedin_url as query parameters. A hit costs 1 record. A 404 means we hold nothing for that company and costs nothing.
Step 4: Loop a batch
There is no batch endpoint for company enrichment. Loop over your domains and keep the pace under your plan's rate limit: 5 requests a second on Free, 200 on Agency.
while read -r d; do
code=$(curl -s -o "out/$d.json" -w "%{http_code}" \
-X POST "https://api.leadocean.io/v1/companies/enrich" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d "{\"domain\":\"$d\"}")
echo "$d $code"
sleep 0.25
done < domains.txtCreate the out/ folder first. Log the status code per domain. A 404 is a miss, not a failure. On a 429, wait for the Retry-After header and retry.
Step 5: Flatten the output to a table
Keep the fields you will filter on and drop the rest. This jq pass turns the saved files into a CSV with one row per hit.
jq -r '.data | [
.company_data.company_domain,
.company_data.company_name,
.company_data.company_employees.number_of_employees,
.company_data.company_primary_address.country_code,
.company_metrics.marketability_score
] | @csv' out/*.json > companies.csvFiles for misses hold an error body, not a record, so jq prints nothing useful for them. Delete files whose status was 404 before you run it, or filter on .success.
What it costs at scale
If you enrich 10,000 domains and 9,200 are found, that is 9,200 records. The 800 misses are free. The Free plan covers the first 1,000 once. Paid plans have no per-record price. Solo is $97 a month and Agency is $497 a month, inside fair use. See pricing.
What you get
Step 1 returns an exact total. This is the free MCP count for the same filters, run on 21 October 2026:
{
"total": 9261,
"totalIsExact": true,
"credits": 0,
"unsupportedFilters": []
}Step 3 returns the shape below. This is the response shape from the API reference, with placeholder values.
{
"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_primary_address": { "city": "Austin", "country_code": "US" },
"company_funding": { "last_round_type": "Series B" }
},
"company_detected_technologies": [
{ "technology_product": { "name": "Cloudflare" }, "technology_last_detected_date": "2026-08-21" }
],
"company_metrics": { "completion_score": 94, "marketability_score": 81 },
"meta": { "schema": "leadocean.company.v1", "credits": 1 }
}
}Unknown values come back as null, never guessed. Funding and revenue are thin for small private companies, so do not build a filter on them alone. Technology data covers about 7.8M crawled sites, so that array is empty for companies outside the set.
For comparison, Crustdata's docs list company enrich at 2 to 4 credits a call, and no public dollar price per credit (Crustdata docs, September 2026). On LeadOcean a hit is 1 record, and paid plans have a fair-use pace instead of credits.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key header | Check $LEADOCEAN_API_KEY is exported and the header name is exact |
| 404 | We hold nothing for that domain | Treat it as a miss. It costs nothing. Try the LinkedIn company URL |
| 429 | Above your plan's rate limit (5 a second on Free, 200 on Agency) | Slow the loop and honor Retry-After |
| 402 | The 1,000 Free records are spent | Upgrade to Solo ($97 a month) or Agency ($497 a month) |
| Empty search results | A filter value that is not an exact enum string | Check spelling and case with /v1/enums |
| Search stops at 10,000 rows | The depth cap, meta.depthCapped true | Add filters and run several narrower searches |
FAQ
Can I enrich a company by name?
No. Enrichment takes a domain or a linkedin_url. With only a name, run company search first and enrich the domain it returns.
How much does a miss cost?
Nothing. A 404, a count and an empty page are free. You pay 1 record for each company you receive.
How fresh is the data?
The dataset is refreshed monthly, and each record carries its own fetched_at date in meta. Check it before you act on a time-sensitive field.
Can I get the people at the company too?
Yes. GET /v1/companies/{domain}/people lists people we hold there, up to 10,000 rows, 1 record per person. See company headcount for the size fields.
Where do I go from here?
Compare vendors in best company data APIs and best contact enrichment APIs. Plans are on pricing. More guides are in the blog.
Enrich your first company free
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →