TL;DR
- Most conference pages list names, titles and companies. They list no emails, so you take the company website and look the person up by domain.
- It takes about 15 minutes for 10 people. The API route spends up to 40 LeadOcean records: up to 3 per name search, plus 1 per work-email lookup.
- For a whole list, skip the loop and run one export. Read
email_statusin the CSV before you send.
Prerequisites
- A LeadOcean account from app.leadocean.io. The free plan has no card and gives 1,000 records one-off.
curl,jqandpython3.- An API key in your shell as
$LEADOCEAN_API_KEY. Free keys get both scopes, search and enrich. - Your attendee, speaker or exhibitor list, from a page you are allowed to read or a file the organiser gave you.
export LEADOCEAN_API_KEY="paste-your-key-here"Step 1: Turn the list into names and domains
An attendee list gives you a name and a company. You need the company website, because the lookup runs on the domain. Put one person per line in a CSV: first name, last name, website.
The script below cleans the websites and builds the JSON array the later steps send as domain. The names are placeholders.
cat > attendees.csv <<'EOF'
Jane,Doe,https://www.acme.com/
John,Roe,http://example.org
EOF
cut -d, -f3 attendees.csv | sed -E 's#^https?://##; s#^www\.##; s#/.*$##' | sort -u > domains.txt
jq -R . domains.txt | jq -s -c . > domains.json
cat domains.jsonCopy by hand or use the list the organiser sent. This guide does not scrape event sites. Read the site terms first.
Step 2: Find one person by hand
For one person, the manual route is to guess the address and test it. This prints the usual candidates for a placeholder name.
first="jane"; last="doe"; domain="acme.com"
for p in "$first.$last" "$first" "${first:0:1}$last" "$first$last"; do
echo "$p@$domain"
doneEvery line is a guess. A domain that accepts all mail answers the same for a real and a fake address, so a guess can look fine and still bounce. Use this for one or two people, then move to the API.
Step 3: Size the list for free
Ask how many people we hold at your domains before you spend a record. Send count=true as a query parameter with limit at 1. It costs nothing.
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\": $(cat domains.json), \"limit\": 1}" \
| jq '.meta | {total, totalIsExact, credits}'A total of 0 means we hold nobody at those domains, so drop them. A big company returns thousands of people. Add title or seniority before you search, or you will page through staff who never went to the event.
Step 4: Search by domain, then get the work email
There is no name plus domain lookup in the API. Search the domain with the name as free text q, then use the person_id from the row. Each person returned costs one record, so keep limit low.
curl -s "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{"domain": ["acme.com"], "q": "Jane Doe", "limit": 3}' \
| jq '.data[0]'Check the name and title against the attendee page before you go on. A common name can match two people. Then send the person_id from the row to the work-email endpoint.
PERSON_ID="paste-person_id-from-the-search"
curl -s "https://api.leadocean.io/v2/people/email/work?person_id=$PERSON_ID" \
-H "x-api-key: $LEADOCEAN_API_KEY" | jq '.data'It returns one address or null, and costs one record either way. It returns only an address at the current employer that is verified, catch_all_valid or catch_all. For every email and phone we hold, call POST /v1/people/enrich with reveal_email true.
Step 5: Export the whole list
For more than a few dozen people, export by role instead of by name. Bulk CSV export is not on the Free plan: it comes with Solo ($97 a month) and Agency ($497 a month). One request takes up to 50,000 rows and a day takes up to 500,000. Each row costs one record.
curl -s https://api.leadocean.io/v1/exports \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d "{
\"name\": \"Conference attendees\",
\"filters\": {
\"domain\": $(cat domains.json),
\"seniority\": [\"c_suite\", \"vp\", \"director\"],
\"emailStatus\": [\"verified\", \"catch_all_valid\", \"catch_all\"]
},
\"limit\": 100,
\"preset\": \"full\"
}" | jq '.data | {id, status}'This returns the senior people at each company, not only the ones who attended. Match the CSV to your attendee names afterwards. Poll GET /v1/exports/{id}, then fetch GET /v1/exports/{id}/download when the status is done. The app does the same on its Exports page, with a filter builder, a column picker and the record price before you start.
Step 6: Match and check before you send
Columns are numbered: email_1_address, email_1_status. Download the file, read the header row, then keep rows where the status is verified or catch_all_valid and the name is on your attendee list.
EXPORT_ID="id-from-step-5"
curl -s "https://api.leadocean.io/v1/exports/$EXPORT_ID/download" \
-H "x-api-key: $LEADOCEAN_API_KEY" -o export.csv
python3 - <<'EOF'
import csv
rows = list(csv.DictReader(open("export.csv")))
ok = [r for r in rows if r.get("email_1_status") in ("verified", "catch_all_valid")]
print(len(rows), "rows,", len(ok), "with a sendable status")
print(list(rows[0].keys())[:12] if rows else "empty export")
EOFUse the name columns the header shows to match against attendees.csv. LeadOcean gives no refund or credit-back for bounced emails, so read email_1_status first. catch_all means the domain accepts any address, so it is riskier than catch_all_valid.
What you get
The Step 3 sizing call is a real run. We ran it on 2026-10-21 with leadocean_count_leads, which spends 0 records, for VP and C-Team people at three large company domains: stripe.com, airbnb.com and doordash.com.
{
"total": 2007,
"totalIsExact": true,
"totalAll": 4937,
"distinctCompanies": 10,
"unsupportedFilters": []
}That is 2,007 mailable people on 2026-10-21 (verified, catch_all_valid or catch_all), out of 4,937 with no email filter. The match spans 10 employers, because a domain can map to more than one company record. Big domains return thousands, which is why you add a name or a title before you spend records.
The work-email call returns the shape below. This is the response shape from the API reference, with placeholder values.
{
"success": true,
"data": {
"email": "jane.doe@acme.com",
"status": "verified",
"verified_batch_date": "2026-09-20"
}
}Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing, wrong or revoked key | Re-copy the key from app.leadocean.io and export $LEADOCEAN_API_KEY again. |
| 429 | Above your plan's rate limit (5 a second on Free, 200 on Agency) | Slow the loop and honour the Retry-After header, or use an export for large lists. |
| 402 | The 1,000 free records are spent | Check GET /v1/account, or move to Solo ($97 a month) or Agency ($497 a month) on pricing. Free records do not reset. Paid plans slow down instead of answering 402. |
| Search returns no rows | A filter value outside the catalogue, such as a job level of "VP Sales" | Check exact strings with GET /v1/enums or leadocean_list_enum_values. |
data: null on the work email | No address at the current employer is verified, catch_all_valid or catch_all | It still costs one record. Try POST /v1/people/enrich with reveal_email. |
400 export_limit_rows | The export limit is above 50,000 rows | Split the domain list and run several exports. |
FAQ
Do conference attendee lists include emails?
Rarely. Public pages show name, title and company. A file from the organiser may hold emails, and you should use them only within the terms you were given.
How many records does it cost?
One per person returned by a search and one per work-email call. Counts are free. Ten people searched at limit 3 each, plus 10 lookups, spend 40 at most.
Can I email people from an attendee list?
Check the event terms and the rules where your recipient lives before you send. Some organisers restrict outreach that uses attendee data. Use the list to find the person, then write to them about their work.
What if the person has left the company?
Search returns the current employer we hold. If it no longer matches the company on the attendee page, treat the row as unverified and skip it.
Where do I find more recipes?
Start from a list of domains, the YC company list or podcast guests. The blog hub lists them all, and plans are on pricing.
Turn your conference attendee list into checked work emails, free
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →