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

Integrations

LeadOcean + Outreach: Send Verified Prospects to Sequences

Export from LeadOcean, split by email status so catch-all addresses get their own sequence, and create each row as an Outreach prospect over the REST API.

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

You get a three-part pipeline: a LeadOcean export, split by email_status, created as prospects in Outreach and enrolled in two sequences. Verified addresses go to your main sequence. Catch-all addresses go to a second one, so a bad domain cannot drag down the first. LeadOcean is a plain REST API with a key, and Outreach has a REST API with OAuth, so a short script does the job.

Split the exports because status decides risk. A verified address has been checked against the mailbox. A catch-all domain accepts everything, so a catch-all address may still bounce. LeadOcean marks it in email_status, and LeadOcean gives no refund for bounces.

Related: the LeadOcean integrations hub, the Smartlead recipe, the Salesloft recipe, the Reply.io recipe and pricing.

How it works

Six steps. Outreach authenticates every API call with OAuth 2.0 and a bearer token that lives 2 hours (source: Outreach getting started, September 2026).

  1. Get both credentials. Sign up at app.leadocean.io and copy a key from the API keys page. In Outreach, create an app, add the prospects.all scope on its API access tab, and run the OAuth flow to get an access token.
  2. Size the list. Run a free count first. A search with count=true and limit=1 costs nothing, and meta.total is capped at 100,000.
  3. Export verified. POST your filters to /v1/exports with emailStatus set to verified.
  4. Export catch-all. Repeat with catch_all_valid and catch_all. Same filters, a second file.
  5. Create two sequences in Outreach. One for verified, one for catch-all.
  6. Create the prospects. Post each row to POST /api/v2/prospects and tag it with its status and file. Then add each tag group to the matching sequence.

Run a 100-row test first and open one prospect before you send the rest. Free has no bulk CSV export, so on Free search with POST /v1/people/search, then call POST /v1/people/enrich with reveal_email set to true for each person to get the address. Each person returned costs one record.

Prefer to click? The LeadOcean app has an Exports page with a filter builder, a column picker, the record price before you start and a Download button. Outreach also imports CSV files, in its app and through an imports API that needs the imports.write scope (source: Outreach bulk API and imports, October 2026).

Configuration

Steps 3 and 4, the exports. Several values in one filter join with OR.

bash
curl -X POST https://api.leadocean.io/v1/exports \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"outreach verified","filters":{"jobLevel":["VP"],"jobFunction":["Sales & Business Development"],"country":["CA"],"emailStatus":["verified"],"emailType":["work"]},"limit":10000,"columns":["profile_first_name","profile_last_name","current_job_title","current_company_name","current_company_domain","email_N_address","email_N_status"]}'

curl -H "x-api-key: $LEADOCEAN_API_KEY" https://api.leadocean.io/v1/exports/EXPORT_ID
curl -H "x-api-key: $LEADOCEAN_API_KEY" -o verified.csv https://api.leadocean.io/v1/exports/EXPORT_ID/download

For the second file, change emailStatus to ["catch_all_valid","catch_all"] and download to catchall.csv. Contact columns need a key with the enrich scope.

Step 6, the push. Outreach follows JSON:API, so the body wraps attributes in data. Outreach limits the API to 10,000 requests an hour per user (source: Outreach getting started, September 2026), so the script pauses between calls.

python
import csv, os, sys, time, requests

URL = "https://api.outreach.io/api/v2/prospects"
HEAD = {"Authorization": f"Bearer {os.environ['OUTREACH_ACCESS_TOKEN']}",
        "Content-Type": "application/vnd.api+json"}
path, tag = sys.argv[1], sys.argv[2]

for r in csv.DictReader(open(path)):
    if not r["email_1_address"]:
        continue
    body = {"data": {"type": "prospect", "attributes": {
        "emails": [r["email_1_address"]],
        "firstName": r["profile_first_name"],
        "lastName": r["profile_last_name"],
        "title": r["current_job_title"],
        "company": r["current_company_name"],
        "tags": [tag, "lo-" + r["email_1_status"]],
        "source": "LeadOcean",
    }}}
    res = requests.post(URL, headers=HEAD, json=body)
    if res.status_code == 429:
        time.sleep(60)  # Outreach's reset header is a time, not seconds
        res = requests.post(URL, headers=HEAD, json=body)
    if not res.ok:
        print(r["email_1_address"], res.status_code, res.text[:200])
    time.sleep(0.4)

