TL;DR
- ChatGPT reaches LeadOcean through one custom MCP server URL. You count the audience for free, check ten rows, then export a CSV.
- It takes about 20 minutes and spends about 510 records: 10 for the spot-check, 500 for the export. Bulk CSV export needs Solo ($97 a month) or above; on Free you page the same rows with search.
- Counting, filter lookups and enum lookups cost nothing. Only people you receive count as records.
Prerequisites
- A LeadOcean account from app.leadocean.io. The free plan has no card and 1,000 records, one-off.
- A ChatGPT account that may add a custom MCP server. OpenAI's docs, October 2026, say account and workspace policies apply, so ask your admin if the option is missing.
- Optional, for the REST steps: an API key exported as
$LEADOCEAN_API_KEY, pluscurlandjq.
export LEADOCEAN_API_KEY="paste-your-key-here"Step 1: Connect LeadOcean to ChatGPT
Add the server URL as a custom MCP server with OAuth. No key is pasted into the chat.
ChatGPT Plugins > plus button > Add custom MCP server
Name: LeadOcean
URL: https://api.leadocean.io/mcp
Auth: OAuth
Then: I understand and want to continue > Create as a pluginInstall the plugin, sign in to LeadOcean and approve. The full walkthrough, with troubleshooting, is on Connect LeadOcean to ChatGPT. The server exposes 13 tools, and seven of them never spend records.
Step 2: Count the audience for free
Write the audience as filters, not as a story. The example is VP-level sales leaders at US software companies with 51 to 200 staff. In a new chat, type @, select the LeadOcean plugin and send this.
Use the LeadOcean plugin only. Call leadocean_count_leads with jobLevel ["VP"],
jobFunction ["Sales & Business Development"], country ["US"],
industry ["Software Development"], employeeRange ["51-200"].
Report the total and say which email statuses it counted. Do not pull anyone.ChatGPT may ask you to confirm the tool call. Check the filters, then approve. A count costs 0 records.
The same count over REST is a search with count=true as a query parameter and limit at 1. It returns 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 '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"industry": ["Software Development"],
"employeeRange": ["51-200"],
"emailStatus": ["verified", "catch_all_valid", "catch_all"],
"limit": 1
}' | jq '.meta'Step 3: Spot-check ten rows
Look at real rows before you export hundreds. Ten records is a cheap test of whether the filters match who you mean.
Use leadocean_search_leads with the same filters and limit 10. Show a table of
job title, company, company domain and email_status. Flag any title that does not
look like a sales leader, so I can exclude it.Each person returned counts one record, so this spends 10. If the sample has noise, add an excludeTitle array such as ["assistant","intern"] and run it again.
Step 4: Export the list to CSV
Hundreds of rows belong in a file, not in a chat window. Ask ChatGPT to start an export and poll it.
Use leadocean_export_leads with the same filters, limit 500, and the full column
preset. Then call leadocean_get_export until the status is done and give me the
download link.Each export row costs one record. An export takes up to 50,000 rows a request and 500,000 a day. Bulk CSV export is on Solo and above, not on Free. On Free, ask for leadocean_search_leads pages of 100 instead, which spends the same one record per person.
Step 5: Repeat it over REST (optional)
Once the filters are right, a script gives you the same export without ChatGPT. This spends records again, so skip it if you already hold the file.
curl -s https://api.leadocean.io/v1/exports \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{
"name": "US VP sales, software, 51-200",
"filters": {
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"industry": ["Software Development"],
"employeeRange": ["51-200"],
"emailStatus": ["verified", "catch_all_valid", "catch_all"]
},
"limit": 500,
"preset": "full"
}' | tee export.json | jq '.data | {id, status, requested, perRow, pollAfter}'Poll the job, then download when the status is done.
ID=$(jq -r '.data.id' export.json)
curl -s https://api.leadocean.io/v1/exports/$ID -H "x-api-key: $LEADOCEAN_API_KEY" | jq '.data.status'
curl -s https://api.leadocean.io/v1/exports/$ID/download -H "x-api-key: $LEADOCEAN_API_KEY" -o leads.csvThe LeadOcean app has the same export on its Exports page: a filter builder, a column picker, the record price before you start and a Download button.
What you get
The count in Step 2 is a real result. We ran the same filters through the free leadocean_count_leads tool on 2026-10-01 (trimmed).
{
"total": 1603,
"totalIsExact": true,
"credits": 0,
"defaults": "Counted only addresses worth sending to (emailStatus: verified or catch_all_valid or catch_all)",
"facets": {
"country": [{ "value": "US", "count": 1603 }],
"industry": [{ "value": "Software Development", "count": 1603 }],
"seniority": [{ "value": "vp", "count": 1603 }],
"company_size": [{ "value": "51-200", "count": 1603 }]
}
}That is 1,603 mailable people, not everyone we hold for those filters. The count is the tool's default email filter. Your number will differ as the data changes.
The export request returns a job. This is the response shape from the API reference, with placeholder values.
{
"success": true,
"data": {
"id": "<export id>",
"name": "US VP sales, software, 51-200",
"status": "queued",
"requested": 500,
"perRow": "<1, or 2 when a column needs the full record>",
"remaining": "<records left after this reservation>",
"pollAfter": 10,
"file": null
}
}The finished download is a plain .csv, one row per person, with email and phone columns when the preset includes them.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing, wrong or revoked API key on a REST call | Re-copy the key from app.leadocean.io and export $LEADOCEAN_API_KEY again. |
| 429 | Above your plan's rate (5 requests a second on Free, 200 on Agency) | Wait the Retry-After seconds, then retry. Ask for full pages of 100 rather than more calls. |
| 402 | Free plan: the 1,000 records are spent, or the limit is above what you have left | Check leadocean_get_account or GET /v1/account, lower limit, or move to a paid plan. |
| Count of 0, or 400 on a filter | A value outside the catalogue, such as industry: "Software" | Have ChatGPT call leadocean_list_enum_values and pass the exact string. |
400 export_limit_rows | limit is above 50,000 rows for one export | Split the audience by country or headcount band and run several exports. |
| ChatGPT browses the web instead | It chose a built-in tool over the plugin | Type @, select LeadOcean, and name the tool in the prompt. |
FAQ
How many records does a lead list cost?
One record per person returned, or per export row. Counting is free, so the plan is count, spot-check ten, then export. The example spends about 510.
Why not ask ChatGPT to paste the whole list in chat?
A search returns at most 100 rows a page, and a long table is hard to check. An export writes one CSV with the contact columns. A row costs one record either way.
Do I need an API key for ChatGPT?
No. The MCP server uses OAuth sign-in. The REST steps use an x-api-key header, and both draw on the same record balance.
Can I do this in another editor?
Yes. The same MCP URL works elsewhere. See build a lead list in Cursor, in VS Code and in Windsurf. Plans are on pricing.
More recipes live in the blog hub.
Build your first lead list in ChatGPT today
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →