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

How-to guide

How to Find and Monitor Your Total Addressable Market (with Company Data)

Three free counts give you TAM, SAM and SOM. One page of 100 companies gives you the list. One monthly script tells you when the market moves.

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

TL;DR

  • You size TAM, SAM and SOM with three free company counts, pull the SOM list once, then re-run the counts every month with a short script.
  • It takes about 25 minutes to set up. The run spends about 100 of your 1,000 free records, all on the list in Step 4. Counts cost 0.
  • LeadOcean refreshes its dataset monthly, so a monthly check is the right rhythm. Faster polling shows the same numbers.

Prerequisites

  • A LeadOcean account from app.leadocean.io. The free plan has no card and 1,000 records, one-off.
  • A key in your shell as $LEADOCEAN_API_KEY, plus curl and Python 3 with requests.
  • Optional: the MCP server at https://api.leadocean.io/mcp in Claude, for the people count in Step 3. It signs in with OAuth, so no key is pasted.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"

Step 1: Pin the segment with the real filter names

Write the market as filters before you count anything. A TAM that lives in a slide has no query behind it, so nobody can re-run it. A TAM is one set of filters, a SAM adds a geography or a size band, and a SOM adds what you can actually sell to this year.

Filter and enum names are exact strings. Look them up first. Both calls are free.

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

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

The example market is software companies. The industry enum holds 534 values and has no plain "Software". The value we want is Computer Software. Headcount comes as eight employeeRange brackets, and HQ country takes two-letter codes such as US.

LayerFilters
TAMindustry: ["Computer Software"]
SAMTAM plus employeeRange: ["51-200", "201-500"]
SOMSAM plus hqCountry: ["US"]

One caveat. Size filters only match companies whose value we hold. A company with no headcount on file never appears in the SAM, so treat the SAM as a floor.

Step 2: Count each layer for free

Send each layer to POST /v1/companies/search with count=true and limit=1 as query parameters. The body is flat JSON and filters are arrays. The count call returns no rows, so it spends nothing.

bash
count () {
  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 "$1" | jq '.meta | {total, totalIsExact}'
}

count '{"industry":["Computer Software"]}'
count '{"industry":["Computer Software"],"employeeRange":["51-200","201-500"]}'
count '{"industry":["Computer Software"],"employeeRange":["51-200","201-500"],"hqCountry":["US"]}'

meta.total is capped at 100,000. If a layer is bigger, totalIsExact is false and the number is a floor. For an exact total with no cap, use GET /v1/companies/count or the MCP tool leadocean_count_companies. Both are free, take the same filters and break the total down by industry, headcount band, HQ country, HQ state and NAICS.

Put the three totals in a sheet next to your price per customer. TAM is the first count times your annual contract value. SAM and SOM follow the same arithmetic.

A worked example with placeholder numbers: a SOM of 2,000 companies at a $10,000 annual contract is a $20M serviceable obtainable market. Change one filter and the sheet updates. That is the point of keeping the filters in code. For the definitions, see what TAM means.

Step 3: Size the buyers inside the segment

A company count tells you how many accounts exist. It does not tell you how many people you can reach. For that, ask the MCP server. The people count is free too.

text
Count mailable people with jobLevel C-Team or VP at companies in the
Computer Software industry with 51-200 or 201-500 employees and an HQ in the US.
Also count the same without the HQ filter, and without the size filter.
Use leadocean_count_leads. Do not search or export.

Claude maps that to leadocean_count_leads with industry, employeeRange, hqCountry and jobLevel. The tool counts only verified, catch-all-valid and catch-all addresses unless you say otherwise.

Step 4: Pull the SOM list once

Pull the list only when the SOM looks right. Each company returned counts one record, so set limit to what you will actually use. One page is 100 companies and 100 records.

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", "201-500"],
    "hqCountry": ["US"],
    "limit": 100
  }' > som-page-1.json

jq -r '.data[].company_data.company_domain // empty' som-page-1.json | sort > som-domains.txt

To get the next page, pass back meta.nextCursor unchanged as cursor. A single walk stops after 10,000 rows by default. For a bigger SOM, split it by hqState or employeeRange and run several walks. For a full list of people in one segment, use POST /v1/exports on Solo ($97 a month) and above. It takes up to 50,000 rows a request. Bulk CSV export is not on Free.

Keep som-domains.txt. It is your baseline for the diff in Step 5.

The list is also the input for the next job. Enrich a company with POST /v1/companies/enrich, or find its buyers with GET /v1/companies/{domain}/people. Both spend records, so run them on the accounts you will work, not the whole SOM.

Step 5: Monitor with a monthly snapshot

The dataset is refreshed monthly. Each record also carries its own fetched_at date. So you re-run the counts once a month and log the totals.

python
import csv, datetime, os, requests

URL = "https://api.leadocean.io/v1/companies/search"
HEAD = {"x-api-key": os.environ["LEADOCEAN_API_KEY"]}
SEGMENTS = {
    "tam": {"industry": ["Computer Software"]},
    "sam": {"industry": ["Computer Software"], "employeeRange": ["51-200", "201-500"]},
    "som": {"industry": ["Computer Software"], "employeeRange": ["51-200", "201-500"], "hqCountry": ["US"]},
    "new_2026": {"industry": ["Computer Software"], "hqCountry": ["US"], "minFounded": 2026},
}

rows, today = [], datetime.date.today().isoformat()
for name, body in SEGMENTS.items():
    meta = requests.post(URL, params={"count": "true", "limit": 1}, json=body, headers=HEAD).json()["meta"]
    rows.append([today, name, meta.get("total"), meta.get("totalIsExact"), bool(meta.get("totalWithheld"))])

with open("tam-snapshots.csv", "a", newline="") as f:
    csv.writer(f).writerows(rows)

Run it from cron on the second day of each month: 0 7 2 * * python3 tam_snapshot.py. The new_2026 row is a cheap proxy for new entrants. You can add funding filters such as minLastFundingYear as another row. If a filter cannot be applied, meta.total comes back null with meta.totalWithheld set, and the script logs that instead of a wrong number.

Read the CSV as a trend. A TAM that grows 1 percent in a month is noise. A SOM that jumps, say, 8 percent in a month is a signal to refresh your target list and your forecast.

Pull the list again only when a layer moves by more than you care about, say 5 percent. Then diff the new domains against som-domains.txt. The diff costs records, so the free counts decide when to spend them.

What you get

The company counts below come from leadocean_count_companies on 2026-10-21. Each is exact and cost 0 records.

Layer (industry Computer Software)Companies
TAM: worldwide, all sizes27,143
SAM: 51-200 and 201-500 employees1,552
SOM: SAM with HQ in the US728

The SAM count shows the size-filter caveat from Step 1: 18,437 of the 27,143 companies sit in the 1-10 band. The SOM splits into 460 companies at 51-200 and 268 at 201-500, and 204 of them have an HQ in California.

The people counts come from leadocean_count_leads on the same day. They count mailable people, not companies, using the default email filter: verified, catch-all-valid or catch-all.

Segment (industry Computer Software, jobLevel C-Team or VP)Mailable peopleSame filters, no email condition
Worldwide, all company sizes10,91670,265
Worldwide, 51-200 and 201-500 employees3,40331,528
HQ in the US, 51-200 and 201-500 employees2,0138,187

The last row breaks down as 1,005 c_suite, 540 vp and 468 owner by seniority band, and 1,030 at 51-200 and 983 at 201-500 by company size. Each tool call returned "credits": 0.

The count-only search in Step 2 returns the envelope below. This is the response shape from the API reference, and the total is a placeholder:

json
{
  "success": true,
  "data": [],
  "meta": { "source": "leadocean", "count": 0, "total": 1234, "totalIsExact": true, "countOnly": true }
}

A list page from Step 4 returns an array of company documents. Each has company_data, company_detected_technologies, company_metrics and meta.

The page-level meta carries nextCursor.

Troubleshooting

ErrorCauseFix
401Missing, wrong or revoked keyRe-copy the key from app.leadocean.io and export $LEADOCEAN_API_KEY again.
429Above the plan's rate limit per account (5 a second on Free, 50 on Solo, 200 on Agency)Wait the Retry-After seconds. The monthly script sends four calls, so this only hits a large fan-out.
402Free plan: the 1,000 records are spentCounts stay free. Lower limit on list pulls or move to Solo at $97 a month. Free records do not reset.
Zero results or a total of 0A filter value outside the catalogue, such as industry: "Software"Call GET /v1/enums/industry and use the exact string it returns.
meta.total is null with totalWithheldA filter in the request could not be applied, so a number would be wrongDrop that filter from the count and say it narrows the list further at search time.
meta.depthCapped is trueOne walk reached 10,000 rowsNarrow the filters and run several smaller searches, or use POST /v1/exports.

FAQ

How many records does TAM monitoring cost?

Counts cost 0. The example spends 100 records on one page of the SOM list and then nothing each month. Only a re-pull of the list costs records, one per company returned.

How often does the data change?

The dataset is refreshed monthly. A monthly snapshot catches every change the data holds. Hourly polling returns the same totals until the next refresh.

Can LeadOcean push an alert when the market changes?

Not today. The API reference, October 2026, lists no webhook or watcher endpoint, so you poll with the script above. Crustdata's market analysis page, September 2026, describes watcher APIs that alert you by Slack or into your system. If push alerts matter more to you than a flat price, check that first.

What if my market is not an industry?

Use keywords for company description text, technologyCategories for what a company runs on its site, or hqSalesRegion for a territory. The same count call works with any filter from Step 1.

Can an AI agent run this?

Yes. The same counts work through the MCP server, and you can wire the snapshot into an agent loop. See a real-time B2B data provider for AI agents and real-time company data for investment platforms. More recipes are in the blog hub.

Size and monitor your market, free

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

Get your free API key →