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

How-to guide

How to Automate Pre-Call Account Research and ABM Scoring (with Claude)

Score 25 accounts with a script you can read, then let Claude write the brief for the top five.

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

TL;DR

  • You score a list of target accounts with a small jq rubric, so the number is the same every run. Claude then writes the pre-call brief for the accounts that score highest.
  • The first setup takes about 45 minutes. A refresh takes under 5.
  • 25 accounts spend up to 60 of your 1,000 free records. Counts and filter lookups cost 0, and accounts that fail the free gate are never enriched.

Prerequisites

  • A LeadOcean account from app.leadocean.io. The free plan has no card and 1,000 records, one-off.
  • A key in your shell as $LEADOCEAN_API_KEY, plus curl and jq.
  • Claude with the LeadOcean connector for Step 6. Setup is on Connect LeadOcean to Claude. Claude Code works too.
  • A text file of 25 account domains, one per line. The examples use placeholders such as acme.com.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"
printf '%s\n' acme.com example.com > accounts.txt   # replace with your 25 domains

Crustdata published a version of this workflow on 9 May 2026 (checked October 2026). It scores in natural language and leans on hiring and funding signals. This one scores in code, with fields LeadOcean holds.

Step 1: Write the rubric as code

Put the score in a script, not in a prompt. A prompt gives a different 7 out of 10 each run. A script gives the same score until the data changes.

Every account gets 100 points. Four checks, each answerable from one free count or one company lookup:

CheckPointsSource
Senior coverage: C-Team, VP or Director people we hold with a verified or catch-all email35 at 10 or more, 25 at 3 to 9, 12 at 1 to 2Free count
Headcount of 201 to 1,00030 (15 for 51 to 200 or 1,001 to 5,000, 5 otherwise)Company lookup
A CRM or marketing automation category found on the website25Company lookup
A funding record dated 2025 or later10Company lookup

Change the weights to match your ICP. Any field can be null, so a missing value scores 0 and is not an error. The tech and funding checks read the raw fields as text, so they work whatever shape the record holds.

bash
cat > score.jq <<'JQ'
def band($n): if $n >= 10 then 35 elif $n >= 3 then 25 elif $n >= 1 then 12 else 0 end;
def size($n):
  if $n == null then 0
  elif $n >= 201 and $n <= 1000 then 30
  elif ($n >= 51 and $n < 201) or ($n > 1000 and $n <= 5000) then 15
  else 5 end;
.data as $d
| ($d.company_data.company_employees.number_of_employees) as $emp
| ($d.company_data.company_technology_categories // [] | tostring
    | test("CRM|Marketing automation")) as $tech
| ($d.company_data.company_funding // {} | tostring | test("202[5-9]")) as $fresh
| { domain: $d.company_data.company_domain, seniors: $seniors,
    pts: { coverage: band($seniors), size: size($emp),
           tech: (if $tech then 25 else 0 end),
           funding: (if $fresh then 10 else 0 end) } }
| .score = (.pts | add)
JQ

Step 2: Gate the list with free counts

Count senior people at each domain before you spend anything. A search with count=true as a query parameter and limit at 1 is free. The body is flat JSON and filters are arrays.

bash
mkdir -p out
while read -r d; do
  n=$(curl -s "https://api.leadocean.io/v1/people/search?count=true" \
    -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
    -d "{\"domain\": [\"$d\"], \"jobLevel\": [\"C-Team\",\"VP\",\"Director\"],
         \"emailStatus\": [\"verified\",\"catch_all_valid\",\"catch_all\"], \"limit\": 1}" \
    | jq '.meta.total // 0')
  echo "$d $n"
done < accounts.txt | tee out/seniors.txt

Drop every domain with a count of 0. We hold nobody senior there, so the later steps would spend records on thin results. The count covers only people with a verified, catch_all_valid or catch_all email, because the call filters emailStatus.

Step 3: Look up the accounts that passed

Each company lookup is one record. A company we hold nothing for is a 404 and costs nothing. The call takes a domain.

bash
while read -r d n; do
  [ "$n" -gt 0 ] || continue
  curl -s https://api.leadocean.io/v1/companies/enrich \
    -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
    -d "{\"domain\": \"$d\"}" > "out/$d.json"
done < out/seniors.txt

The response carries company_data with headcount, funding and company_technology_categories, plus company_detected_technologies and meta.fetched_at. The field list is on the company lookup docs.

Step 4: Score and rank

Join each saved lookup with its senior count and run the rubric. The output is one JSON line per account, sorted high to low.

bash
while read -r d n; do
  [ -f "out/$d.json" ] && jq -c --argjson seniors "$n" -f score.jq "out/$d.json"
done < out/seniors.txt | jq -s -c 'sort_by(-.score)[]' | tee out/scored.jsonl

Read the top of the list yourself before you trust it. If an account you know is a bad fit scores 85, change the weights, not the prompt. Keep the old scored.jsonl next to the new one. A diff between two weeks shows which accounts moved and which check moved them, and that line is often the best opener for the call.

Step 5: Pull the roster for the top five

Research only the accounts you will call. Take five senior people per account, which caps the spend at 25 records. Search rows are thin and carry no addresses.

bash
head -5 out/scored.jsonl | jq -r .domain | while read -r d; do
  curl -s https://api.leadocean.io/v1/people/search \
    -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
    -d "{\"domain\": [\"$d\"], \"jobLevel\": [\"C-Team\",\"VP\",\"Director\"],
         \"excludeTitle\": [\"assistant\",\"intern\"], \"limit\": 5}" > "out/$d.people.json"
done

Then enrich the two people you will meet on each call. One enrichment is one record. Send exactly one identifier, here the person_id from meta.source_ids.person_id on the search row.

Enrichment is where the pre-call research lives. Since 17 October 2026 the record carries career history in resume_data: past roles with title, company and dates, plus education and certifications, each when we hold it. A buyer who ran the same tool at a former employer is the first thing to look for. Past employers carry no company_id yet, so name the company in the brief rather than looking it up.

bash
curl -s 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 the search row>", "reveal_email": true}'

Step 6: Have Claude write the brief

Give Claude the scored rows and the roster, and one rule: use only what is in the data. LeadOcean holds firmographics, website technologies and people. It holds no news, hiring or intent signals, so the brief must say so.

text
Here are the scored accounts (out/scored.jsonl) and the rosters (out/*.people.json).
For each of the top five accounts write a half-page brief:
1. Score and the four point components, in one line.
2. Why it ranked where it did, using only those components.
3. Who to speak to: three people from the roster with title and email_status.
   For enriched people, add their last two past roles from resume_data.experiences.
4. Gaps: every field that is null, and the checks to do by hand (news, hiring).
Do not add news, quotes or numbers that are not in the files.
Do not change the scores.

In Claude with the connector you can also ask it to run leadocean_count_leads itself. It signs in with OAuth, so no key goes into the chat. In Claude Code, point it at the out/ folder and let it read the files.

Step 7: Run it before every call block

Save Steps 2 to 4 as refresh.sh and run it from cron on Monday morning. Keep the spend visible by printing the record count at the end.

bash
curl -s https://api.leadocean.io/v1/account -H "x-api-key: $LEADOCEAN_API_KEY" | jq .

Check it after each run. A rubric that quietly widens a roster to 100 rows shows up here first. The dataset is refreshed monthly, so a weekly run mostly re-scores the same data.

What you get

Step 2 is a real run. We ran it on 2026-10-21 with leadocean_count_leads, which spends 0 records, on the placeholder domain acme.com. All three totals count mailable addresses only (verified, catch_all_valid or catch_all), the tool's default. Trimmed:

json
{ "filters": { "domain": ["acme.com"] }, "total": 32, "totalIsExact": true, "totalAll": 707 }
{ "filters": { "domain": ["acme.com"], "jobLevel": ["C-Team","VP","Director"] },
  "total": 13, "totalIsExact": true, "totalAll": 276 }
{ "filters": { "domain": ["acme.com"], "jobLevel": ["C-Team","VP","Director"],
  "jobFunction": ["Sales & Business Development"] }, "total": 1, "totalIsExact": true, "totalAll": 6 }

So on 2026-10-21 we held 13 senior mailable people at acme.com, which earns 35 coverage points. Without the email condition there are 276. Only 1 sits in sales, which is a useful thing to know before you pick a first contact.

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

json
{
  "success": true,
  "data": {
    "company_data": {
      "company_name": "Acme", "company_domain": "acme.com",
      "company_employees": { "number_of_employees": 340, "number_of_employees_code": "201-500" },
      "company_funding": "<as held, or null>",
      "company_technology_categories": ["CRM", "Analytics"]
    },
    "company_detected_technologies": "<as held>",
    "meta": { "fetched_at": "<date>", "schema": "leadocean.company.v1" }
  }
}

Run the Step 1 rubric on a record like that, with 13 seniors and a 2025 funding date, and it prints the line below. Your rows will have your own domains and scores.

json
{"domain":"acme.com","seniors":13,"pts":{"coverage":35,"size":30,"tech":25,"funding":10},"score":100}

Total spend for the whole run is 25 company lookups, 25 roster rows and 10 enrichments, so 60 records at most. On the free plan that is the 1,000 records spent in about 16 runs. On a paid plan (Solo at $97 a month) there is no per-record price, only a fair-use pace.

Troubleshooting

ErrorCauseFix
401Missing, wrong or revoked keyRe-copy the key from app.leadocean.io and export $LEADOCEAN_API_KEY again.
429Above the plan's rate limit: 5 requests a second on Free, 50 on Solo, 200 on AgencyAdd sleep 0.25 inside the Step 2 loop on Free, and lower the concurrency of parallel jobs. Wait the Retry-After seconds.
402The 1,000 free records are spentCheck your balance with GET /v1/account, then move to a paid plan. Free records do not reset.
Count is 0 for every domainA filter value outside the catalogue, such as jobLevel: "Vice President"Ask Claude to call leadocean_list_enum_values for job_level. Valid values are C-Team, Director, Manager, Other, Staff and VP.
404 on a company lookupWe hold nothing for that domainNothing is charged. Score it 0 and move on.
400 "Invalid cursor"A cursor was edited or hand-builtRestart the search and pass back meta.nextCursor unchanged.

FAQ

Why score in code and not in the prompt?

A scripted score is repeatable and you can audit it. Claude is good at explaining a score and poor at producing the same one twice. Let it do the writing.

Can Claude run the whole thing without a script?

Yes, for a handful of accounts. Ask it to count each domain, look up the survivors and score them against your table. Past about ten accounts the script is faster and the numbers stay stable.

Does LeadOcean cover hiring or news signals?

No. It holds firmographics, website technologies and people. Check news and open roles by hand, and let the brief's gaps section remind you.

What does a weekly refresh cost on a paid plan?

The counts stay free on every plan. The 60 records of lookups and roster rows fall well inside Solo's pace of 10k enrichments and 100k search records every 5 hours. Agency at $497 a month adds 5 keys and 200 requests a second for a team running several lists.

How current is the data?

The dataset is refreshed monthly, and each record carries a fetched_at date. Check it before you quote a headcount or a role on a call.

Score your account list for free before your next call

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

Get your free API key →