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

How-to guide

How to Do lm-tui Style B2B Enrichment From the Terminal (curl and jq)

LeadOcean ships no CLI. Here are the lm commands people reach for, and the curl and jq calls that do the same job with real queries and output.

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

TL;DR

  • We read "lm-tui" as LeadMagic's terminal tool: the lm command and its interactive workspace. LeadOcean has no CLI, but every job lm does maps to one curl call.
  • It takes about 15 minutes and about 6 of your 1,000 free records. Counts, filter lookups and enum lookups spend nothing.
  • Pick lm if 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.
  • curl and jq.
bash
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 lmLeadOcean callCost
lm loginGET /v1/account with your keyFree
Size a list before spendingPOST /v1/people/search?count=trueFree
lm find people at a companyPOST /v1/people/search with a domain filter1 record per person
lm find emailPOST /v1/people/enrich with reveal_email: true1 record, 404 is free
lm enrich on a CSVA shell loop over /v1/people/enrich, or POST /v1/exports1 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.

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

A 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.

bash
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.

bash
curl -s "https://api.leadocean.io/v1/enums/industry?q=software" \
  -H "x-api-key: $LEADOCEAN_API_KEY" | jq

Step 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.

bash
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.json

To 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.

bash
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.

bash
#!/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.txt

Run 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.

json
{
  "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.

json
{
  "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

ErrorCauseFix
401Missing, wrong or revoked keyCopy the key again from app.leadocean.io and re-export $LEADOCEAN_API_KEY.
429Faster 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.
402Free plan: the 1,000 records are spentCheck GET /v1/account, or move to Solo ($97) or Agency ($497).
Empty results or 400A filter value outside the catalogue, such as industry: "Software"Resolve it with GET /v1/enums/industry?q=... and pass the exact string.
404 on enrichWe hold nothing for that personNothing was spent. Mark the row not found and move on.
400 on an exportA limit above the 50,000-row ceilingSplit 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 →