A true intent feed tells you which accounts are researching a category right now. You can get most of the way there without one. Pair fit data with public timing signals, then enrich only the people who pass.
This guide builds that shortlist in five steps. Each one is a real request against https://api.leadocean.io.
TL;DR
- Fit plus timing beats fit alone. The timing signals here are funding year, detected technology and a recent role start. None is a live research signal, so treat them as proxies.
- It takes about 30 minutes. Sizing is free. The run spends about 110 records: 100 for one search page and 10 for enrichments.
- LeadOcean has no intent feed or alerts. You re-run the query on your own schedule and diff the results.
Prerequisites
- A LeadOcean account on the Free plan (1,000 records for life, no card): app.leadocean.io/register.
- An API key from the app, exported as
$LEADOCEAN_API_KEY. curlandjq. Free allows 5 requests a second, so keep loops sequential.- Optional: the hosted MCP server at
https://api.leadocean.io/mcpif you would rather run Step 1 from Claude.
Step 1: Size the fit audience for free
Count before you spend. A count costs no records, so run as many as you like.
Start with fit only: VPs of sales at US companies with 51-200 employees. Enum values are exact strings, so check them with GET /v1/enums if a filter returns nothing.
curl -s -G "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-d count=true -d limit=1 \
--data-urlencode 'jobLevel=VP' \
--data-urlencode 'jobFunction=Sales & Business Development' \
--data-urlencode 'hqCountry=US' \
--data-urlencode 'employeeRange=51-200' | jq .metacount=true goes in the query string with limit=1. meta.total is capped at 100,000 and meta.countOnly comes back true. The MCP tool leadocean_count_leads does the same job and returns the mailable total by default.
Step 2: Add a technology signal
A detected tool is a cheap proxy for a live problem. A company running a CRM is a fit for CRM-adjacent products. You see what is detected on the site, not what was removed.
Add technologies. It is detected on company websites and covers about 7.8M crawled sites.
curl -s -G "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-d count=true -d limit=1 \
--data-urlencode 'jobLevel=VP' \
--data-urlencode 'jobFunction=Sales & Business Development' \
--data-urlencode 'hqCountry=US' \
--data-urlencode 'employeeRange=51-200' \
--data-urlencode 'technologies=HubSpot' | jq .metaIf a company-side filter cannot be applied, the response names it in unsupportedFilters and withholds the total. Narrow with industry or a country and count again. Do not quote a total that came back withheld.
Step 3: Add a funding-recency signal
Fresh funding is the oldest timing signal in outbound. New money means new budget and new hires.
The funding filters are fundingType and minLastFundingYear. On a people search they apply only when the matching companies number 50,000 or fewer after the size, industry and country filters. Otherwise they land in unsupportedFilters. So keep the fit filters tight first.
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": ["VP"],
"jobFunction": ["Sales & Business Development"],
"hqCountry": ["US"],
"employeeRange": ["51-200"],
"technologies": ["HubSpot"],
"fundingType": ["Series A"],
"minLastFundingYear": 2025,
"emailStatus": ["verified", "catch_all_valid"],
"limit": 100
}' > page1.json
jq '.meta | {count, nextCursor, notice}' page1.jsonThe body is flat JSON. List filters are arrays of strings, and year filters are integers. limit runs 1 to 100, and you page with meta.nextCursor. This call spends one record per person returned, so up to 100.
Funding data is matched through the employer. A company with no funding figure on file is never returned. A missing match does not mean the company has no funding.
Step 4: Check for a recent role start
A new VP of sales hires tools in the first 90 days. Search does not filter on role start date, so check it on enrichment.
Pull meta.source_ids.person_id from the search page, then enrich a sample of ten. Enrichment takes exactly one of linkedin_url, email, phone or person_id.
for id in $(jq -r '.data[:10][].meta.source_ids.person_id' page1.json); do
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\": \"$id\"}" \
| jq '{role: .data.contact_data.contact_current_experiences[0], past: .data.resume_data.experiences[0:2]}'
sleep 0.3
doneThe current role is in contact_data.contact_current_experiences[]. Past roles are in resume_data.experiences[], with title, company name, start and end dates and job level. Past employers carry no company_id yet, so match them by name.
A person we hold nothing for returns a 404 and costs nothing. Add reveal_email only for people you will contact.
Step 5: Score and export
Every row on the page passed fit, technology and funding. Add the role-start check from Step 4 and score each person in a spreadsheet or a script. A plain count of signals works fine.
jq -r '.data[] | [
.profile_data.profile_full_name,
.meta.source_ids.person_id
] | @csv' page1.json > shortlist.csvFor the full list, use POST /v1/exports or the Exports page in the app. It has a filter builder, a column picker and a price preview before you start. Exports take up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on Free.
Re-run the same body weekly and diff person_id values. New ids are people who just entered your window.
What you get
Free count run on 2026-10-21 through leadocean_count_leads, using the Step 1 and Step 2 filters. Totals are mailable people (verified, catch_all_valid or catch_all).
Fit only
jobLevel VP, jobFunction Sales & Business Development,
hqCountry US, employeeRange 51-200
total: 23,999 (exact) no email condition: 86,697
distinct employers: 13,729
Fit + technologies HubSpot
total: 5,855 (exact) no email condition: 18,203
distinct employers: 3,284Adding one timing-style filter cut the audience from 23,999 to 5,855. Funding is not counted here, because free counts with funding filters are not reliable. The funding filter narrows the list further at search time.
Response shape from the API reference (placeholder values, one search row):
{
"data": [
{
"profile_data": { "profile_full_name": "Jane Doe" },
"contact_data": {
"has_email": true,
"has_phone": false,
"email_status": "verified"
},
"meta": { "source_ids": { "person_id": "1234567890" } }
}
],
"meta": { "count": 1, "nextCursor": "<opaque>", "source": "leadocean" }
}Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key header | Re-copy the key from the app and check $LEADOCEAN_API_KEY is exported |
| 429 | Requests above the plan's rate limit (5 a second on Free, 200 on Agency) | Honor Retry-After, add sleep between calls |
| 402 | The 1,000 free records are spent | Count only, or move to Solo ($97 a month) or Agency ($497 a month) |
| Empty results | A bad enum value, such as "United States" instead of US | Check exact values with GET /v1/enums/{name} |
Total missing, unsupportedFilters set | A company-side filter matched too many employers to apply | Narrow with industry or hqCountry, then count again |
| Export refused | Over 50,000 rows a request or 500,000 a day | Split the filters into slices under 50,000 rows |
FAQ
Is this real intent data?
No. Intent data usually means observed research behavior, such as content views or search activity. LeadOcean holds none. It holds firmographics, technology, funding and career history, which work as proxies for timing.
How fresh are the timing signals?
The dataset is refreshed monthly, and each record carries its own fetched_at date. A role change from last week may not be there yet.
How many records does the whole run cost?
About 110: one search page of 100 and ten enrichments. Counts, GET /v1/filters, GET /v1/enums and enrichments that find nothing are free.
Can I run this from Claude instead of curl?
Yes. The hosted MCP server has 13 tools, including leadocean_count_leads and leadocean_count_companies, both free. Sign in with OAuth, then ask for the counts in plain language. For related background, see buyer's journey intent data.
What should I do with the shortlist?
Clean it first. Our guides on fixing a messy CRM and enrichment tools for RevOps cover that step. Plans and pace limits are on the pricing page. More guides are on the blog.
Build your timing shortlist with real data. Start free.
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →