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

Integrations

LeadOcean + Reply.io: Import Verified Leads Into Sequences

Export from LeadOcean, split by email status so catch-all addresses get their own sequence, and import each file into Reply.io in batches of 1,000.

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, imported into Reply.io 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. Both sides are plain REST with a key.

Split the lists because the status decides the 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.

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

How it works

Six steps. Reply.io's import endpoint takes up to 1,000 items per request and enrolls the contacts in a sequence you name (source: Reply import guide, September 2026).

  1. Get both keys. Sign up at app.leadocean.io and copy a key from the API keys page. In Reply.io open Settings, then API Key, and create a key with the contacts:write scope.
  2. Size the list. Run a free count before you spend records. 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 Reply.io. One for verified, one for catch-all. Note both sequence ids.
  6. Import each CSV. Send 1,000 rows at a time to POST /v3/contacts/import with the matching sequenceId.

Run a small test first. 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. Check one contact in Reply.io before you send the rest.

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. Reply.io's docs say CSV import is available in the product, and the API guide says the API itself takes JSON, not CSV (source: Reply import guide, September 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":"reply 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 import. Reply.io uses a bearer token on api.reply.io. Every item needs firstName, or it comes back failed with the error "Invalid data" while the HTTP status stays 200 (source: Reply import endpoint, September 2026).

python
import csv, os, sys, time, requests

URL = "https://api.reply.io/v3/contacts/import"
HEAD = {"Authorization": f"Bearer {os.environ['REPLY_API_KEY']}"}
path, sequence_id = sys.argv[1], int(sys.argv[2])

items = [{
    "email": r["email_1_address"],
    "firstName": r["profile_first_name"],
    "lastName": r["profile_last_name"],
    "company": r["current_company_name"],
    "title": r["current_job_title"],
    "customFields": [{"name": "email_status", "value": r["email_1_status"]}],
} for r in csv.DictReader(open(path))
  if r["email_1_address"] and r["profile_first_name"]]

for i in range(0, len(items), 1000):
    body = {"items": items[i:i+1000],
            "options": {"skipExisting": True, "sequenceId": sequence_id}}
    res = requests.post(URL, headers=HEAD, json=body)
    print(res.status_code, {k: v for k, v in res.json().items() if k != "items"})
    time.sleep(1)

Reply.io limits each user to 100 requests a minute, 3,000 an hour and 150,000 a week. Above that it answers 429 with a Retry-After header (source: Reply API introduction, September 2026). A 10,000-row file is 10 requests, so the limit does not bite here.

Run it twice: python push.py verified.csv VERIFIED_SEQUENCE_ID and python push.py catchall.csv CATCHALL_SEQUENCE_ID. The response reports added, updated, skipped and failed, plus a per-item outcome.

Field mapping

Map the status as well as the address. Reply.io does not know which contacts came from a catch-all domain, so write email_status into a custom field and you can report on it later. The import body takes email, firstName, lastName, phone, title, company, industry, city, state, country, linkedInUrl and customFields. A custom field is addressed by id or name (source: Reply API spec, September 2026).

LeadOcean fieldReply.io fieldNote
email_1_addressemailEmail is the default dedupe key.
email_1_statuscustomFields[name=email_status]Create the custom field in Reply.io before the first import.
profile_first_namefirstNameRequired. An item without it fails.
profile_last_namelastName
current_company_namecompany
current_job_titletitle
current_company_domaincustomFields[name=company_domain]Reply.io has no plain domain field on a contact. Use a custom field.
phone_1_numberphoneAdd the column to the export. Needs a plan with phones.

Column ids come from GET /v1/exports/columns, which needs no key.

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. Reply.io's plan price is not quoted here; read it on reply.io/pricing for your plan.

Reply.io's billing schemas count active contacts, meaning contacts first touched in a billing month (source: Reply API, billing schemas, September 2026). Importing 10,000 contacts is not the same as activating 10,000. That reading is ours.

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. 200 requests a second, 50k rows a file.
Reply.ioYour planBilled on active contacts, not imports.

Troubleshooting

SymptomCauseFix
401 from Reply.ioMissing, wrong or revoked token.Send Authorization: Bearer KEY, not x-api-key.
Import returns 200 but failed is above 0An item has no firstName, or names a stage that does not exist.Drop rows without a first name before the call. Read the per-item error.
skipped is highskipExisting matched contacts already in the workspace.Expected for repeat runs. Set it to false only if you want updates.
429 from Reply.ioOver 100 requests a minute for the user.Honor Retry-After. Keep the pause between batches.
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 sequence clean. LeadOcean gives no refund for bounces, so read email_status before you send.

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.

Should I validate again inside Reply.io?

Reply.io offers email validation on a list through its API (source: Reply import guide, September 2026). It is optional on a verified file, since LeadOcean already sends the status.

Can an AI agent run this?

Yes on both sides. LeadOcean's MCP server is at https://api.leadocean.io/mcp with 13 tools, including export_leads at one record per row. Reply.io runs its own MCP server at https://mcp.reply.io/ with a bearer key (source: Reply MCP connect, September 2026).

Export your first Reply.io 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 →