A personal sales email contains one fact that is true of the reader and of nobody else on your list. Everything else in the email serves that line. This guide shows how to pull candidate facts with the LeadOcean API, choose one, and build the email around it.
TL;DR
- Count a small segment for free, pull five people, enrich one for career history, then write one email around one fact.
- It takes about 20 minutes and spends about 6 records, inside the free 1,000.
- If no fact in the data is specific, do not fake one. A generic email with a merge tag is not personal.
Prerequisites
- A free LeadOcean key in
$LEADOCEAN_API_KEY(start free, no card: see pricing). curlandjq.- Any inbox or sending tool. LeadOcean returns data only. It has no sequencer or inbox.
- Related reading: the email templates that use the same fields, and inbox setup. More guides are in the blog hub.
Step 1: Pick a segment and size it for free
Choose a narrow segment first. A narrow segment makes the shared context obvious, which is what makes the email feel written for one person. Counting costs nothing.
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 '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"employeeRange": ["201-500"],
"limit": 1
}' | jq '.meta | {total, distinctCompanies}'On 2026-10-21 the free MCP tool leadocean_count_leads returned 12,281 people with a verified, catch_all_valid or catch_all email, across 6,321 companies. With no email condition the same filters matched 35,380. Say which number you mean when you quote one.
Step 2: Pull five people
One search page of 5 is 5 records. Ask only for addresses worth sending to.
curl -s https://api.leadocean.io/v1/people/search \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"employeeRange": ["201-500"],
"emailStatus": ["verified"],
"limit": 5
}' > people.json
jq -r '.data[] | [.meta.source_ids.person_id,
.profile_data.profile_full_name,
.contact_data.contact_current_experiences[0].job_title,
.contact_data.contact_current_experiences[0].company_name,
.contact_data.email_status] | @tsv' people.jsonSearch is a flat JSON body, filters are arrays, and limit runs 1 to 100. Page on with cursor when you want more.
Step 3: Enrich one person for candidate facts
Search gives you title and company. Enrich adds career history: past roles, schools, certifications and awards. These are the facts a stranger would not guess. Enrich takes exactly one of linkedin_url, email, phone or person_id. Use the person_id from the first column of Step 2.
curl -s -X POST https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"person_id": "1234567"}' > person.json
jq '.data | {now: .contact_data.contact_current_experiences[0],
past: .resume_data.experiences[0:2],
school: .resume_data.educations[0:1],
awards: .resume_data.awards[0:1]}' person.jsonA person we hold nothing for is a 404 and costs nothing. Past employers carry no company_id yet, so compare them by name. Each section appears only when held.
Step 4: Score the facts and choose one
Not every fact is personal. Use this test: could you paste the line into an email to the person next to them on the list? If yes, it is a merge tag, not a personal line.
Fact Passes the test? Why
Title: VP Sales No Everyone in the segment has it
Company size: 201-500 No Shared by the whole segment
Past role: Head of Sales, Yes Specific to this person's path
previous employer (by name)
Award in resume_data.awards Yes Rare, recent and checkable
School Maybe Only if you share it or it ties to the askPick one fact. Two facts in one email read as research done by a script.
Step 5: Write around the one fact
Put the fact in the first sentence, tie it to one problem, and ask one question. Keep the email under 90 words.
Subject: From {{past_company}} to {{company}}
Hi {{first_name}},
You moved from {{past_title}} at {{past_company}} to running sales at {{company}}.
Teams that make that jump often rebuild how they source pipeline in the first year.
I work on {{problem}}. Is that on your list this quarter?
{{your_name}}Fill the variables in your own script or sending tool. Read every email aloud once. If a line only works because of a variable, cut it.
Step 6: Check the email status before sending
Read email_status on every row. We do not refund bounces.
jq -r '.data[] | select(.contact_data.email_status=="verified") | .meta.source_ids.person_id' people.json | wc -lWhat you get
Response shape from the API reference, with placeholder values (not a real person):
{
"success": true,
"data": [
{
"profile_data": { "profile_full_name": "Jane Doe" },
"contact_data": {
"has_email": true,
"email_status": "verified",
"contact_current_experiences": [
{ "job_title": "VP of Sales", "company_name": "Acme", "company_domain": "acme.com" }
]
},
"meta": { "source_ids": { "person_id": "1234567" } }
}
],
"meta": { "count": 1, "limit": 5, "nextCursor": null }
}Enrich adds resume_data with experiences[], educations[], certifications[] and awards[], each present only when held.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key | Copy the key from app.leadocean.io and export it again |
| 429 | Above the plan rate limit (5 a second on Free, 200 on Agency) | Honor Retry-After, or move to a higher plan |
| 402 | Records spent (Free has 1,000 for life) | Check GET /v1/usage, then pick a plan on pricing |
| Empty results | A bad enum value, such as vp instead of VP for jobLevel | Check exact strings with leadocean_list_enum_values |
| 404 on enrich | Nothing held for that person | No cost. Try another person_id |
| Export refused | Over 50,000 rows a request or 500,000 a day | Split the export. Bulk CSV is not on Free |
FAQ
How many facts should one email use?
One. A second fact turns research into a list. Save it for the follow-up.
Is a merge tag for first name and company personal?
No. Both are in every record on your list. Treat them as formatting.
What if the enriched record has no usable fact?
Send a plain, short email and say why you are writing. See the template guide. Do not invent a hook. Pace and tone matter more than fake detail; for sending from a work platform, see Pardot sending from a salesperson.
How many records does this cost?
About 6 here. Counting costs nothing, and an enrichment that finds nobody costs nothing.
Pull the one fact that makes your next email personal
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →