TL;DR
- TAM sourcing is turning a market definition into a list of named accounts. Do it as three calls: a free count, a company search that pages by cursor, and a people pull for the accounts you keep.
- It takes about 30 minutes. Counting spends 0 records. The company list in this example is 728 records, so it fits the 1,000 on the Free plan.
- Count first, pull second. A count is free, so you can tighten the filters until the list is the size you will actually work.
Prerequisites
- A LeadOcean account from app.leadocean.io. Free is 1,000 records for life, no card, 5 requests a second.
- An API key in your shell:
export LEADOCEAN_API_KEY=... curlandjq. Python 3 for the paging loop.- Optional: the hosted MCP server at
https://api.leadocean.io/mcp, if you would rather ask Claude to run the counts.
Step 1: Write the market as filters
Write the TAM as filters before you touch the API. Each filter is a field the data holds, so the definition is testable.
Our example: US software companies with 51 to 500 employees. In LeadOcean terms that is industry, hqCountry and employeeRange.
{
"industry": ["Computer Software"],
"hqCountry": ["US"],
"employeeRange": ["51-200", "201-500"]
}Enum values are exact strings. industry has 534 of them and hqCountry takes ISO codes. A wrong value gives an empty result, not an error. Look values up first. The enum endpoints need no key.
curl -s "https://api.leadocean.io/v1/enums/industry?q=software" | jq '.data.values'In Claude, the MCP tool leadocean_list_enum_values does the same with a substring search, for example name: "industry", q: "software".
Step 2: Count the accounts for free
A company count returns an exact total and breakdowns by industry, headcount band, HQ country, HQ state and NAICS. It spends no records.
curl -s -X POST "https://api.leadocean.io/v1/companies/count" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"industry": ["Computer Software"],
"hqCountry": ["US"],
"employeeRange": ["51-200", "201-500"]
}' | jq '{total: .data.total, state: .data.facets.hq_state[:5]}'Run the same filters through the MCP tool leadocean_count_companies and you get the same answer. This is the output we got on 2026-10-21 (see "What you get" below).
Add hasMailableContacts: true to keep only companies with at least one person whose best email is verified, catch_all_valid or catch_all. Use it when the list feeds outbound. Skip it when you are sizing a market.
Step 3: Tighten until the number is workable
Read the breakdown, then cut. If 204 of 728 accounts sit in California, you can split the list by state and work it in waves. If a headcount band is too thin to matter, drop it.
Each change is another free count. There is no reason to pull a list you have not sized.
curl -s -X POST "https://api.leadocean.io/v1/companies/count" \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{"industry":["Computer Software"],"hqCountry":["US"],"employeeRange":["201-500"]}' \
| jq '.data.total'Do not quote a people count that uses funding, revenue, HQ city or HQ state filters: the people count does not apply them reliably. On any count, a filter that cannot apply is named in unsupportedFilters and the total is withheld. Read that field every time.
Step 4: Page the companies out with a cursor
Now spend records. Pull accounts only after the count says the list is the size you want. POST /v1/companies/search takes the same flat JSON body. limit runs 1 to 100, and you page with cursor from meta.nextCursor. One record is one company returned.
import os, requests
URL = "https://api.leadocean.io/v1/companies/search"
H = {"x-api-key": os.environ["LEADOCEAN_API_KEY"], "content-type": "application/json"}
body = {
"industry": ["Computer Software"],
"hqCountry": ["US"],
"employeeRange": ["51-200", "201-500"],
"limit": 100,
"fields": ["company_data.company_name", "company_data.company_domain"],
}
rows, cursor = [], None
while True:
if cursor:
body["cursor"] = cursor
r = requests.post(URL, headers=H, json=body, timeout=60)
r.raise_for_status()
j = r.json()
rows += j["data"]
cursor = j["meta"].get("nextCursor")
if not cursor:
break
print(len(rows), "companies")fields trims each record to the dotted paths you name, which keeps the payload small. A search pages to 10,000 rows. If meta.depthCapped is true there is no nextCursor, and the fix is narrower filters, not a longer walk.
728 companies at 100 a page is 8 requests. That is well inside the 5 a second on Free.
A note on what the list is not. It is a snapshot of the database on the day you pull it, refreshed monthly, and each record carries its own fetched_at date. Store the domains, and re-run the free count each month to see whether the market moved.
Step 5: Pull buyers at the accounts you keep
A TAM list is accounts. Outbound needs people. Search people with the same company filters plus the roles you sell to, and count first.
curl -s -X POST "https://api.leadocean.io/v1/people/search?count=true&limit=1" \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{
"industry": ["Computer Software"],
"hqCountry": ["US"],
"employeeRange": ["51-200", "201-500"],
"jobLevel": ["VP", "C-Team"],
"jobFunction": ["Sales & Business Development"]
}' | jq '.meta'The same count through leadocean_count_leads returned 145 people with a mailable email across 66 companies on 2026-10-21. Without the email condition it matched 681. Say which one you mean when you quote it.
To get people at one account, call GET /v1/companies/{domain}/people. To export a finished list, POST /v1/exports takes up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on Free.
Before you send anything, check email_status on each person. Bounced emails are not refunded or credited back, so filter on verified and catch_all_valid first.
What you get
These are the free counts we ran on 2026-10-21 through the MCP tools. No records were spent.
leadocean_count_companies
industry: Computer Software
hqCountry: US
employeeRange: 51-200, 201-500
total: 728 (exact)
employee_range: 51-200 = 460, 201-500 = 268
hq_state (top 5): California 204, Massachusetts 51, New York 51, Texas 44, Florida 37
credits: 0leadocean_count_leads
same company filters + jobLevel VP, C-Team + jobFunction Sales & Business Development
total (verified, catch_all_valid or catch_all): 145
totalAll (no email condition): 681
distinctCompanies: 66
credits: 0Below is a company page from Step 4, trimmed with fields. Label: response shape from the API reference, placeholder values.
{
"success": true,
"data": [
{
"company_data": {
"company_name": "Acme",
"company_domain": "acme.com"
}
}
],
"meta": {
"count": 100,
"limit": 100,
"total": 728,
"nextCursor": "opaque-cursor-string"
}
}Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key header | Check that $LEADOCEAN_API_KEY is set in the shell that runs the call. |
| 429 | Above the plan's rate limit (5 a second on Free, 200 on Agency) | Wait for the Retry-After header, then slow the loop. |
| 402 | Out of records. Free is 1,000 for life | Count first, narrow the list, or move to a paid plan on pricing. |
Empty data | A filter value is not an exact enum string | Look it up with leadocean_list_enum_values or GET /v1/enums/{name}. |
No nextCursor, meta.depthCapped true | One search pages to 10,000 rows | Split by state, headcount band or industry and run each slice. |
| Export refused | Over 50,000 rows a request or 500,000 a day, or you are on Free | Export in slices. Bulk CSV export needs a paid plan. |
FAQ
What is TAM sourcing?
TAM sourcing is building the actual list of companies (and later people) that make up your total addressable market. Sizing gives you a number. Sourcing gives you names you can work. For the sizing math, see TAM, SAM and SOM and the TAM sizing use case.
How many records does it cost?
Counting costs nothing. Pulling the 728 companies in this example costs 728 records, one per company returned. People are a separate pull, one record per person. See how records are counted.
Do I need a data enrichment tool on top?
Not to get the list. Tools such as Clay describe combining several data providers into one workflow, per their TAM sourcing page (October 2026). Use that route when you want waterfalls across vendors. If one database covers your filters, a filter, a count and a cursor are enough.
Can I run this from Claude instead of curl?
Yes. The hosted MCP server has 13 tools. leadocean_count_companies and leadocean_count_leads are free, so you can size a market in a chat before you spend a record.
Is there a calculator for the sizing step?
Yes: the TAM calculator. For the broader TOFU read, start at from TAM to a working list, and browse the blog hub for related guides.
Source your TAM with one filter and one cursor
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →