This stack gives each tool one job. LeadOcean builds the list, Clay gates the risky emails, and Salesforce holds the Leads your reps and senders work. The free plan sizes the list and returns search pages. The CSV export in step 2 needs Solo.
The example audience is VPs of sales in the US. Swap the filters for yours.
TL;DR
- Time: about 60 minutes for a 200-row pilot, plus whatever your Salesforce admin needs for one custom field and an integration user.
- Records: 200 to 400 LeadOcean records for the pilot. Sizing the list first is free. The free plan has 1,000 records, one-off, but bulk CSV export is not on Free, so the pilot export needs Solo.
- Cost per 10,000 contacts: $97 for LeadOcean Solo plus $495 for Clay Growth, about $592 in a month at monthly list prices. Salesforce licences are on top, at whatever your contract says.
Prerequisites
- A LeadOcean key in
$LEADOCEAN_API_KEY. Sign up at app.leadocean.io/register. No card needed. Free covers steps 1 and 6; the step 2 export needs Solo ($97 a month) or Agency ($497 a month). - A Clay workspace on Growth or higher. The pricing page lists CRM integrations on Growth and Enterprise only (Clay pricing, September 2026).
- A Salesforce org where an admin can create a custom field on Lead and an integration user. Test in a sandbox first.
curland Python 3.
Sending is outside this guide. Point your sender at the Leads this stack creates.
Step 1: Size the list before you spend anything
Count first. A search with count=true and limit=1 is free (LeadOcean API reference, September 2026).
curl -X POST "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"],"emailType":["work"],"emailStatus":["verified","catch_all_valid","catch_all"],"limit":1}'Read meta.total. It is capped at 100,000. Filters join with AND, and several values inside one filter join with OR.
Step 2: Export the pilot list
Export 200 rows, not the whole audience. Bulk CSV export is included on Solo and Agency, not on Free. The export is asynchronous and reserves records up front (LeadOcean docs, September 2026).
curl -X POST https://api.leadocean.io/v1/exports \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"vp-sales-us pilot","filters":{"jobLevel":["VP"],"jobFunction":["Sales & Business Development"],"country":["US"],"emailType":["work"],"emailStatus":["verified","catch_all_valid","catch_all"]},"limit":200,"columns":["person_id","profile_first_name","profile_last_name","profile_url","current_job_title","current_company_name","current_company_domain","email_status","email_N_address"],"caps":{"emails":1}}'The answer is a 202 with an export id. Poll GET /v1/exports/{id} until status is done, then download the CSV.
curl -H "x-api-key: $LEADOCEAN_API_KEY" -o leads.csv \
https://api.leadocean.io/v1/exports/EXPORT_ID/downloadEmail columns need a key with the enrich scope. One export takes up to 50,000 rows, and an account takes 500,000 rows a day.
Step 3: Verify in Clay with a run condition
Import leads.csv into a new Clay table. Tables hold up to 50,000 rows on Launch and Growth (Clay docs, September 2026). Importing your own data uses no Actions and no Data Credits (Clay docs, September 2026).
LeadOcean already tags each address. Rows marked verified or catch_all_valid go straight through. Only catch_all rows get a second check.
Table: vp-sales-us pilot (import leads.csv)
Gate column: Ready to load (formula)
{{email_status}} == "verified" || {{email_status}} == "catch_all_valid"
Validator: add an email validation enrichment from Clay's list
Run condition: {{email_status}} == "catch_all"
Load filter: email_status is verified or catch_all_valid
OR the validator column says the address is validClay's conditional runs take a plain-language condition and a Generate button that writes the formula, and the docs show conditions in this {{column}} == "value" shape (Clay docs, September 2026). Check the generated formula against the sample output before you run the column.
Clay's own example shows select validators at 0 Data Credits (Clay docs, September 2026). A validator still costs one Action per row it runs on. Read the cost shown next to the validator in your table before you run it.
Step 4: Prepare Salesforce
Create one custom field and one connection. The field is how Clay matches a row to an existing Lead, so a re-run updates instead of duplicating.
In Salesforce Setup, add these custom fields on Lead.
Object: Lead
Field 1: LeadOcean_Person_ID__c Text(20), External ID, Unique
Field 2: LeadOcean_Email_Status__c Text(20)Clay's upsert action needs an external ID on the object (Clay docs, September 2026).
Then connect Clay. Clay offers User Sign In (OAuth) or Client Credentials for a server-to-server connection (Clay docs, September 2026). Use Client Credentials with an integration user.
Clay: Settings > Connections > Add connection > Salesforce
Method: Client Credentials
My Domain URL: https://acme.my.salesforce.com
Consumer key: from your Salesforce external client app
Consumer secret: from your Salesforce external client app
Test first: Settings > Connections > Salesforce Test Env (sandbox)Clay's FAQ says you cannot undo an update or create from Clay, and that a sandbox connection exists for testing (Clay docs, September 2026). Do the pilot there.
Step 5: Upsert the Leads
Add the Salesforce Upsert object action to the table, choose Lead, and map the columns. Set the run condition to the load filter from step 3.
Action: Salesforce > Upsert object
Salesforce object: Lead
External ID field: LeadOcean_Person_ID__c
Run condition: {{Ready to load}} == true
Field mapping (Clay column -> Lead field)
person_id -> LeadOcean_Person_ID__c
profile_first_name -> FirstName
profile_last_name -> LastName
current_company_name -> Company
current_job_title -> Title
email_1_address -> Email
email_status -> LeadOcean_Email_Status__c
current_company_domain -> WebsiteTurn auto-update off, run 20 rows, and open the Leads in Salesforce. Then run the rest. Clay batches Create, Update and Upsert through Salesforce's Composite API and handles each record on its own, so one failure does not stop the batch (Clay docs, September 2026).
Lead needs a last name and a company, which the export carries. Rows missing either will fail, so filter them out first.
Step 6: Cost a 10,000-contact run and know where each tool stops
Price the run before you scale. This script is arithmetic from list prices, not a quote.
rows = 10_000
leadocean_solo = 97 # flat per month, fair-use pace, no per-record price
clay_growth_monthly = 495 # monthly list price
clay_growth_yearly = 446 # billed yearly, per month
salesforce_actions = rows # 1 Action per CRM export record
validator_actions = rows # worst case: every row validated
actions = salesforce_actions + validator_actions
assert actions <= 40_000 # Growth entry tier
print("Actions used:", actions, "of 40,000")
print("Monthly list:", leadocean_solo + clay_growth_monthly)
print("Clay yearly view:", leadocean_solo + clay_growth_yearly)
print("Per contact:", round((leadocean_solo + clay_growth_monthly) / rows, 3))It prints 20,000 Actions, $592 a month at monthly list prices, $543 with Clay billed yearly, and about $0.059 a contact. Salesforce licences are extra.
The inputs come from public pages. Clay's Growth entry tier is $495 a month, or $446 billed yearly, with 40,000 Actions and 6,000 Data Credits a month (Clay pricing, September 2026). CRM exports and HTTP API calls use one Action per record (Clay docs, September 2026). LeadOcean Solo is $97 a month flat with a fair-use pace instead of credits, and 10,000 contacts use 10,000 to 20,000 records. Pace limits are on the LeadOcean pricing page (October 2026). Agency is $497 a month if a team shares the keys.
Solo's pace covers a 10,000-row export, with one catch. Export rows count against the search window, 100k records every 5 hours on Solo. Rows the export enriches also count against the enrichment window, 10k every 5 hours and 50k a week, per the limits docs. With perRow at 2, a 10,000-row export uses the whole 5-hour enrichment window. Nothing stops when you reach it: calls of that kind slow to one a minute until the window resets. Run the export as two 5,000-row jobs a few hours apart, or use Agency, whose enrichment pace is 1M a day.
Salesforce limits API calls per 24 hours. Enterprise Edition gets 100,000 plus a per-license amount (Salesforce Developer Limits, September 2026). Even at one call per record, 10,000 upserts fit.
Where each tool stops:
- LeadOcean stops at the list. It has no sequencer, dialer, CRM or Chrome extension.
email_statusis a signal, and there is no refund for bounced emails. - Clay stops at orchestration. It holds up to 50,000 rows a table on Growth, and every record it sends to a CRM costs an Action.
- Salesforce stops at the record. It does not supply contact data, and the edition and license decide what else it can do.
What you get
Step 1 is a free count. We ran the Step 1 audience (VP, Sales & Business Development, US, emailType work) through LeadOcean's MCP leadocean_count_leads tool on 2026-10-21, split by email status.
verified + catch_all_valid total 26988 totalIsExact true credits 0
catch_all total 80524 totalIsExact true credits 0Most of this audience is catch_all, so the Clay validator step does real work here. Your mix will differ. A count with an email status filter is a count of that status, not a total.
The export create call answers with the shape below. This is the response shape from the API reference (openapi.json), with placeholder values.
{
"success": true,
"data": {
"id": "EXPORT_ID",
"name": "vp-sales-us pilot",
"status": "queued",
"requested": 200,
"estimatedTotal": 107512,
"perRow": 1,
"remaining": 800,
"pollAfter": 5
}
}requested is the records reserved, and estimatedTotal is the free count at creation (here the two counts above added together). perRow is 1 or 2, and remaining is what is left after the reservation. On a paid plan remaining is null, because there is a pace rather than a balance. Read perRow before you scale up.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 "Missing or malformed x-api-key" | The header is missing or wrong. | Send x-api-key: $LEADOCEAN_API_KEY. |
| 402 on export create | Fewer records are left than the export reserves. | Lower limit. On Free the 1,000 records are one-off, and bulk CSV export is not on Free. |
| 429 | More requests a second than your plan allows (5 on Free, 50 on Solo, 200 on Agency), or a daily or period export ceiling. | Honour Retry-After. Exports allow 500,000 rows a day. |
| Zero rows back | A filter value is outside the catalogue, such as United States for US. | Read the valid values from GET /v1/enums. |
| 400 on export create | limit is over 50,000, or a filter cannot be applied. | Split into several exports with narrower filters. |
OAUTH_APPROVAL_ERROR_GENERIC in Clay | The Salesforce user has an Integration User or API Only license, or SSO blocks the approval screen. | Use Client Credentials, or a full license user (Clay docs, September 2026). |
FAQ
Do I need Clay at all?
Not to load Salesforce. You can import the CSV with Salesforce's own tools. Clay earns its place when you want run conditions, validators and other providers on the rows LeadOcean misses.
Why Growth and not Launch?
CRM integrations are listed on Growth and Enterprise only (Clay pricing, September 2026). On Launch you can still import the CSV into Salesforce directly.
How many records does a full run cost?
One export row costs one record, or two when the create response shows perRow of 2. Solo at $97 a month and Agency at $497 a month have no per-record price, only a fair-use pace. See pricing.
Can I send from Salesforce?
This guide stops at the Lead, and what Salesforce can send depends on your edition and add-ons. Ask your Salesforce account team for that. If you already run a sender, compare the VerifyHQ and ReachHQ stack or the Smartlead and Pipedrive stack.
Can I automate this without Clay?
Yes. The n8n and Attio stack wires the same list step to a different CRM. Back to the blog hub.
Build your first LeadOcean list for Clay and Salesforce. Start free.
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →