POST /v1/companies/enrich takes one LinkedIn company URL and returns the company record, with the website domain at data.company_data.company_domain. It costs 1 record per company found. A 404 costs nothing.
There is no separate "domain" endpoint. The domain is one field of the company record, leadocean.company.v1. This page is the developer reference. For what the data is, read LinkedIn company URL to domain. The same lookup is 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.
curl -s -X POST "https://api.leadocean.io/v1/companies/enrich" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"linkedin_url":"https://www.linkedin.com/company/acme"}'The endpoint also answers GET with query parameters:
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)
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({
linkedin_url: "https://www.linkedin.com/company/acme",
}),
});
if (res.status === 404) {
console.log("Company 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();
console.log(data.company_data?.company_domain ?? "Company found, no domain held");
}Python (requests)
import os
import requests
r = requests.post(
"https://api.leadocean.io/v1/companies/enrich",
json={"linkedin_url": "https://www.linkedin.com/company/acme"},
headers={"x-api-key": os.environ["LEADOCEAN_API_KEY"]},
timeout=10,
)
if r.status_code == 404:
print("Company not in our data. Not billed.")
else:
r.raise_for_status()
company = r.json()["data"]["company_data"]
print(company.get("company_domain") or "Company found, no domain held")Request
Send linkedin_url or domain. The key needs the enrich scope. There is no lookup by company name.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
linkedin_url | string (URL) | One of the two | LinkedIn company page URL, for example https://www.linkedin.com/company/acme. |
domain | string | One of the two | Website domain, for example acme.com. Use it when you already have the domain and want the rest of the record. |
POST takes these as a JSON body. GET takes them as query parameters. POST /v1/companies/enrich is an older alias, so use the path above.
Response
Response shape from the API reference. Every value below is a placeholder, and fields we hold nothing for are left out for brevity.
{
"success": true,
"data": {
"company_data": {
"company_name": "Acme",
"company_domain": "acme.com",
"company_social_links": {
"linkedin": { "url": "https://www.linkedin.com/company/acme" }
},
"company_employees": {
"number_of_employees": 240,
"number_of_employees_code": "201-500"
},
"company_primary_address": {
"city": "Austin",
"country_code": "US"
}
},
"company_detected_technologies": [
{
"technology_product": { "name": "Cloudflare" },
"technology_last_detected_date": "2026-08-21"
}
],
"company_metrics": { "completion_score": 94, "marketability_score": 81 },
"meta": { "sources": ["own"], "schema": "leadocean.company.v1" }
},
"meta": { "credits": 1, "source": "own" }
}| Field | Meaning |
|---|---|
data.company_data.company_domain | The website domain. The field you came for. |
data.company_data.company_name | Company name. |
data.company_data.company_social_links | Social links, including the LinkedIn page. |
data.company_data.company_employees | Headcount and a banded size code. |
data.company_detected_technologies[] | Technology found on the company website, with a last detected date. |
data.company_metrics | completion_score and marketability_score. |
meta.credits | Records counted for this call. |
Unknown values are null, never guessed. Check company_domain before you write it anywhere. Each record also carries meta.fetched_at, and the dataset is refreshed monthly.
Errors
Every failure is { "success": false, "error": { "message": "...", "details": ... } }. Status codes are from the limits docs, September 2026.
| Status | Meaning | What to do |
|---|---|---|
| 400 | Validation failed. details names the wrong fields. | Send linkedin_url or domain. Not billed. |
| 401 | Missing, wrong or revoked key. | Check the x-api-key header. |
| 402 | Free plan: the 1,000 records are spent. They do not reset. | Upgrade. Not billed. |
| 403 | The key lacks the enrich scope, or the account is suspended. | Create a key with the scope. |
| 404 | Not in our data. | Stop. It costs nothing. Log the URL and move on. |
| 429 | Over 100 requests a second, or 1 a minute on a paid account past its records. | Wait for Retry-After, then retry. Not billed. |
| 503 | The store behind the lookup is unreachable (code: no_source). | Retry with backoff. Never billed. |
Rate limits and cost
One company found is 1 record. A 404, 400, 401, 402, 403, 429 or 503 costs nothing. A 200 with company_domain set to null still costs 1 record, because we returned a company.
The limit is 100 requests per second per key, on every plan. 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.
Worked example: 10,000 company URLs and 8,700 found is 8,700 records. The 1,300 misses are free. The docs give no hit rate, so test a sample of your own list first.
Bulk
A list of company URLs has no export. POST /v1/exports exports people, not companies, so loop this endpoint once per URL. At 100 requests per second, 10,000 URLs fit in a couple of minutes.
If you are starting from people, the export already carries each employer. The column picker includes current_company_domain, current_company_linkedin_url and current_company_name, next to the numbered contact columns email_N_address and email_N_status. They come back as email_1_address, email_1_status, email_2_address and so on. caps sets how many (default 3 emails).
curl -X POST https://api.leadocean.io/v1/exports \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{
"name": "VPs with employer domain",
"filters": { "jobLevel": ["VP"], "country": ["US"] },
"limit": 5000,
"columns": ["person_id", "profile_full_name", "current_company_domain", "current_company_linkedin_url", "email_N_address", "email_N_status"],
"caps": { "emails": 1 }
}'The reply is a 202 with a job id. Poll GET /v1/exports/{id}, then fetch /v1/exports/{id}/download. One export row is 1 record whatever the columns. Contact columns need the enrich scope too.
FAQ
Does a LinkedIn URL we cannot match cost a record?
No. A 404 costs nothing. You pay 1 record for each company returned.
Can I look up a domain by company name?
No. Send a LinkedIn company URL or a domain. With only a name, search companies first, then enrich the domain you get back. See company enrichment over the API.
Can an agent call it without an API key?
Yes. The MCP server at https://api.leadocean.io/mcp signs in with OAuth 2.1, so no key is pasted. The tool is leadocean_get_company, 1 record. Setup is on the MCP page.
Get your LinkedIn company to domain API key free
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →