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

How-to guide

How to enrich, score and route sign-ups (with the LeadOcean API)

One enrich call per sign-up, a scoring function you can read in a minute, and three routes.

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

Enrich each sign-up from the work email they typed, score the result against your ICP, then send the lead to sales, nurture or self-serve. It is one API call and about 40 lines of code.

TL;DR

  • One POST /v1/people/enrich call per sign-up, keyed on the email. A miss is a 404 and costs nothing.
  • Takes about 45 minutes to wire up. A scoring function decides the route: sales, nurture or self-serve.
  • Spends 1 LeadOcean record per matched sign-up. Free gives you 1,000 records, once, with no card.

Prerequisites

  • A LeadOcean key with the enrich scope, exported as $LEADOCEAN_API_KEY. Start free.
  • A webhook or queue that fires when a user signs up and hands you the email.
  • Somewhere to send the result: a CRM, a Slack channel or a sequencer. This guide stops at a JSON payload.
  • curl and Python 3.10 or later.

Step 1: Size your ICP first

Count the people you want before you wire anything. It tells you whether your scoring rules are realistic. leadocean_count_leads (and the search count=true parameter) spend no records.

Prompt for any MCP client connected to https://api.leadocean.io/mcp:

text
Use leadocean_count_leads with jobLevel ["VP","C-Team"],
jobFunction ["Sales & Business Development"],
employeeRange ["51-200","201-500"], country ["US"], facets false.

On 2026-10-21 this returned 61,084 people with a verified, catch-all-valid or catch-all email (203,746 with no email condition), across 28,019 employers. Those are the people your ICP rules describe. A sign-up that matches them scores high.

Step 2: Enrich the sign-up by email

Send the email from the sign-up form. Send exactly one identifier. reveal_email stays false: you already have the address.

bash
curl -s -X POST "https://api.leadocean.io/v1/people/enrich" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"email":"jane@acme.com"}'

Skip free-mail domains (gmail.com, outlook.com) before you call. The email input is for work addresses, and you save the record.

Step 3: Pull the fields you score on

The response carries the person's current role in contact_data.contact_current_experiences[], plus profile_data and, since October 2026, resume_data with past roles. Keep a small flat object.

python
import os, requests

API = "https://api.leadocean.io/v1/people/enrich"
HEADERS = {"x-api-key": os.environ["LEADOCEAN_API_KEY"]}
FREE_MAIL = {"gmail.com", "outlook.com", "yahoo.com", "icloud.com"}

def enrich(email: str):
    if email.split("@")[-1].lower() in FREE_MAIL:
        return None
    r = requests.post(API, headers=HEADERS, json={"email": email}, timeout=15)
    if r.status_code == 404:      # nobody matched, costs nothing
        return None
    r.raise_for_status()
    p = r.json()["data"]
    cur = (p["contact_data"].get("contact_current_experiences") or [{}])[0]
    return {
        "name": p["profile_data"].get("profile_full_name"),
        "title": cur.get("job_title", ""),
        "company": cur.get("company_name"),
        "domain": cur.get("company_domain"),
        "headcount": (cur.get("company_employees") or {}).get("number_of_employees"),
        "past_roles": len((p.get("resume_data") or {}).get("experiences", [])),
    }

Each item in contact_current_experiences[] carries job_title, company_name, company_domain and company_employees, per the enrich docs. Past roles sit in resume_data.experiences[].

Step 4: Score it

Keep scoring boring and visible. Four rules, each worth points. Tune the weights against the deals you actually closed.

python
def score(lead: dict | None) -> int:
    if not lead:
        return 0
    s = 0
    t = lead["title"].lower()
    if any(k in t for k in ("vp", "head of", "chief", "director", "founder")):
        s += 40
    if any(k in t for k in ("sales", "revenue", "growth", "marketing", "revops")):
        s += 25
    n = lead.get("headcount") or 0
    if 50 <= n <= 500:
        s += 25
    if lead["past_roles"] >= 3:
        s += 10
    return s

Step 5: Route it

Three routes. Put the thresholds in one place so sales can change them without you.

python
def route(email: str) -> dict:
    lead = enrich(email)
    pts = score(lead)
    if pts >= 70:
        dest = "sales"        # alert an owner, book a call
    elif pts >= 40:
        dest = "nurture"      # onboarding emails for a team buyer
    else:
        dest = "self_serve"   # product-led path, no human touch
    return {"email": email, "score": pts, "route": dest, "lead": lead}

Post that payload to your CRM or a Slack webhook. For a no-code version of the same idea, see enrich, classify and route leads from Typeform submissions.

Step 6: Make it safe to run on every sign-up

Sign-up webhooks retry, and the same person signs up twice. Cache the result by email so a retry never spends a second record. Never block the sign-up on the call: enrich after the account exists.

python
import json, sqlite3

db = sqlite3.connect("enriched.db")
db.execute("create table if not exists e (email text primary key, payload text)")

def route_once(email: str) -> dict:
    row = db.execute("select payload from e where email=?", (email,)).fetchone()
    if row:
        return json.loads(row[0])
    out = route(email)
    db.execute("insert into e values (?,?)", (email, json.dumps(out)))
    db.commit()
    return out

Run it from a background job, not the request that creates the account. If the call times out, route the sign-up to self-serve and retry later. A late score is better than a slow sign-up page.

Step 7: Check the funnel weekly

After a month, compare the three routes against what happened next. Which score band booked calls? Which self-serve sign-ups became paying teams anyway? Move the thresholds in route() until the sales band holds the sign-ups your reps would have picked by hand.

Check two numbers: the share of sign-ups that matched (your hit rate) and the share routed to sales. A hit rate under half usually means many personal emails. Fix that at the form, not in the scoring.

A sizing note: at 500 work-email sign-ups a month and a hit rate of 60 percent, you spend about 300 records a month. That fits a Solo plan at $97 a month with room to spare. The Free plan covers a test run of your first 1,000 matches.

What you get

The response shape from the API reference, with placeholder values. This is not a captured response.

json
{
  "success": true,
  "data": {
    "profile_data": { "profile_full_name": "Jane Doe" },
    "contact_data": {
      "has_email": true,
      "has_phone": false,
      "email_status": "verified",
      "email_type": "work",
      "contact_current_experiences": [
        {
          "job_title": "VP Sales",
          "company_name": "Acme",
          "company_domain": "acme.com",
          "company_employees": { "number_of_employees": 120 }
        }
      ]
    },
    "resume_data": { "experiences": [ { "job_title": "Director of Sales", "company_name": "Example Co" } ] },
    "meta": { "schema": "leadocean.person.v1" }
  }
}

And the router output for that sign-up:

json
{ "email": "jane@acme.com", "score": 75, "route": "sales" }

Source: api.leadocean.io/openapi.json, September 2026. Enrichment sees what is public and held in the dataset, which is refreshed monthly. Treat the score as a prior, not a verdict.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-keyCheck $LEADOCEAN_API_KEY and that the key has the enrich scope.
400More than one identifier in the bodySend only email, not email plus linkedin_url.
404Nobody matched the emailCosts nothing. Route to self-serve with score 0.
429Above the plan's rate limit (5 a second on Free, 200 on Agency)Honor Retry-After, queue sign-ups, or move up a plan.
402Records spentFree is 1,000 records for life. See pricing.
Empty contact_current_experiencesProfile has no current role on fileScore 0 for title, fall back to a manual review route.

FAQ

How many records does one sign-up cost?

One record per person we return. A 404 or an enrichment that finds nothing costs nothing. See pricing for what each plan includes.

Can I enrich by name and company instead of email?

No. Enrich takes one of linkedin_url, email, phone or person_id. If you only have a name and domain, search by domain first, then enrich by person_id.

Should I enrich personal-email sign-ups?

Usually not. A Gmail address gives the match little to work with. Ask for a work email at a later step, or route those sign-ups to self-serve.

Which enrichment tools can do this?

Several can. More guides like this one are on the blog. For a comparison, read best lead enrichment tools. To run the same job from an AI client, see the enrich leads prompt.

Enrich your next sign-up in one call

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

Get your free API key →