Run it twice: python push.py verified.csv lo-main and python push.py catchall.csv lo-catchall. At 0.4 seconds a call, 10,000 rows take about 70 minutes, which also keeps you under the hourly cap. Access tokens last 2 hours, so refresh the token for longer runs. Every Outreach response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a 429 means the hour is spent.

This sends one prospect per request. Outreach's bulk actions change records that already exist, so they do not replace this loop. For very large files, its CSV imports API is the batch route.

Field mapping

Map the status as well as the address. Outreach has no field for it, so the script writes it into a tag, which you can filter on when you enroll prospects. Tags are a plain list of strings on the prospect (source: Outreach Prospect reference, September 2026).

LeadOcean fieldOutreach fieldNote
email_1_addressemails[]Array of strings.
email_1_statustags[]Written as lo-verified or lo-catch_all.
profile_first_namefirstNameEmpty if the profile has no split name.
profile_last_namelastName
current_job_titletitle
current_company_namecompanyOutreach says this is the account name if the prospect has an account.
current_company_domaincustom1Custom fields must be defined by an admin; GET /api/v2/types lists them.
phone_1_numberworkPhones[]Add the column to the export. Needs a plan with phones. Use mobilePhones if you know it is a mobile.

Create the account first if you want prospects grouped by company. The Outreach docs say you cannot write to an account's prospects list, so set the account on each prospect instead (source: Outreach common patterns, September 2026).

Cost at 10,000 rows

A 10,000-row run needs LeadOcean Solo at $97 a month, because bulk CSV export is not on Free. Outreach has no public price. Its pricing page says to request pricing, and lists packages by AI credits and API calls (source: Outreach pricing, October 2026).

ItemCostNote
LeadOcean Free$01,000 records for life. No bulk CSV export. Test with search.
LeadOcean Solo$97 a monthBulk CSV export included. Fair-use pace, no credits.
LeadOcean Agency$497 a monthFor teams. Exports up to 50k rows a file, 200 requests a second.
Outreach seatsNo public priceRequest pricing from Outreach.
Outreach API calls500,000 on Amplify Plus, 1,000,000 on Amplify ProListed on the pricing page. 10,000 rows is 10,000 calls.

The pricing page lists API calls for the two top packages and not for the smaller ones. Check that your package includes API access before you build. That is our reading of the page.

Troubleshooting

SymptomCauseFix
401 from OutreachAccess token expired after 2 hours.Refresh it. Store the token and reuse it.
403 from OutreachThe app lacks prospects.all, or governance rules limit what the user can create.Add the scope on the API access tab, or use a user with rights.
429 from OutreachOver the hourly request limit, or tokens fetched more than once a minute.Keep the pause between calls. Reuse the token.
Duplicate prospect errorsThe ruleset blocks duplicate emails.Check the ruleset permitDuplicateProspects setting or dedupe the CSV.
402 on LeadOcean exportFewer records left than limit reserves.Lower limit, or move to a paid plan.
403 on LeadOcean exportContact columns asked without the enrich scope.Use a key with that scope, or drop the email columns.
410 on LeadOcean downloadThe file expired.Create the export again.

FAQ

Why split catch-all from verified?

A catch-all domain accepts any address, so you cannot confirm the mailbox exists. Verified addresses carry less bounce risk. Separate sequences let you cap catch-all volume and keep the main one clean.

Which statuses should I send?

Send verified to the main sequence and catch_all_valid plus catch_all to the second. Leave risky, unknown, untested, invalid, role, disposable, spam_trap, abuse, derived and none out.

Can I import without code?

Yes. Download the CSV from the Exports page at app.leadocean.io and import it in Outreach. Map email_1_status to a tag or custom field so you can still split by status.

Can an AI agent run this?

Yes. LeadOcean's MCP server is at https://api.leadocean.io/mcp with 13 tools, including export_leads at one record per row. Outreach runs its own MCP server with OAuth 2.1 sign-in (source: Outreach MCP server, October 2026). We have not tested the two together, so the script stays the path for 10,000 rows.

Export your first Outreach list with a free LeadOcean key

Free to start. No credit card. 1,000 records to spend whenever you like.

Get your free API key →