You do not need 40 templates. You need 8 angles and 5 data triggers, and the data to fill the gaps. That gives 40 versions that each say one true thing about the reader.
We publish no reply rates here. We have no tested results to show, and a "with results" number we cannot source would be invented. What we can show is the part you control: the query, the fields and the output.
TL;DR
- Pick 1 of 8 angles and 1 of 5 triggers (table below). Pull the merge fields from one search call.
- Time: about 25 minutes. Records: 25 for a test page, then one record per person you keep.
- Counting your list first is free. Sending is up to your sequencer.
Prerequisites
- A free LeadOcean API key from the app, stored as
$LEADOCEAN_API_KEY. The Free plan gives 1,000 records for life, no card, 5 requests a second. curlandjq.- A sequencer or mail tool you already use. LeadOcean has no sequencer, dialer or CRM. It returns the data.
- Optional: the LeadOcean MCP server at
https://api.leadocean.io/mcp(13 tools) if you want an assistant to run the counts.
The 40 templates: 8 angles by 5 triggers
Each cell is a template. Write the angle once, swap the trigger line.
| Angle | Opening shape |
|---|---|
| 1. Problem | "Teams like {{company}} usually hit {{pain}} around {{trigger}}." |
| 2. Peer | "We help {{similar_company_type}} with {{result}}." |
| 3. Question | "Who owns {{topic}} at {{company}}?" |
| 4. Referral | "{{mutual_context}} suggested I write." |
| 5. Observation | "Noticed {{company}} {{fact}}." |
| 6. Offer | "Here is a {{asset}} for {{role}}s. No call needed." |
| 7. Breakup | "Closing the loop on {{topic}}." |
| 8. Bump | "Short follow-up: {{one_line_proof}}." |
| Trigger | Where the field comes from |
|---|---|
| A. New role | start_date in contact_data.contact_current_experiences[0] |
| B. Company size band | employeeRange filter |
| C. Tech in use | technologies filter |
| D. Past employer | resume_data.experiences[] from person enrich |
| E. Location | country filter, a person field |
8 angles times 5 triggers is 40. The trigger decides the first line. The angle decides the ask.
The 8 angles, written out
Each sample below uses one trigger so you can see the merge. Swap the trigger line to get the other four versions. Acme, Globex and Jane are placeholders.
1. Problem (trigger B, size band)
Jane, teams at Acme's size (51 to 200 people) often have one ops person who owns the list and the CRM. How is that split at Acme?
2. Peer (trigger C, tech in use)
Jane, we work with sales teams that run HubSpot and want verified contacts loaded before the first sequence. Is list quality on your plate this quarter?
3. Question (trigger A, new role)
Jane, you started at Acme in March. Who owns the account list there now: you or ops?
4. Referral (trigger D, past employer)
Jane, you were at Globex before Acme. Former Globex sales leaders tend to rebuild the target list in the first quarter. Worth comparing notes?
Only use a referral line when the context is true. A past employer is context, not a referral, so do not write "X suggested I write" unless X did.
5. Observation (trigger C, tech in use)
Jane, noticed acme.com runs HubSpot. Do your reps enrich contacts before they land in it, or after?
6. Offer (trigger E, location)
Jane, here is a count of VPs of sales at 51 to 200 person companies in the US, split by seniority. No call needed. Want the file?
7. Breakup (any trigger)
Jane, closing the loop on list building at Acme. If it is not a priority, I will stop here.
8. Bump (any trigger)
Jane, short follow-up: the count I mentioned is free to run yourself. One line of curl.
Keep every version under 80 words, one fact per email and one question per ask.
Step 1: Size the list for free
Counting spends no records. Start with the audience, not the copy.
curl -s "https://api.leadocean.io/v1/people/search?count=true&limit=1" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"employeeRange": ["51-200"]
}' | jq '.meta'count=true goes in the query string, not the JSON body. meta.total is capped at 100,000. Enum values are exact strings, so check them with GET /v1/enums first.
Step 2: Pull 25 people with the trigger fields
Use the same filters and add a technology for trigger C. technologies is matched through the employer, so a very broad company filter can come back in unsupportedFilters.
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": ["51-200"],
"technologies": ["HubSpot"],
"limit": 25
}' > page1.jsonThat costs 25 records. Page with cursor from meta. One search pages to 10,000 rows, so narrow the filters instead of walking the index.
Step 3: Enrich for the career trigger
For trigger D, enrich one person by person_id. It takes exactly one of linkedin_url, email, phone or person_id. An enrichment that finds nothing costs nothing.
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_STEP_2", "reveal_email": true}' \
| jq '.data.resume_data.experiences'Each past role carries job_title, company_name, start_date and end_date. Past employers have no company_id yet, so match on the name string.
Step 4: Merge into a template
A minimal merge, angle 5 (Observation) with trigger C (tech in use). Field names follow the response shape below.
jq -r '.data[]
| (.profile_data.profile_first_name) as $first
| (.contact_data.contact_current_experiences[0].company_domain) as $domain
| select($first and $domain)
| "Hi \($first),\n\nNoticed \($domain) runs HubSpot. Do your reps enrich contacts before they land in it, or after?\n"' page1.jsonRead each output before you send. A merge line that is wrong once costs more than the template saves.
Step 5: Check the email status before sending
Read contact_data.email_status on every row. Send to verified and catch_all_valid. Treat catch_all as a smaller test batch. LeadOcean gives no refund for bounces, so filter first.
Step 6: Test one cell at a time
Run one angle and one trigger per batch. Keep the list, the subject line and the send window the same, and change only the cell. That is the only way to learn which of the 40 works for your buyer.
- Split the list with the same search filters, so each batch has the same audience shape.
- Send each batch from the same mailboxes on the same days.
- Record replies per cell in your sequencer or a sheet. LeadOcean does not track sends or replies.
- Drop a cell after one clean test. Do not rewrite it five times.
If a trigger field is empty for a person, move them to a cell whose trigger they have. Trigger B and E fields are filled for most rows, because they come from the filters you searched on.
What you get
A free count on 2026-10-21, with every filter named:
leadocean_count_leads
jobLevel: VP
jobFunction: Sales & Business Development
country: US
employeeRange: 51-200
total: 18,567 (default: verified, catch_all_valid, catch_all)
totalAll: 60,456 (same filters, no email condition)
distinctCompanies: 12,192
records spent: 0So 18,567 people are mailable on those filters. They sit at 12,192 companies, which is about 1.5 people per company. Cap your sends per company.
Adding technologies: HubSpot (trigger C) on the same day returned 4,781 mailable people at 3,069 companies, out of 13,902 with no email condition.
Response shape from the API reference, placeholder values:
{
"success": true,
"data": [
{
"profile_data": { "profile_first_name": "Jane", "profile_full_name": "Jane Doe" },
"contact_data": {
"has_email": true,
"email_status": "verified",
"contact_current_experiences": [
{ "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com", "start_date": "2026-03-01" }
]
},
"meta": { "source_ids": { "person_id": "123456789" } }
}
],
"meta": { "count": 1, "nextCursor": "NEXT_CURSOR" }
}A search row carries email flags, not addresses. Enrich with reveal_email to get the address.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key | Copy the key from the app and export $LEADOCEAN_API_KEY |
| 429 | Above the plan's rate limit (5 a second on Free, 200 on Agency) | Honour Retry-After, or move up a plan |
| 402 | Records spent (Free is 1,000 for life) | See pricing; Solo is $97 a month |
| Empty results | Enum value not an exact string, such as vp for VP | Check GET /v1/enums |
| 404 on enrich | Nothing held for that person | Costs nothing. 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
Are these templates tested?
No. We have no tested reply rates to publish, so we give none. Test one angle against one trigger on 200 people, then change one thing.
How many records does the test cost?
25 for the search page in Step 2, plus one per enrichment that finds someone. The Free plan's 1,000 covers about 40 test pages.
Where do I put the merge fields?
In your sequencer. LeadOcean returns data and exports CSV. It does not send email.
Can I personalize without a name?
Yes. Trigger B, C and E need no name, only a company field. See how to personalize sales emails.
Where do I go next?
Read personalized cold email outreach and the pharmaceutical sales cold email samples. More guides are in the blog hub.
Fill your templates with data that is true
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →