TL;DR
- We read "lm-tui" as LeadMagic's terminal tool: the
lmcommand and its interactive workspace. LeadOcean has no CLI, but every joblmdoes maps to onecurlcall. - It takes about 15 minutes and about 6 of your 1,000 free records. Counts, filter lookups and enum lookups spend nothing.
- Pick
lmif you want a packaged command with an interactive workspace. Pick this route if you want plain HTTP you can drop into cron, CI or a Makefile.
Prerequisites
- A LeadOcean account and API key from app.leadocean.io. The free plan has no card and 1,000 records, one-off.
- The key in your shell as
$LEADOCEAN_API_KEY. curlandjq.
export LEADOCEAN_API_KEY="paste-your-key-here"Step 1: Map the lm commands to LeadOcean calls
LeadMagic describes its CLI as a terminal product with an lm command, direct commands such as lm enrich and lm find, and an interactive workspace (LeadMagic CLI docs, October 2026). It installs with one script and signs in through the browser (LeadMagic, October 2026). LeadOcean uses an x-api-key header instead.
What you do in lm | LeadOcean call | Cost |
|---|---|---|
lm login | GET /v1/account with your key | Free |
| Size a list before spending | POST /v1/people/search?count=true | Free |
lm find people at a company | POST /v1/people/search with a domain filter | 1 record per person |
lm find email | POST /v1/people/enrich with reveal_email: true | 1 record, 404 is free |
lm enrich on a CSV | A shell loop over /v1/people/enrich, or POST /v1/exports | 1 record per hit |
LeadOcean has no name plus domain lookup. Search by domain first, then enrich by person_id. That is one extra call compared with a name-and-domain command.
curl -s https://api.leadocean.io/v1/account \
-H "x-api-key: $LEADOCEAN_API_KEY" | jqA 401 here means a bad key, and you have spent nothing finding out.
Step 2: Size the list for free
Write the audience as flat JSON. Filters are arrays of strings. Send count=true as a query parameter and limit 1. You get meta.total and no rows.
curl -s "https://api.leadocean.io/v1/people/search?count=true" \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{
"title": ["Head of Data", "Head of RevOps"],
"country": ["US"],
"employeeRange": ["51-200"],
"limit": 1
}' | jq '.meta | {total, totalIsExact, countOnly}'Enum values are exact strings. Resolve a value before you guess it.
curl -s "https://api.leadocean.io/v1/enums/industry?q=software" \
-H "x-api-key: $LEADOCEAN_API_KEY" | jqStep 3: Pull a two-row sample
Look at real rows before you pull hundreds. Each person returned counts one record, so two rows cost two.
curl -s https://api.leadocean.io/v1/people/search \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{
"title": ["Head of Data", "Head of RevOps"],
"country": ["US"],
"employeeRange": ["51-200"],
"limit": 2
}' | tee sample.json | jq '.meta | {count, nextCursor}'
jq -r '.data[].meta.source_ids.person_id' sample.jsonTo page on, pass meta.nextCursor back as cursor, unchanged. Limit is 1 to 100 a page. One search walks at most 10,000 rows, so narrow the filters instead of paging harder.
Step 4: Enrich one person
Enrich takes exactly one of linkedin_url, email, phone or person_id. Set reveal_email to true to get the addresses and phones we hold. It costs no extra record.
PID=$(jq -r '.data[0].meta.source_ids.person_id' sample.json)
curl -s https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d "{\"person_id\": \"$PID\", \"reveal_email\": true}" \
| jq '.data.contact_data | {email_status, email_type, contact_emails, contact_phones}'A person we hold nothing for is a 404 and costs nothing. For only a phone number, GET /v2/people/phone is the narrow endpoint, and it costs one record per call even on a miss.
Step 5: Enrich a CSV, the lm enrich job
Put one email per line in emails.txt. Use your own list. This is the loop that replaces a packaged batch command.
#!/usr/bin/env bash
echo "email,email_status,email_type" > out.csv
while read -r EMAIL; do
RES=$(curl -s -w "\n%{http_code}" https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d "{\"email\": \"$EMAIL\", \"reveal_email\": true}")
CODE=$(tail -n1 <<<"$RES")
[ "$CODE" = "404" ] && { echo "$EMAIL,not_found," >> out.csv; continue; }
sed '$d' <<<"$RES" | jq -r --arg e "$EMAIL" \
'[$e, .data.contact_data.email_status, .data.contact_data.email_type] | @csv' >> out.csv
sleep 0.2
done < emails.txtRun it with bash enrich.sh. Three addresses spend at most three records. The sleep 0.2 keeps you under the Free rate of 5 requests a second.
Past a few thousand rows, stop looping. Bulk CSV export is on Solo and above, not on Free. POST /v1/exports takes the same filters and writes up to 50,000 rows a request and 500,000 a day. The app's Exports page does the same job with a column picker and the record price shown before you start.
What you get
On 21 October 2026 the free MCP count for the Step 2 audience returned this. It spent no records.
{
"total": 289,
"totalIsExact": true,
"totalAll": 630,
"distinctCompanies": 259,
"credits": 0
}That is 289 people with a verified, catch_all_valid or catch_all email. Without any email condition the same filters match 630. The number moves as the data is refreshed monthly.
This is the enrich response shape from the API reference, with placeholder values.
{
"success": true,
"data": {
"profile_data": { "profile_full_name": "Jane Doe" },
"contact_data": {
"email_status": "verified",
"email_type": "work",
"contact_emails": [
{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }
],
"contact_phones": [
{ "phone": "+14155550133", "type": "mobile", "priority": 1 }
]
}
}
}Read email_status before you send. There is no refund for bounced emails.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing, wrong or revoked key | Copy the key again from app.leadocean.io and re-export $LEADOCEAN_API_KEY. |
| 429 | Faster than your plan's rate (5 a second on Free, 200 on Agency) | Wait the Retry-After seconds, then retry. Keep the sleep in the loop. |
| 402 | Free plan: the 1,000 records are spent | Check GET /v1/account, or move to Solo ($97) or Agency ($497). |
| Empty results or 400 | A filter value outside the catalogue, such as industry: "Software" | Resolve it with GET /v1/enums/industry?q=... and pass the exact string. |
| 404 on enrich | We hold nothing for that person | Nothing was spent. Mark the row not found and move on. |
| 400 on an export | A limit above the 50,000-row ceiling | Split by country or headcount band and run several exports. |
FAQ
Does LeadOcean have a CLI like lm-tui?
No. LeadOcean has the REST API, a hosted MCP server at https://api.leadocean.io/mcp and an app with an Exports page. From a terminal you use curl and jq, as above. The wider walkthrough is in data enrichment for developers.
Which should I use, lm or curl?
Use lm if you want an interactive workspace on your laptop. Use curl and jq if the job runs unattended in CI, cron or a backend. The data and the cost model differ more than the interface, so size your list first.
What does this cost?
The free plan is 1,000 records, one-off, with no card. Solo is $97 a month and Agency $497 a month, with a fair-use pace and no per-record price. See pricing and what enrichment actually costs.
I am new to the terms. Where do I start?
Read what data enrichment is, then come back for the calls.
Enrich from your terminal. Free key, one curl.
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →