A buying signal only helps if it is wired to a list and a message the same day. This guide builds that for one signal type, recent funding, then adds two more: a new executive and a tech-stack match.
LeadOcean is a data API, not a signal feed. It holds firmographic fields you can filter on, and the dataset is refreshed monthly. Use it to turn a signal you already track into contacts. For a live event feed, pair it with a source that watches the news.
TL;DR
- Total time is about 20 minutes. Sizing is free.
- You spend about 30 records: 25 search rows and 5 enrichments.
- You end with a short list of buyers at recently funded companies, flagged for who is new in role, and ready to send.
Prerequisites
- A LeadOcean key from app.leadocean.io/register. The Free plan has 1,000 records for life and no card.
export LEADOCEAN_API_KEY=your_keyin your shell.curlandjq. Free allows 5 requests a second, so run the calls one at a time.
Step 1: Pick the signal and write the play first
Most teams collect signals and act on none of them. The fix is boring: write the play next to the signal before you touch the API. That also keeps you from pulling data you cannot use.
Decide what each signal triggers before you pull any data. A signal with no play is noise. Clay's own guide makes the same point and lists funding, hiring and job changes as the common ones (Clay, October 2026).
signal filter you can query play
funded in 2025 or later minLastFundingYear VP and C-team, growth message
new in role (under 90 days) resume_data on enrich congratulate, ask about priorities
site runs a tool you replace technologies switch messageKeep it to these three. Each maps to a field LeadOcean holds.
Step 2: Size the list for free
Sizing first tells you whether the signal is worth working. If the count is 40, you write by hand. If it is 40,000, you need a tighter filter before you spend anything. Counting also catches a bad enum value, because the call returns nothing instead of an error you notice later.
A count costs nothing. Send count=true as a query parameter with limit=1. meta.total is capped at 100,000.
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 '{
"jobLevel": ["C-Team", "VP"],
"jobFunction": ["Sales & Business Development"],
"hqCountry": ["US"],
"minLastFundingYear": 2025,
"emailStatus": ["verified", "catch_all_valid"]
}' | jq '.meta'The same check from the MCP server is leadocean_count_leads. For the account side use GET /v1/companies/count or leadocean_count_companies, also free.
Step 3: Pull the buyers
Pick the buyer by role, not by name. A funded company at 51 to 200 people usually has one head of sales and a few VPs, so the title filters are narrow on purpose. Add employeeRange to keep out the large companies where a raise means little.
Drop count, set a small limit, and keep the same body. Each person returned is one record, so 25 rows is 25 records.
curl -s -X POST "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"jobLevel": ["C-Team", "VP"],
"jobFunction": ["Sales & Business Development"],
"hqCountry": ["US"],
"employeeRange": ["51-200"],
"minLastFundingYear": 2025,
"emailStatus": ["verified", "catch_all_valid"],
"limit": 25
}' > page1.json
jq '.meta' page1.jsonRead meta.nextCursor and pass it back as cursor for the next page. One search pages to 10,000 rows. If meta.depthCapped is true, narrow the filters instead.
Step 4: Find who is new in role
New leaders buy. They have a mandate, a budget and no loyalty to the old vendor. Do not enrich the whole page, though. Enrich the five or ten people at companies you rank highest, and keep the rest as plain search rows. This keeps the record cost near 30.
Enrich a handful of the best-fit people and read their career history. Since October 2026 person enrich returns resume_data, with past roles and dates. Enrich takes exactly one of linkedin_url, email, phone or person_id.
PID=$(jq -r '.data[0].meta.source_ids.person_id' page1.json)
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\": \"$PID\"}" \
| jq '.data.contact_data.contact_current_experiences, .data.resume_data.experiences[0:2]'A current role that started in the last 90 days is your new-in-role flag. Past employers carry no company_id yet, so match them by name. A miss returns 404 and costs nothing.
Step 5: Add the tech-stack signal
Funding says the company has money. A tool in the stack says what it already pays for. The two together separate a company that might buy from one that is ready to switch. This is the cheapest signal to add, because the count is free and the filter is one array.
Filter companies by technology detected on their website. This covers about 7.8M crawled sites. Resolve names with leadocean_list_enum_values using tech_category before you guess.
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 '{"minLastFundingYear": 2025, "technologyCategories": ["Marketing automation"], "hqCountry": ["US"]}' \
| jq '.meta.total'Funded and running a tool category you sell against is a stronger list than either alone.
Step 6: Act on it
Order matters. Work the accounts with two signals first, then one signal plus a new executive, then funding alone. Put each reason in the first line of the message. A reader who sees the raise or the new title in line one knows why you wrote.
Keep the cadence short. Three touches over ten days is enough for a signal that fades in a few weeks. Stop when the window closes instead of running the list for a quarter.
Send only to addresses with email_status of verified or catch_all_valid. Write one line that names the signal, for example the raise or the new role. Send within days, not weeks.
For a bigger run, POST /v1/exports takes up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on Free.
What you get
Free counts run on 2026-10-21 through the MCP server.
People: jobLevel C-Team or VP, Sales & Business Development, HQ US,
funded 2025 or later
mailable (verified, catch_all_valid, catch_all): 4,594
no email filter: 10,918
distinct employers: 447
Companies: HQ US, 51-200 employees, funded 2025 or later
total: 429 (California 126, New York 58, Texas 28)A record-level search response has this shape, from the API reference. Values are placeholders.
{
"success": true,
"data": [
{
"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" } }
}
],
"meta": { "count": 25, "credits": 25, "nextCursor": "opaque-token" }
}Response shape from the API reference (openapi.json, October 2026). The id you pass to enrich sits at meta.source_ids.person_id on each row.
Read the numbers with care. The 4,594 is a mailable count, not everyone matching: it filters to verified, catch-all-valid and catch-all addresses. The 10,918 has no email condition. The gap is people we hold but cannot yet reach by a good email. Funding year is a filter on the employer, so a person who changed jobs after the round sits under the new employer's data. That is why Step 4 matters.
Also note what is missing. LeadOcean has no field for hiring volume or open job posts, so it cannot detect a hiring push. If that signal matters to you, source it elsewhere and match on domain.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key | Check $LEADOCEAN_API_KEY is exported and has no stray space |
| 429 | Above the plan rate limit (5 a second on Free, 200 on Agency) | Wait for Retry-After, then slow the loop |
| 402 | Records spent | Free is 1,000 for life. Pick a paid plan on pricing |
| Empty results | Bad enum value, such as Vice President for jobLevel | Use exact strings from leadocean_list_enum_values (VP, C-Team) |
| 404 on enrich | Nobody matched the input | Free. Try a different identifier |
Search stops, depthCapped true | 10,000-row depth reached | Narrow the filters and run smaller searches |
FAQ
What counts as a buying signal?
An observable event that raises the odds a company buys: a funding round, a new executive, a hiring push or a tool adoption. See buying signal for the short definition.
Does LeadOcean detect signals in real time?
No. It is a monthly-refreshed dataset you filter. Track live events elsewhere and use LeadOcean to find the contacts. The signal detection prompt shows one way.
Which signal works best?
Two signals together beat one. Funding plus a new executive is the strongest pair in this guide, because one shows budget and the other shows a decision-maker who has not chosen vendors yet.
How fresh is the funding data?
The dataset is refreshed monthly, and each record carries its own fetched_at date. A round announced last week may not be there yet. For same-day alerts, watch the news and use LeadOcean for the contacts.
How many records does this cost?
About 30 on the steps above. Counts, filter lookups and empty enrichments are free.
Where do I go next?
Read the outreach playbook for message structure. It is linked in the table below.
| Related reading | Link |
|---|---|
| Outreach playbook for signals | How to use buying signals in outreach |
Turn your next buying signal into a contact list
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →