TL;DR
- A warm Slack lead is a member of your own community who posts often and fits your buyer profile. Claude Code finds the first group, LeadOcean checks the second.
- It takes about 30 minutes. It spends up to 55 of your 1,000 free records: 40 to enrich the top members and up to 15 to find their colleagues.
- Everything runs on files you already control: a member list and a public-channel export from a workspace you own.
Prerequisites
- A Slack workspace you own or admin. A Workspace Owner can export public-channel messages on any plan, September 2026.
- A Slack app token with the
users:readandusers:read.emailscopes, in your shell as$SLACK_TOKEN. Slack's docs say the email field needsusers:read.email, September 2026. - A LeadOcean API key from app.leadocean.io, as
$LEADOCEAN_API_KEY. The free plan has no card and 1,000 records, one-off. - Claude Code, plus
curlandjq.
export SLACK_TOKEN="paste-your-slack-token-here"
export LEADOCEAN_API_KEY="paste-your-key-here"Step 1: Pull the member list with emails
Slack's users.list returns every member, including invited and deactivated users, September 2026. Drop deleted accounts and bots, and keep the email.
curl -s "https://slack.com/api/users.list?limit=200" \
-H "Authorization: Bearer $SLACK_TOKEN" |
jq -r '.members[]
| select(.deleted == false and .is_bot == false and .profile.email != null)
| [.id, .profile.real_name, .profile.email] | @csv' > members.csvSlack pages the list. If response_metadata.next_cursor is not empty, repeat the call with &cursor=<that value> and append to members.csv.
Guests have is_restricted or is_ultra_restricted set to true. Decide now whether guests count as leads. Most teams drop them.
Step 2: Export public-channel messages
In Slack, open Admin, then Workspace settings, then Security, then Import & export data. Pick a date range on the Export tab and start the export. Slack emails a ZIP when it is ready.
Slack says each channel gets its own folder with one JSON file per date, September 2026. Every message carries type, user, text and ts. Unzip it next to members.csv.
unzip slack-export.zip -d export
ls export | headUse public channels only. Do not export direct messages to score leads. Slack also notes that a retention policy can delete old messages, so a date range older than your retention window returns no channel folders.
Step 3: Score activity with Claude Code
Count messages per member over the last 90 days. This is a job for a script, not a chat, so tell Claude Code to write one and show it to you first.
In ./export each public channel is a folder of date files. Each file holds messages
with the fields type, user, text and ts. Write score.sh that counts messages per
user ID from the last 90 days, ignoring messages without a user. Join the counts to
members.csv on user ID and write warm.csv with columns id, name, email, messages.
Drop anyone whose email domain is mine (acme.com). Keep the top 40 by messages.
Show me the script before you run it, then run it.The core of what it should write looks like this. Check one date file with jq 'type' first, so you know whether it is a list.
find export -mindepth 2 -name '*.json' -exec cat {} + |
jq -r '.[] | select(.type == "message" and .user != null)
| select((.ts | tonumber) > (now - 90 * 86400)) | .user' |
sort | uniq -c | sort -rn > counts.txtMessages are a crude signal. A member who asks three questions about your product is warmer than one who posts ten jokes. Ask Claude Code to print the three most recent message texts per member, then judge for yourself.
Step 4: Enrich the top members by email
You already hold the email, so enrich to learn the title and company. POST /v1/people/enrich takes exactly one of linkedin_url, email, phone or person_id. It costs one record per match. A member we hold nothing for is a 404 and costs nothing.
Test on five rows before the full run. The script writes one CSV row per member and skips any member that returns a 404.
echo "id,email,messages,name,job_title,company,domain,employees" > enriched.csv
tail -n +2 warm.csv | head -5 | tr -d '"' | while IFS=, read -r id name email messages; do
curl -s -X POST https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "Content-Type: application/json" \
-d "{\"email\":\"$email\"}" |
jq -r --arg id "$id" --arg email "$email" --arg m "$messages" '
select(.data != null) | .data as $d | $d.contact_data.contact_current_experiences[0] as $e
| [$id, $email, $m, $d.profile_data.profile_full_name, $e.job_title, $e.company_name,
$e.company_domain, $e.company_employees.number_of_employees] | @csv' >> enriched.csv
donewarm.csv has a header row, so tail -n +2 skips it. A member name with a comma breaks the split. If you have any, ask Claude Code to parse the CSV with Python instead.
Look at the five rows in enriched.csv. If the titles match the people you know, run the other 35. Replace head -5 with sed -n '6,40p' and drop the echo line, so the header is not rewritten. Leave reveal_email off: you do not need an address you already have.
Step 5: Keep the members who match your buyer
Ask Claude Code to filter enriched.csv against your buyer, and to explain every drop.
From enriched.csv keep rows where job_title is a VP, Head, Director or founder in sales,
marketing or revenue, and employees is 51 to 500. Write buyers.csv sorted by
messages. List each dropped row with the reason. Do not guess a title that is empty.The kept rows are your warm leads. Expect a short list. Many active members are peers, students and vendors, not buyers. Open each member's last messages before you write to them, and mention what they asked. A reply to a real question is the only reason this list is warm.
Step 6: Find colleagues at the warm accounts
One engaged person is a signal about their company. GET /v1/companies/{domain}/people returns the people we hold there, one record per person returned. Cap it with limit.
curl -s "https://api.leadocean.io/v1/companies/acme.com/people?limit=3" \
-H "x-api-key: $LEADOCEAN_API_KEY" | jq '.data | length'Run it for your top five accounts at limit=3: at most 15 records. The rows are thin, with no addresses. Enrich a person by person_id only after you pick them.
To see how many more buyers like yours exist outside your community, size them for free. Add the MCP server, sign in with /mcp, then ask for a count.
claude mcp add --transport http leadocean https://api.leadocean.io/mcpUse leadocean_count_leads with jobLevel ["VP","Director"], jobFunction
["Sales & Business Development"], industry ["Software Development"], employeeRange
["51-200"], country ["US"], facets false. Report the total and say which email
statuses it counted. Do not call any tool that spends records.What you get
The run ends with buyers.csv: one row per warm member, with their message count, title and company. This is the shape, with placeholder values.
name,email,messages,job_title,company,domain,employees
Jane Doe,jane@acme.com,31,VP Sales,Acme,acme.com,120The enrich call returns this shape. It is the response shape from the API reference, with placeholder values, and carries no email addresses because reveal_email is off.
{
"success": true,
"data": {
"profile_data": { "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",
"company_employees": { "number_of_employees": 120 }
}]
}
}
}The free count in Step 6 returned this on 1 October 2026:
{"total":4665,"totalIsExact":true,"credits":0,"defaults":"Counted only addresses worth sending to (emailStatus: verified or catch_all_valid or catch_all)"}That is 4,665 mailable VPs and Directors in sales at US software companies with 51 to 200 staff. It is a mailable count, not everyone matching the other filters. Your number will differ as the data changes.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | The x-api-key header is missing, or the key is wrong or revoked. | Copy a fresh key from the app and re-export $LEADOCEAN_API_KEY. |
| 402 | Your 1,000 free records are spent. Free records do not reset. | Check GET /v1/account, then move to Solo ($97 a month) or Agency ($497 a month) on pricing. |
| 404 | We hold nothing for that email. | Nothing to fix. A 404 costs 0 records. Try the member's LinkedIn URL instead. |
| 429 | Faster than your plan's rate per account: 5 a second on Free, 50 on Solo, 200 on Agency. | Wait the Retry-After seconds. The one-at-a-time loops here rarely hit it. On Free, add sleep 0.2 between calls. |
| Count of 0 or an empty search | A filter value is not an exact enum string, such as VP Sales in jobLevel. | Run leadocean_list_enum_values for job_level and pass an exact value such as VP. |
| Slack returns no email | The token lacks users:read.email. | Add the scope, reinstall the app, and rerun Step 1. |
FAQ
Can I do this on a Slack workspace I do not own?
No. You need a Workspace Owner for the export and a token for the member list. Members of a community you only belong to cannot export it. Ask the owner, or use LinkedIn post engagement as your warm signal instead.
Is a Slack member a lead I can email?
A member joined to learn, not to be sequenced. Treat activity as a reason to look at an account, and write only when you have a relevant answer or offer. Check your community's own rules before you do.
Why enrich by email and not by name?
Enrichment takes one of linkedin_url, email, phone or person_id. There is no name plus domain lookup. The email is the key you already hold, and it round-trips to the same person.
How many records does it cost?
One per matched member and one per colleague returned. Counts are free, and a member we hold nothing for costs 0. The example uses up to 55 of your 1,000 free records.
Can Claude Code read Slack directly?
This recipe does not need it. Claude Code reads the files you export and writes the scripts. If you also connect a Slack tool, Claude Code's MCP docs, September 2026, cover adding servers and signing in.
For a list built from filters instead of your own members, read build a lead list in Claude Code or the firmographics prompt. Plans are on pricing. More recipes live in the blog hub.
Turn your Slack community into a warm lead list, free
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →