You get a HubSpot workflow that takes a company you already sell to and creates similar companies in HubSpot. LeadOcean does the matching: same industry, same headcount bracket, same headquarters country. There is no HubSpot listing for LeadOcean, so the call is a plain HTTP request to https://api.leadocean.io from one custom code action.
How it works
The trigger is a checkbox on the seed company. The action reads the seed from LeadOcean, searches for matches and writes them to HubSpot. HubSpot says custom code actions need a Data Hub Professional or Enterprise account (HubSpot docs, October 2026).
- Create a LeadOcean key. Sign up at app.leadocean.io/register. No card, 1,000 records.
- Add two secrets. In the custom code action, click Add secret. Add
LEADOCEAN_API_KEYand a HubSpot private app token with company write scope. Secrets reach the code asprocess.envvariables (HubSpot docs, October 2026). - Create a company-based workflow. Create a company property
lookalike_seed(single checkbox). Enroll companies where it is true and Company domain name is known. - Add a Custom code action. Language Node.js. Add
domainas an input property. Paste the code below. - Size the list first. Call
GET /v1/companies/countwith the same filters. It is free and returns an exact total, so you know how many records a run will spend. - Test on one seed, then turn it on. A test spends up to 26 LeadOcean records: 1 seed and 25 matches.
LeadOcean matches on firmographic filters. It is not a model score. Say that to whoever reads the list.
Configuration
HubSpot lists axios as a supported Node.js library (HubSpot docs, October 2026). Company creation is POST /crm/v3/objects/companies, and domain is the unique identifier HubSpot uses to avoid duplicates (HubSpot docs, October 2026).
const axios = require('axios');
const LO = { headers: { 'x-api-key': process.env.LEADOCEAN_API_KEY } };
const HS = { headers: { Authorization: 'Bearer ' + process.env.HUBSPOT_TOKEN } };
exports.main = async (event, callback) => {
const domain = event.inputFields['domain'];
// 1 record: the seed
const seed = (await axios.post('https://api.leadocean.io/v1/companies/enrich',
{ domain }, LO)).data.data.company_data;
// up to 25 records: the lookalikes
const found = (await axios.post('https://api.leadocean.io/v1/companies/search', {
industry: [seed.company_industries[0].name2],
employeeRange: [seed.company_employees.number_of_employees_code],
hqCountry: [seed.company_primary_address.country_code],
hasMailableContacts: true,
limit: 25,
fields: ['company_data.company_name', 'company_data.company_domain']
}, LO)).data.data;
let created = 0;
for (const c of found) {
const d = c.company_data;
if (!d.company_domain || d.company_domain === domain) continue;
try {
await axios.post('https://api.hubapi.com/crm/v3/objects/companies',
{ properties: { name: d.company_name, domain: d.company_domain } }, HS);
created++;
} catch (e) { /* duplicate or bad row: skip it */ }
}
callback({ outputFields: { created } });
};The seed fields come from company_data: company_industries[0].name2, company_employees.number_of_employees_code and company_primary_address.country_code (LeadOcean docs). Any of them can be null, so guard them in production. Check the same search outside HubSpot first:
curl -X POST "https://api.leadocean.io/v1/companies/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"industry":["Software Development"],"employeeRange":["51-200"],"hqCountry":["US"],"limit":25}'Industry and headcount values are exact strings. Look them up free with list_enum_values or GET /v1/enums (LeadOcean docs, September 2026).
Field mapping
| LeadOcean field | HubSpot property | Note |
|---|---|---|
company_data.company_name | name | Sent on create. |
company_data.company_domain | domain | Primary unique identifier in HubSpot. Never create without it. |
seed domain | custom lookalike_of | Create a text property so you can report by seed. |
| run date | custom lookalike_added_on | Date property. Lets you filter new rows. |
Cost at 10,000 rows
10,000 lookalikes cost $97 on LeadOcean Solo, plus HubSpot Data Hub Professional. Take 400 seeds at 25 rows each: 10,000 search records plus 400 seed lookups. Solo allows 100k search records every 5 hours (LeadOcean pricing). Free stops at 1,000 records, which covers about 38 seeds.
| LeadOcean | HubSpot | |
|---|---|---|
| Plan | Solo, $97 a month, flat | Data Hub Professional |
| Price | No per-record price, fair-use pace | Listed on HubSpot pricing |
| Free tier | 1,000 records, once | Workflows with webhooks and custom code are not on it |
Teams running many seeds a day should read the Agency plan on the pricing page.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| 400 from LeadOcean search | Industry or range is not an exact enum value | Fetch the value with GET /v1/enums and map it. |
Empty found list | Filters too narrow | Drop hqCountry, then hasMailableContacts, one at a time. |
| 401 from LeadOcean | Wrong secret name | Match the secret name to process.env. |
| 402 from LeadOcean | The free 1,000 records are spent | Move to Solo. Free records do not renew. |
| 429 from LeadOcean | Over the rate limit | 5 requests a second on Free, 50 on Solo (LeadOcean docs, September 2026). |
| 401 from HubSpot | Token lacks company write scope | Add the scope to the private app. |
| Same seed runs twice | Checkbox stays true | Add a final action that clears lookalike_seed. |
FAQ
Can I use the Send a webhook action instead of code?
Possibly. The action sends POST or GET requests and can set a header API key (HubSpot docs, October 2026). It needs Data Hub Professional or Enterprise too. The seed's industry must match a LeadOcean enum, so code is simpler.
Is this a similarity score?
No. It is a filter match on industry, headcount and country. See the lookalike skill for the same logic in Claude.
Do I need HubSpot Data Hub?
For the workflow, yes. Without it, run the same script from cron against the HubSpot companies API.
Where else can I find companies?
See find companies and our lookalike tool comparison.
Turn your best HubSpot customers into a target list
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →