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

How-to guide

How to Build a Prospect List by Tech Stack (With the LeadOcean API)

Name the tool, size the audience for free, spot-check five rows, then pull the list or export it to CSV.

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

TL;DR

  • A tech-stack list is a people search with one extra filter: technologies (a tool by name) or technologyCategories (what the tool is for).
  • It takes about 20 minutes. Sizing is free, and the example list spends about 505 of your 1,000 free records.
  • The tech signal covers about 7.8M crawled company websites, not the whole database. Size the audience before you buy it.

Prerequisites

  • A LeadOcean API key from app.leadocean.io/register. The free plan has 1,000 records, one-off, no card.
  • The key in your shell: export LEADOCEAN_API_KEY=your_key_here.
  • curl and jq. Any HTTP client works the same way.
  • Optional: an MCP client such as Claude, if you want to size audiences by chat instead of curl.

Step 1: Pick the signal and name it

Pick one tool that predicts a sale, then decide whether you filter by name or by category. Name is narrow. Category is wide.

  • By name: technologies: ["HubSpot"]. Use it when your product replaces, extends or plugs into one tool.
  • By category: technologyCategories: ["Marketing automation"]. Use it when any tool in the class is a fit.

Matching on technologies is case-insensitive. On 2026-10-21 a count with hubspot returned the same total as HubSpot. Category values are exact strings, so look them up instead of guessing. The lookup is free.

bash
curl -s "https://api.leadocean.io/v1/enums/tech_category?q=CRM" \
  -H "x-api-key: $LEADOCEAN_API_KEY"

Clay's guide builds the same list inside Clay from a separate technographic source (Clay, September 2026). Here the signal is a filter on the same search you already use for people.

Step 2: Add the people filters

Tech tells you which companies. Title, level and size tell you who to write to. Combine them in one flat JSON body: every filter is an array, and enum values are exact strings.

json
{
  "technologies": ["HubSpot"],
  "hqCountry": ["US"],
  "employeeRange": ["51-200", "201-500"],
  "jobFunction": ["Sales & Business Development"],
  "jobLevel": ["VP"],
  "emailStatus": ["verified", "catch_all_valid", "catch_all"]
}

hqCountry is the company's headquarters. country is where the person sits, so use hqCountry for a tech list. The emailStatus line keeps only addresses worth sending to. Drop it and you pay for rows you cannot mail.

Step 3: Size the audience for free

Add count=true as a query parameter and set limit to 1 in the body. You get meta.total and an empty data array. No records are spent, however often you ask.

bash
curl -s -X POST "https://api.leadocean.io/v1/people/search?count=true" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "limit": 1,
    "technologies": ["HubSpot"],
    "hqCountry": ["US"],
    "employeeRange": ["51-200", "201-500"],
    "jobFunction": ["Sales & Business Development"],
    "jobLevel": ["VP"],
    "emailStatus": ["verified", "catch_all_valid", "catch_all"]
  }' | jq '.meta | {total, totalIsExact, countOnly}'

count=true goes in the query string. The JSON body rejects unknown fields. The total is capped at 100,000, and totalIsExact tells you when it is a floor.

Run it three or four times with the filters changed. Swap the tool name, widen the size band, add a second country. You are tuning the list before it costs anything.

Step 4: Spot-check five rows

Pull five rows before you export hundreds. Remove count, set limit to 5, and read what comes back.

bash
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,
    "technologies": ["HubSpot"],
    "hqCountry": ["US"],
    "employeeRange": ["51-200", "201-500"],
    "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}'

This costs 5 records. Search rows carry flags, not addresses, so you see whether a deliverable email exists before you buy it. Open each company's site and confirm the tool is really there. The detection reads each company's own website, so a tool that never shows up in page code will not be matched.

To work account-first, call POST /v1/companies/search with the same technologies filter. Each company costs one record, and the row includes company_detected_technologies. Then pull people with GET /v1/companies/{domain}/people.

Step 5: Pull the list, or export it as CSV

