You get a short pipeline: a LeadOcean export of people with verified work emails, converted to rows, imported into a ReachHQ lead list and attached to a campaign. Both sides are plain REST with an API key, so you can script it in an afternoon. The free LeadOcean plan has 1,000 records to spend on a first run.
Related: the LeadOcean integrations hub, the VerifyHQ and ReachHQ stack guide, and the pricing page.
How it works
Five steps, two APIs. ReachHQ's API lets you import rows with a dry run first and then commit them to a static lead list (source: ReachHQ API spec, September 2026).
- Get both keys. Sign up at app.leadocean.io and copy a key from the API keys page. In ReachHQ, create a key under Settings, API keys, with the scopes
leads:write,lead_lists:writeandcampaigns:write. ReachHQ shows the secret once. - Export from LeadOcean. POST your filters to
/v1/exportswithemailStatusset toverifiedandcatch_all_valid. The API answers 202 with a job id. - Download the CSV. Poll
GET /v1/exports/{id}untilstatusisdone, then download the file. - Convert and dry-run. Turn CSV rows into the JSON ReachHQ expects and send them with
action: dryRun. Read the preview, then send the same rows withaction: commitand alistId. - Attach the list to a campaign. Call the campaign recipients endpoint with
action: addFromList. A large list returnsRUNNING, so poll withaudienceJobStatus.
If you would rather click, ReachHQ's public pages do not document an in-app CSV import or its column mapping screen. Check the app at app.reachhq.io for the current flow.
Do not launch from this recipe. Launching is a separate campaigns:launch scope in ReachHQ, so keep it off the key you use for imports.
Configuration
Step 2, the export. Several values inside one filter join with OR, so this keeps both good statuses.
curl -X POST https://api.leadocean.io/v1/exports \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"reachhq VP sales CA","filters":{"jobLevel":["VP"],"jobFunction":["Sales & Business Development"],"country":["CA"],"emailStatus":["verified","catch_all_valid"],"emailType":["work"]},"limit":1000,"columns":["profile_first_name","profile_last_name","current_job_title","current_company_name","current_company_domain","profile_url","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 people.csv https://api.leadocean.io/v1/exports/EXPORT_ID/downloadSize the audience first. A search with count=true and limit=1 is free. Contact columns need a key with the enrich scope. Keys on the free plan get both scopes, search and enrich, inside the 1,000 one-off records.
Step 4, convert the CSV to rows. This script is ours, and the 500-row chunk is a conservative choice, not a ReachHQ limit.
import csv, json, os, requests
API = "https://api.reachhq.io/api/v1/leads/import"
HEAD = {"Authorization": f"Bearer {os.environ['REACHHQ_API_KEY']}"}
LIST_ID = os.environ["REACHHQ_LIST_ID"]
rows = []
for r in csv.DictReader(open("people.csv")):
if r["email_1_status"] not in ("verified", "catch_all_valid"):
continue
rows.append({
"email": r["email_1_address"],
"firstName": r["profile_first_name"],
"lastName": r["profile_last_name"],
"company": r["current_company_name"],
"jobTitle": r["current_job_title"],
"domain": r["current_company_domain"],
})
for i in range(0, len(rows), 500):
body = {"action": "commit", "source": "CSV", "fileName": "people.csv",
"rows": rows[i:i+500], "listId": LIST_ID}
print(requests.post(API, headers=HEAD, json=body).json())Run it once with "action": "dryRun" and no listId before you commit. ReachHQ's API reference types rows as an array of objects and fieldMapping as a free-form object, and it states no row limit per request. The script above sends rows already named for ReachHQ, so it leaves fieldMapping out (ReachHQ API reference, October 2026).
Step 5 attaches the list to a campaign.
curl -X POST https://api.reachhq.io/api/v1/campaigns/CAMPAIGN_ID/recipients \
-H "Authorization: Bearer $REACHHQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"action":"addFromList","leadListId":"LIST_ID"}'ReachHQ allows 600 requests per 60 seconds per key, so 500-row chunks stay far under it (source: ReachHQ REST API guide, September 2026).
Field mapping
ReachHQ's create-lead schema requires email and accepts firstName, lastName, company, tags and customFields. The other columns go in as extra fields. Those names come from the create-lead schema. The reference does not list the row fields that POST /leads/import reads, so confirm them with a dryRun (ReachHQ API reference, October 2026).
| LeadOcean field | Target field (ReachHQ) | Note |
|---|---|---|
email_1_address | email | Required. Best address first. |
email_1_status | filter only | Drop anything but verified and catch_all_valid before import. |
profile_first_name | firstName | Empty if the profile has no split name. |
profile_last_name | lastName | |
current_company_name | company | |
current_job_title | jobTitle | Extra field. Use it as a merge field in the sequence. |
current_company_domain | domain | Extra field. Good dedupe key across lists. |
profile_url | linkedin | Extra field. Not needed for sending. |
person_id | externalId | Extra field. Add it to columns to re-match later. |
Column ids come from GET /v1/exports/columns, which needs no key. Email status has 13 values, and catch_all is left out here on purpose.
Cost at 10,000 rows
Ten thousand rows need LeadOcean Pro at $499 a month flat, plus a ReachHQ plan sized by sending volume, not by lead count. ReachHQ says it has no per-lead credit system, and its plans are limited by emails per month (source: ReachHQ pricing, September 2026).
| Item | Free LeadOcean | Pro LeadOcean |
|---|---|---|
| LeadOcean | 1,000 records, one-off, no card | $499 a month, flat |
| Rows you can export | Up to 1,000 | Up to 50,000 per export |
| ReachHQ Solo | $99 a month, 75,000 emails, 2 seats, 1 workspace, no API access | Same |
| ReachHQ Scale | $299 a month, 750,000 emails, 10 seats, 3 workspaces, API access | Same |
| ReachHQ free trial | 14 days, 3,000 emails, no card | Same |
A 3-step sequence to 10,000 people is 30,000 emails, which fits inside Solo's 75,000. That sum is ours, and it ignores follow-ups you add. But ReachHQ's pricing page marks API access "No" for Solo and the free trial and "Yes" for Scale (ReachHQ pricing, October 2026). This API recipe needs Scale at $299 a month.
On LeadOcean, an export reserves one record per row up to limit, and Pro covers it flat. There is no per-record price, no credits and no overage invoice. The free plan runs a 1,000-row test of the whole recipe.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| 402 on export create | Fewer records left than limit reserves. | Lower limit, or move to Pro. |
| 403 on export create | Contact columns asked without the enrich scope. | Use a key with that scope, or drop the email columns. |
| 409 on download | The export is still running. | Poll until data.status is done. |
| 410 on download | The file expired after 7 days. | Create the export again. |
| 401 from ReachHQ | Missing or wrong bearer token. | Send Authorization: Bearer rhq_live_..., not x-api-key. |
| 403 from ReachHQ | The key lacks a scope. | Add leads:write, lead_lists:write or campaigns:write in Settings, API keys. |
400 on commit with listId | The list is dynamic, or the row shape is wrong. | Use a STATIC list. Run dryRun and read the preview. |
429 RATE_LIMITED | More than 600 requests in 60 seconds. | Wait a minute and resend the chunk. |
Campaign audience shows RUNNING | A large list builds asynchronously. | Poll audienceJobStatus with the jobId. |
FAQ
Do I need LeadOcean if ReachHQ has its own lead finder?
Only if you want LeadOcean's filters and its email status values on the list. ReachHQ has its own finder and says enrichment is unlimited on paid plans. Use this recipe when your list comes from LeadOcean filters or an earlier export.
Which emails should I import?
Import verified and catch_all_valid. Treat every other status as unsent until you review it.
Can I import without code?
ReachHQ's public pages do not document an in-app CSV import, so check the app at app.reachhq.io. Download the LeadOcean CSV from the Exports page at app.leadocean.io, which has a filter builder, a column picker, the record price before you start and a Download button.
Can an AI agent run this?
Yes. LeadOcean's MCP server is at https://api.leadocean.io/mcp and has an export_leads tool that costs one record per row. ReachHQ lists its own MCP server at https://api.reachhq.io/mcp.
Export your first ReachHQ 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 →