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

Smartlead recipe

LeadOcean + Smartlead: find lookalikes of warm leads and email them

Take the companies that already engaged with you, find firmographic matches in LeadOcean, pull one buyer at each, and load them into a Smartlead campaign.

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

You get a short script that turns warm leads into new prospects. It reads the companies that already engaged, finds companies with the same industry, size and country in LeadOcean, pulls one buyer at each, and posts them to a Smartlead campaign. Clay's template does the same job with Common Room and RB2B as the warm-lead sources (Clay template, September 2026). This recipe needs no Clay table.

Lookalike here means matching firmographic filters, not a similarity score. LeadOcean does not rank companies by resemblance.

Related: the Smartlead integration, company lookalikes from HubSpot, Salesloft and pricing.

How it works

  1. Get a free key. Sign up at app.leadocean.io/register. No card, 1,000 records.
  2. List your warm leads. Export the company domains of people who replied, booked or visited from your CRM or Smartlead. One domain per line in warm.txt.
  3. Read each seed company. Call POST /v1/companies/enrich with the domain. Keep industry, employee range and HQ country.
  4. Search for matches. Call POST /v1/companies/search with those three filters and drop the seed domain. Save the matched domains to lookalike_domains.txt.
  5. Size it first. Add count=true and limit=1 as query parameters. That call is free. GET /v1/companies/count is also free and breaks the total down by industry and country.
  6. Pull one buyer per company. Call POST /v1/people/search with the domain and a jobLevel, limit 1. Enrich that person_id with reveal_email for the address.
  7. Post to Smartlead. Send the rows to the campaign in batches of 400, the documented maximum (Smartlead Add Leads to Campaign, September 2026).

Run the script on a schedule, for example weekly, against the latest warm domains.

Configuration

Seed, then search. Replace acme.com with a warm lead's domain.

bash
curl -X POST https://api.leadocean.io/v1/companies/enrich \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain":"acme.com"}'

curl -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 '{"industry":["Software Development"],"employeeRange":["51-200"],"hqCountry":["US"],"excludeName":["Acme"]}'

employeeRange takes bands such as 11-50, 51-200 and 201-500, hqCountry takes two-letter codes, and industry takes one of 534 exact strings (API reference, October 2026). Look them up free with leadocean_list_enum_values. From the seed, read company_industries[0].name2, company_employees.number_of_employees_code and company_primary_address.country_code.

The load step. The script is ours; the Smartlead endpoint is theirs.

python
import os, requests

LO = "https://api.leadocean.io"
H = {"x-api-key": os.environ["LEADOCEAN_API_KEY"]}
SMARTLEAD = f"https://server.smartlead.ai/api/v1/campaigns/{os.environ['CAMPAIGN_ID']}/leads"
KEY = {"api_key": os.environ["SMARTLEAD_API_KEY"]}

def buyer(domain):
    # 1 record if someone matches, 0 if the page is empty
    rows = requests.post(f"{LO}/v1/people/search", headers=H,
                         json={"domain": [domain], "jobLevel": ["VP"], "limit": 1}).json().get("data", [])
    if not rows:
        return None
    pid = rows[0]["meta"]["source_ids"]["person_id"]
    # 1 record; a 404 costs nothing
    r = requests.post(f"{LO}/v1/people/enrich", headers=H,
                      json={"person_id": pid, "reveal_email": True})
    return r.json()["data"] if r.ok else None

leads = []
for domain in open("lookalike_domains.txt").read().split():
    p = buyer(domain)
    emails = (p or {}).get("contact_data", {}).get("contact_emails") or []
    if not emails or emails[0]["status"] not in ("verified", "catch_all_valid"):
        continue
    role = p["contact_data"]["contact_current_experiences"][0]
    leads.append({"email": emails[0]["email"],
                  "first_name": p["profile_data"]["profile_first_name"],
                  "last_name": p["profile_data"]["profile_last_name"],
                  "company_name": role["company_name"],
                  "custom_fields": {"job_title": role["job_title"], "seed": "warm"}})

for i in range(0, len(leads), 400):
    print(requests.post(SMARTLEAD, params=KEY, json={"lead_list": leads[i:i+400]}).json())

Each company costs up to 2 records: the search row and the enrichment. GET /v1/companies/{domain}/people has no seniority filter, so people search with domain and jobLevel is the cheaper way to one buyer. Run it on five domains before the full list. Smartlead reads the key from an api_key query parameter, so keep the script out of shared logs.

Field mapping

Smartlead requires email. Every other field is optional (Smartlead docs, September 2026).

LeadOcean fieldTarget field (Smartlead)Note
contact_emails[0].emailemailThe script skips anything not verified or catch_all_valid.
profile_data.profile_first_namefirst_nameMerge field for step one.
profile_data.profile_last_namelast_name
contact_current_experiences[0].company_namecompany_name
contact_current_experiences[0].job_titlecustom_fields.job_titleFree text for personalization.
contact_emails[0].statuscustom_fields.email_statusAdd it if you want to split catch-all later.
Seed company domaincustom_fields.seedNames the warm lead this match came from.

Cost at 10,000 rows

For 10,000 contacts, LeadOcean costs Solo at $97 a month, or Agency at $497 a month for teams, with a fair-use pace and no per-record price. Smartlead's Base plan lists 2,000 contacts, so 10,000 leads need Pro, listed at $78 a month with 30,000 contacts and 90,000 sends. The page has a Monthly and Yearly toggle with 17% off yearly, so check which view you are reading (Smartlead pricing, October 2026).

ItemLeadOcean FreeSolo or Agency
Records1,000 for life, one-offFair-use pace
Seed, search and buyer1 record per company or person returnedInside the pace
CountsFreeFree
Smartlead contacts1,000 fits Base10,000 needs Pro

On Free, the 1,000 records are shared by seeds, matched companies and people. Size the list with the free count before you start. Mailboxes and sending domains cost extra on the Smartlead side.

Troubleshooting

SymptomCauseFix
Search returns the seed itselfThe seed's name was not excluded.Set excludeName and drop the seed domain in code.
Fewer than 10 matchesFilters too tight.Drop hqCountry, then widen the size band, one change at a time.
Enum value rejectedIndustry or range string is not exact.Look it up with leadocean_list_enum_values.
Rows have no emailNo address held, or not verified or catch_all_valid.Expected. The script skips them.
skipped_count above zeroDuplicate or unsubscribed leads.Read skipped_leads for the reason.
402 from LeadOceanFree records are spent.Upgrade, or lower the batch.
429 from LeadOceanAbove 5 requests a second on Free.Sleep between calls.

FAQ

Is this a real lookalike model?

No. It matches industry, employee range and HQ country from the seed. That is predictable and cheap to rerun. If you need a score, add one in your own code after the search.

Can I run it from Claude instead?

Yes. The MCP server at https://api.leadocean.io/mcp has get_company, search_companies and the free count_companies, with OAuth sign-in and no key pasted. Build the list there, then run the load script.

Why one buyer per company?

One contact per account keeps a campaign from emailing five people at the same firm. Raise the cap once you see reply rates.

Do bounced emails get a credit back?

No. LeadOcean gives no refund for bounces. Read email_status and keep catch-all addresses in a small campaign of their own.

Find lookalikes of your warm leads, free

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

Get your free API key →