On the free plan, page the same search. Set limit to 100 and pass meta.nextCursor back as cursor until you have 500 rows. That is five pages and 500 records. Write the rows to a file with jq.

Bulk CSV export is not on Free. It is included on Solo ($97 a month) and Agency ($497 a month, 50k rows a file). Export with POST /v1/exports. It takes the same filters, minus limit, count, cursor and facets, plus a row limit. One export runs up to 50,000 rows. The daily ceiling is 500,000 rows.

bash
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": {
      "technologies": ["HubSpot"],
      "hqCountry": ["US"],
      "employeeRange": ["51-200", "201-500"],
      "jobFunction": ["Sales & Business Development"],
      "jobLevel": ["VP"],
      "emailStatus": ["verified", "catch_all_valid", "catch_all"]
    },
    "limit": 500,
    "preset": "full"
  }'

The answer is HTTP 202 with an export id and status: queued. Poll GET /v1/exports/{id} until status is done, then read the signed downloadUrl. Each row costs one record, so this export spends at most 500.

No code? On a paid plan, the Exports page in the LeadOcean app has a filter builder, a column picker, the record price before you start and a Download button. It does the same job without curl.

What you get

Counts below come from the free leadocean_count_leads MCP tool on 2026-10-21, with no email filter passed. The tool's default counts mailable people (best email verified, catch_all_valid or catch_all). Filters: US company headquarters, job function Sales & Business Development, job level VP.

Tech filterCompany sizeMailable people
technologies: HubSpotany35,686
technologies: HubSpot51-200 and 201-50010,023
technologies: Salesforce51-200 and 201-500851
technologyCategories: Marketing automation51-200 and 201-5002,735

Each call returned totalIsExact: true, credits: 0 and an empty unsupportedFilters list. The category lookup for CRM returned the label "CRM (35,416 companies)" from the 2026-09-07 crawl.

Two things to read from this. First, the Salesforce count is far below HubSpot. Detection reads each company's own website, so a tool that leaves little trace in public page code is likely under-counted. Second, these are counts of people, not companies. The 10,023 HubSpot people span 4,993 employers (distinctCompanies).

A search row looks like this. This is the response shape from the API reference, with placeholder values.

json
{
  "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>" }
}

Paginate by passing meta.nextCursor back unchanged. One search pages through at most 10,000 rows by default, so use exports for anything larger.

Troubleshooting

ErrorCauseFix
401Missing, wrong or revoked keyCheck x-api-key and that $LEADOCEAN_API_KEY is set in this shell.
403The key lacks the scope for that endpointUse a key with the search scope. Exports that reveal contact points also need enrich.
429Above your plan's rate limit: 5 a second on Free, 50 on Solo, 200 on AgencyWait for Retry-After and retry.
402The free 1,000 records are spentThey are a one-off and do not reset. Move to Solo ($97) or Agency ($497) to keep going.
400A bad filter value or an export over 50,000 rowsRead error.details for the field. Look up enum values with GET /v1/enums/{name}. Split big exports.
429 on POST /v1/exportsThe daily or period export ceilingWait for the reset, or narrow the list and export in smaller runs.
meta.total is nullA filter could not be applied, so the count is withheldRead meta.totalWithheld.filters, drop or replace that filter and count again.

FAQ

Is the tech filter available for every company?

No. It reads technologies detected on company websites, which covers about 7.8M crawled companies, roughly an eighth of the database. The category counts date from the 2026-09-07 crawl. Companies we have not crawled never match a tech filter.

Should I filter by technologies or technologyCategories?

Use technologies when one named tool is the trigger, such as a competitor or an integration partner. Use technologyCategories when any tool of that kind fits. Categories are a closed list of 105 values.

Does a tech filter tell me the company is unhappy with the tool?

No. It tells you the tool is on the site. Pair it with a second signal such as headcount band or a recent funding year before you write the pitch.

What does this cost on the free plan?

Sizing costs nothing. The five-row spot-check costs 5 records and a 500-row pull costs 500. That leaves about 495 of your 1,000 free records. CSV export needs Solo or above.

Build your first tech-stack list free

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

Get your free API key →