TL;DR
- A buying signal is a fact about a company that raises the odds it buys now. Funding, headcount band and tech stack are the three you can filter on in LeadOcean.
- The whole recipe takes 30 to 45 minutes. Sizing is free. Pulling the list spends about 400 records, inside the 1,000 on the Free plan.
- The signal decides who and when. Your message should name the signal in the first line.
Prerequisites
- A LeadOcean API key in
$LEADOCEAN_API_KEY. The Free plan gives 1,000 records for life, no card, 5 requests a second. curlandjq. Any language works the same way.- A sequencer or CRM to load the final list into. LeadOcean returns data. It does not send mail.
- One offer and one buyer title. Signals without an offer are just a list.
Step 1: Choose signals that match your offer
Pick signals that change what a company needs this quarter. Three travel well:
| Signal | LeadOcean filter | What it implies |
|---|---|---|
| Recent funding round | fundingType, minLastFundingYear | Budget, plus pressure to grow pipeline |
| Headcount band | employeeRange | Which stage the company is in |
| Tech on the website | technologies, technologyCategories | A tool you replace or sit beside |
Funding is stored as a year, not a date. Treat it as "this year or last", not "last 30 days". If you need day-level timing, add a news or job-board feed on top.
Our example: sell outbound tooling to Series A companies in the US with 11 to 200 employees, funded in 2025 or later.
Step 2: Size the list before you spend anything
Counting is free. Ask for the company count first.
curl -s -G https://api.leadocean.io/v1/companies/count \
-H "x-api-key: $LEADOCEAN_API_KEY" \
--data-urlencode 'fundingType=Series A' \
--data-urlencode 'minLastFundingYear=2025' \
--data-urlencode 'hqCountry=US' \
--data-urlencode 'employeeRange=11-50,51-200' | jq '.data.total'If the number is zero, loosen the year before you loosen anything else. On 21 October 2026 the same filter with minLastFundingYear=2026 returned 0 companies. That is the usual empty-result trap. The newest year can hold few rows, so start one year back.
The MCP tool leadocean_count_companies does the same call from Claude or ChatGPT with the same filters.
Step 3: Pull the companies that fired the signal
Now spend records. One company returned is one record. Keep limit at the size of your list.
curl -s -X POST https://api.leadocean.io/v1/companies/search \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"fundingType": ["Series A"],
"minLastFundingYear": 2025,
"hqCountry": ["US"],
"employeeRange": ["11-50", "51-200"],
"limit": 100
}' > companies.json
jq -r '.data[].company_data.company_domain' companies.json > domains.txtPage with cursor if the count is above 100. One search pages to 10,000 rows, which is far more than a signal list needs.
Step 4: Find the buyer at each company
Use the domain from Step 3 to get the people at that company, filtered to your buyer title.
while read d; do
curl -s -X POST https://api.leadocean.io/v1/people/search \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d "{\"domain\": [\"$d\"], \"jobFunction\": [\"Sales & Business Development\"],
\"jobLevel\": [\"VP\", \"C-Team\", \"Director\"], \"limit\": 3}"
sleep 0.25
done < domains.txt | jq -c '.data[]' > buyers.jsonlThe sleep keeps you under 5 requests a second on Free. Limit 3 per company caps the spend at about 3 records each.
Enum values are exact strings. Check them with leadocean_list_enum_values before you guess.
Step 5: Add a second signal, then rank
One signal is a weak filter. Two is a list worth writing to. Layer a tech signal on the people side and see how much it narrows, still for free.
{
"tool": "leadocean_count_leads",
"arguments": {
"jobLevel": ["VP", "C-Team"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"employeeRange": ["51-200", "201-500"],
"technologyCategories": ["Marketing automation"],
"facets": false
}
}Rank each company by how many signals it matches: funded this year or last (1 point), in your headcount band (1), uses the tool category (1). Send the 3-point accounts first, with a message that names the signal. Test two openers on the top tier before you scale, and keep the lower tiers for a second wave.
Subject: Series A and no outbound yet?
Hi Jane, congrats on the round. Teams at your size usually add outbound
in the next two quarters. We help with the data side: verified emails,
mailable counts before you pay. Worth a look?Replace the example name and company with the record you pulled. Do not send claims you cannot back from the data.
Step 6: Verify before you send and time the send
Signals fade. A round announced this quarter is a reason to write now, not in January. Send within a week of pulling the list, and check the email status on every row first.
jq -c 'select(.contact_data.email_status == "verified" or .contact_data.email_status == "catch_all_valid")' \
buyers.jsonl > send_list.jsonl
wc -l send_list.jsonlRows with risky, unknown or invalid stay out. There is no refund for bounced mail, so the filter is your protection. Search rows carry email flags, not addresses. To get the address, enrich by the row's meta.source_ids.person_id and set reveal_email to true.
curl -s -X POST https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"person_id": "PERSON_ID_FROM_SEARCH", "reveal_email": true}'An enrichment that finds nothing is a 404 and costs nothing.
Which signals to ignore
Not every signal earns a send. Three rules keep the list honest.
- Drop signals you cannot act on in a week. A round from three years ago is context, not a trigger.
- Drop signals that do not touch your offer. Funding matters to a pipeline tool. It does not matter to a payroll tool.
- Drop single-signal accounts when you have enough three-signal ones. Volume is cheap. Replies are not.
A useful habit: write the first line of the email before you pull the list. If you cannot name the signal in one sentence, the signal is too vague to filter on.
What you get
The count run on 21 October 2026, free, no records spent:
{
"total": 3300,
"totalIsExact": true,
"totalAll": 9664,
"distinctCompanies": 1934,
"credits": 0
}Label it correctly. 3,300 is the mailable count (verified, catch_all_valid or catch_all email). It covers US VP and C-Team sales leaders at companies with 51 to 500 employees where a marketing automation tool is detected on the website. Without the email condition the same filters match 9,664 people.
The free leadocean_count_companies tool ran the Step 2 filters the same day (Series A, minLastFundingYear=2025, HQ US, 11 to 200 employees). It returned 121 companies: 63 with 51 to 200 employees and 58 with 11 to 50. Software Development was the largest industry at 40, and California the largest state at 42.
Response shape from the API reference for each person in buyers.jsonl (placeholder values):
{
"profile_data": { "profile_full_name": "Jane Doe", "profile_headline": "VP Sales at Acme" },
"contact_data": {
"has_email": true,
"email_status": "verified",
"contact_current_experiences": [
{ "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com" }
]
},
"meta": { "source_ids": { "person_id": "1234567" } }
}Search rows hold email flags, not addresses. The address comes from the enrich call in Step 6.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key | Check $LEADOCEAN_API_KEY is exported in the shell that runs curl |
| 429 | Above the plan's rate limit (5 a second on Free, 200 on Agency) | Honour Retry-After, add sleep, or move to a plan with a higher limit |
| 402 | Out of records | Trim limit, or see pricing |
Empty data | A bad enum value or a year with no rows yet | Resolve values with leadocean_list_enum_values, then lower minLastFundingYear |
| Count is exactly 1,000 | A filter the people count does not support | Skip funding filters in leadocean_count_leads. Count companies instead |
| Export refused | Over 50,000 rows a request or 500,000 a day | Split the export by country or headcount band. Bulk CSV is not on Free |
FAQ
What counts as a buying signal?
Any observable change that makes a purchase more likely: a funding round, a hiring spike, a new executive, a tool added or dropped. See the buying signal glossary entry.
How many signals should I stack?
Two or three. One signal gives a long list with a low reply rate. Four usually leaves you with too few accounts to test anything.
Does LeadOcean track hiring or job changes?
LeadOcean has no live hiring or job-change feed. Person enrich returns past roles, so you can see tenure, and hiring-based timing is covered in the hiring signals guide.
How fresh is the data?
The dataset is refreshed monthly, and each record carries its own fetched_at date. Read it before you write "congrats on the round".
How much does this cost at scale?
Free covers about one run of this size. Solo is $97 a month for one person, and Agency is $497 a month for teams. Paid plans run on a fair-use pace, not credits.
Is a buying signal the same as intent data?
No. Intent data tracks what accounts research online, and it comes from third-party panels. Firmographic signals such as funding, size and tech stack are facts on a record. You can filter on them yourself and check them. Use intent data as a third layer if you already buy it.
How big should the first test be?
Fifty accounts is enough to compare two openers. Send half the list one opener and half the other, then read replies after two weeks. Do not scale a message that you have not tested on the three-signal tier.
Where does the list go next?
Export it or load it through the API into your sequencer or CRM. The LeadOcean app has an Exports page with a filter builder, a column picker and a price preview, and Solo and above can download a CSV. The sending happens in your own tool.
More on process: how to identify and act on buying signals. Browse all guides in the blog.
Build your first signal list for free
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →