TL;DR
- The ideal GTM stack has four layers: data, system of record, sending and orchestration. Anything else has to earn its seat with a number.
- It takes about 45 minutes and spends about 106 LeadOcean records. Sizing is free. On Free, swap the bulk export for a 100-row search pull.
- Buy the data layer first. Every other tool is only as good as the rows you feed it.
Prerequisites
- A LeadOcean API key from app.leadocean.io/register. The free plan has 1,000 records, one-off, no card, 5 requests a second.
- The key in your shell:
export LEADOCEAN_API_KEY=your_key_here. curlandjq.- A CRM and a sending tool you already use, or none yet. This guide does not need either to run.
- Optional: an MCP client, to size markets by chat.
Step 1: Write the stack down as four layers
A stack is a list of jobs, not a list of logos. Write one line per job and name the tool that does it. If two tools do the same job, cut one.
data: # who to contact, and how
source: LeadOcean API
job: search, enrich, verify email status, export
record: # where deals live
source: your CRM
job: accounts, contacts, deals, one owner per account
sending: # how messages leave
source: your email or sequencing tool
job: mailboxes, sequences, replies
orchestration: # how the other three talk
source: n8n, a script, or an MCP client
job: move rows from data to record to sendingApply one test to every tool already in your stack. Name the weekly action it triggers and the number that moves. If you cannot, pause the renewal for a month and see who notices.
Three things do not need a seat on day one. A dialer, if you do not cold call. An intent feed, until you can name one action it triggers. A second enrichment vendor, until the first one's miss rate is measured.
LeadOcean covers the data layer only. It has an app with an Exports page, but no sequencer, dialer, CRM or Chrome extension. Pair it with the tools you already run.
Step 2: Size the market before you buy anything
Count the accounts and the buyers, free, before you commit to a stack. If the list is 400 people, you need a spreadsheet. If it is 10,000, you need the four layers.
Company count first. GET /v1/companies/count takes the company-search filters and returns an exact total.
curl -s "https://api.leadocean.io/v1/companies/count?hqCountry=US&employeeRange=51-200,201-500&technologies=HubSpot" \
-H "x-api-key: $LEADOCEAN_API_KEY" | jq '.data | {total, totalIsExact}'Array filters in a query string are comma-separated. Then people. Add count=true and limit=1 as query parameters. No records are spent.
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 '{
"hqCountry": ["US"],
"employeeRange": ["51-200", "201-500"],
"technologies": ["HubSpot"],
"jobFunction": ["Sales & Business Development"],
"jobLevel": ["VP"],
"emailStatus": ["verified", "catch_all_valid", "catch_all"]
}' | jq '.meta | {total, totalIsExact, distinctCompanies}'count=true goes in the query string. The JSON body rejects unknown fields. Enum values are exact strings, so look them up with GET /v1/enums/{name} before you guess.
Step 3: Test the data layer on five rows
Spend 5 records, not 500. Remove count, set limit to 5, and read what comes back.
curl -s -X POST "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"limit": 5,
"hqCountry": ["US"],
"employeeRange": ["51-200", "201-500"],
"technologies": ["HubSpot"],
"jobFunction": ["Sales & Business Development"],
"jobLevel": ["VP"],
"emailStatus": ["verified", "catch_all_valid", "catch_all"]
}' | jq '.data[] | {has_email: .contact_data.has_email, email_status: .contact_data.email_status}'Search rows carry flags, not addresses. You see whether a deliverable email exists before you reveal it. Check each row against the person's real profile. If three of five are wrong, change the data source, not the sequencer.
Step 4: Enrich at the point of use
Do not enrich the whole database into your CRM. Enrich the person when a rep or an agent needs the address. POST /v1/people/enrich takes exactly one of linkedin_url, email, phone or person_id. Set reveal_email to true to get the address.
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 a search row>", "reveal_email": true}'A person we hold nothing for returns 404 and costs nothing. Since 17 October 2026 the response also carries career history: past roles, education and certifications, each when held. Past employers carry no company_id yet.
Step 5: Export to the sending layer
Pick the list you tested and export it. POST /v1/exports takes the same filters inside a filters object, plus a row limit. One export runs up to 50,000 rows, and the daily ceiling is 500,000 rows.
curl -s -X POST "https://api.leadocean.io/v1/exports" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"name": "HubSpot shops, VP Sales, US, 51-500",
"filters": {
"hqCountry": ["US"],
"employeeRange": ["51-200", "201-500"],
"technologies": ["HubSpot"],
"jobFunction": ["Sales & Business Development"],
"jobLevel": ["VP"],
"emailStatus": ["verified", "catch_all_valid", "catch_all"]
},
"limit": 100,
"preset": "full"
}'The API answers 202 with an export id. Poll GET /v1/exports/{id} until status is done, then read the signed downloadUrl. This export spends at most 100 records. Bulk CSV export is not on the Free plan, so a free key reaches the same step through the Exports page in the LeadOcean app or a smaller search pull.
Check email_status on every column before the import. Send to verified and catch_all_valid first, and treat catch_all as a smaller test batch. LeadOcean gives no refund for bounces, so the status column is your only protection.
Import the CSV into your CRM, then into the sequencer. That is the whole orchestration layer for a team of one. Add n8n or a script once you repeat this weekly.
Step 6: Give an agent the same data
If an AI client belongs in the orchestration layer, connect it to the hosted MCP server at https://api.leadocean.io/mcp. It signs in with OAuth, so no key is pasted. The server has 13 tools. Three of the free ones do the sizing and lookups above: leadocean_count_leads, leadocean_count_companies and leadocean_list_enum_values.
Start every agent session with a count. A prompt that works:
Use LeadOcean. Count mailable VPs of Sales at US companies with 51-500
employees that run HubSpot. Do not search yet. Tell me the total and
how many distinct companies it spans.For one account at a time, the tech stack qualifier skill checks a company against a technology rule. To see what a site runs without an account, use the free tech stack checker.
What you get
These numbers come from the free MCP tools on 2026-10-21. Filters: US headquarters, 51-200 and 201-500 employees, technologies: HubSpot.
| Question | Tool | Result |
|---|---|---|
| Companies that match | leadocean_count_companies | 29,037 (exact) |
| Mailable VPs of Sales at them | leadocean_count_leads | 10,023 people |
| Companies those people span | distinctCompanies | 4,993 |
| Same people, any email status | totalAll | 29,167 |
Both calls reported credits: 0. The people count covers verified, catch_all_valid and catch_all emails only. The gap between 10,023 and 29,167 is the people you cannot mail yet.
Read the stack decision from the numbers. About 5,000 reachable accounts is too many for a spreadsheet and enough to justify a sequencer. A list of 400 would not be.
A search row looks like this. This is the response shape from the API reference, with placeholder values.
{
"success": true,
"data": [
{
"profile_data": { "...": "identity and headline fields" },
"contact_data": {
"has_email": true,
"has_phone": false,
"email_status": "verified",
"email_type": "work"
},
"meta": { "...": "person_id and source fields" }
}
],
"meta": { "count": 1, "limit": 5, "credits": 1, "nextCursor": "<opaque string>" }
}One search pages to 10,000 rows. If meta.depthCapped is true, narrow the filters or use an export.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing, wrong or revoked key | Check the x-api-key header and that $LEADOCEAN_API_KEY is set in this shell. |
| 429 | More requests a second than the plan allows (5 on Free, 200 on Agency) | Wait for Retry-After, then retry. Slow the loop or move to a higher plan. |
| 402 | The free 1,000 records are spent | They are a one-off and do not reset. Pick a paid plan on the pricing page. |
| 400 or empty results | A filter value is not an exact enum string | Look it up with GET /v1/enums/{name} or leadocean_list_enum_values. |
| 404 on enrich | Nobody matched the input | Costs nothing. Try another identifier, such as linkedin_url. |
| Export refused | Over 50,000 rows a request or 500,000 a day | Split the list into smaller exports, or wait for the reset. |
FAQ
What is the minimum GTM tech stack?
Data, a system of record, a way to send and something that moves rows between them. For a team of one, the last layer is a CSV import. Add tools only when a measured number forces it.
Which tool should I buy first?
The data source. A sequencer sends whatever you give it, and a CRM stores it. Test the data on five rows before you pay for anything downstream.
Do I need an intent or technographic feed?
Only if a signal changes what you send. LeadOcean has a technologies filter, built from about 7.8M crawled company websites, which is a fraction of the database. It tells you a tool is on the site. It does not tell you the buyer is unhappy with it.
What does this guide cost on the free plan?
Sizing costs nothing. The five-row test costs 5 records, one enrichment costs 1 and a 100-row export costs 100. That leaves about 894 of your 1,000. On Free, make the 100 a search pull, because bulk export needs a paid plan.
Does LeadOcean replace my CRM or sequencer?
No. It is the data layer, with an API, an MCP server and an Exports page in the app. It has no rep workspace, sequencer, dialer or CRM.
Test the data layer of your stack free
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →