Real-time enrichment means one API call fired by the lead's arrival, not a nightly batch. The call takes an email and returns the job title, company and contact details before the lead reaches your CRM. This guide shows five tools that do it, from a raw request to three no-code builders, and which one to pick.
TL;DR
- Five tools, one request. Every tool below sends the same
POST /v1/people/enrichcall to LeadOcean. Only the trigger changes. - Time: about 30 minutes for the API call plus a webhook handler. Each no-code tool adds 15 to 20 minutes.
- Cost: one LeadOcean record per lead found. A lead we hold nothing for is a 404 and costs nothing.
Pick by where your lead lands. Real-time only matters if the data arrives before someone acts on the lead: a routing rule, a rep alert or an auto-reply. A form on your own site: use the handler in Step 2. A CRM or sheet you already automate: use n8n, Zapier or Make.
Prerequisites
- A LeadOcean key from app.leadocean.io/register. The free plan needs no card and holds 1,000 records, one-off. Export it as
$LEADOCEAN_API_KEY. curl, and Node 18 or later for Step 2.- For Steps 3 to 5, an account on the tool. Webhooks by Zapier is not on Zapier's Free plan (Zapier pricing, September 2026).
Step 1: Make the enrich call
Send one identifier and reveal_email: true. The identifier is one of linkedin_url, email, phone or person_id. Two identifiers return a 400.
curl -X POST https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"jane.doe@acme.com","reveal_email":true}'reveal_email costs no extra record. Without it, contact points stay hidden and you only see has_email and has_phone flags.
There is no name plus domain lookup. If a lead gives you only a name and company, search by domain first, then enrich by person_id. Here is the search.
curl -X POST https://api.leadocean.io/v1/people/search \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":["acme.com"],"jobLevel":["VP"],"limit":5}'Take meta.source_ids.person_id from the row and send it as person_id to the enrich call. That search spends records for each row returned, so keep limit low.
The ordering matters in a live flow. Enrich first, then score and route, so the rule sees the title and company size and not just a bare email.
Step 2: Run it from a webhook handler
A 20-line handler enriches a lead as it lands from your form, with no third-party tool. It accepts the form POST, calls LeadOcean, and passes the merged record to your CRM code.
// handler.mjs (node handler.mjs)
import http from "node:http";
http.createServer(async (req, res) => {
let body = "";
for await (const chunk of req) body += chunk;
const lead = JSON.parse(body); // { "email": "jane.doe@acme.com" }
const r = await fetch("https://api.leadocean.io/v1/people/enrich", {
method: "POST",
headers: {
"x-api-key": process.env.LEADOCEAN_API_KEY,
"content-type": "application/json",
},
body: JSON.stringify({ email: lead.email, reveal_email: true }),
});
if (r.status === 404) { res.end(JSON.stringify({ ...lead, enriched: false })); return; }
if (!r.ok) { res.statusCode = 502; res.end(`LeadOcean ${r.status}`); return; }
const { data } = await r.json();
const role = data.contact_data?.contact_current_experiences?.[0] ?? {};
res.end(JSON.stringify({
...lead,
enriched: true,
title: role.job_title,
company: role.company_name,
domain: role.company_domain,
email_status: data.contact_data?.email_status,
}));
}).listen(8080);Test it with curl -d '{"email":"jane.doe@acme.com"}' localhost:8080. A 404 means we hold nobody for that address, so the handler returns the lead unchanged and you pay nothing. Do not retry a 404.
Put the handler behind your form's webhook setting, or call it from your own server-side submit code. Keep the key in an environment variable and never in browser code.
Check email_status before you send mail to the address. A risky or unknown status is not a mailable address, and there is no refund for bounces.
Step 3: Add n8n
n8n gives you the same call with a Webhook node in front. Add a Webhook node as the trigger, then an HTTP Request node that calls the enrich URL. n8n's docs describe the HTTP Request node as the generic way to call any REST API (n8n docs, September 2026).
Create a Header Auth credential with Name x-api-key and your key as Value. Then set the node like this.
| HTTP Request field | Value |
|---|---|
| Method | POST |
| URL | https://api.leadocean.io/v1/people/enrich |
| Authentication | Generic Credential Type, then Header Auth |
| Send Body | JSON |
| JSON body | {"email": "{{ $json.body.email }}", "reveal_email": true} |
Under Settings, turn on "Continue On Fail" or add an If node after the call, so a 404 does not stop the workflow for leads we do not hold. The LeadOcean and n8n recipe covers exports and the MCP Client Tool node.
Rate limits rarely bite a lead flow. Free allows 5 requests a second, and a form that sends more than 5 leads in one second is a spike worth queueing anyway.
Step 4: Add Zapier
Zapier fits a trickle of leads from a CRM or sheet. The Zap has a trigger, a Custom Request, and an update step.
- Trigger: HubSpot "New Contact" or Google Sheets "New Spreadsheet Row".
- Filter: continue only if the email is not empty.
- Webhooks by Zapier, event Custom Request. Method POST, the enrich URL, the JSON body below, headers
x-api-keyandcontent-type. - Update the contact with the title, company and email status from the response.
{
"email": "<Email from the trigger step>",
"reveal_email": true
}Each action step is one Zapier task, so the Custom Request plus the update use two tasks per lead. Triggers and Filter steps use none (Zapier help, September 2026). Run the Test step once and map from the field list Zapier shows. The LeadOcean and Zapier recipe has the full mapping table.
Step 5: Add Make
Make suits a sheet of leads that grows. Use Google Sheets "Watch New Rows", then the HTTP "Make a request" module, then Google Sheets "Update a Row".
| HTTP module field | Value |
|---|---|
| URL | https://api.leadocean.io/v1/people/enrich |
| Method | POST |
| Authentication | API key, header x-api-key |
| Body content type | JSON |
| Request content | {"email": "{{1.email}}", "reveal_email": true} |
| Parse response | Yes |
Make exposes the response fields for mapping only after the module has run once, so click "Run once" with a test row first. Each module run is an operation, and the Watch New Rows trigger uses one operation per check. So a new row costs the HTTP call and the row update, plus the trigger's check (Make help, October 2026). See the LeadOcean and Make recipe for the write-back mapping.
Make bills by operation and Zapier by task. Neither changes what LeadOcean charges, which is one record per person found.
How to choose
Start with the handler if you can write 20 lines. It has no per-run fee, one fewer vendor, and you control the 404 and 429 paths. The no-code tools win when someone other than an engineer owns the flow.
Zapier counts every action step as a task, so two steps per lead means two tasks. Make counts one operation per module run, plus one per trigger check. Compare both against your lead volume before you commit. n8n is the one to pick when the enrichment feeds a branch, for example routing enterprise titles to a rep and the rest to a nurture list.
A fair test is cheap. Send ten known leads through each tool, compare the fields that come back, and count the 404s. Ten leads cost at most 10 records.
What you get
This is the response shape from the API reference, with placeholder values (api.leadocean.io/openapi.json, checked October 2026). Field names come from the Person schema, leadocean.person.v1.
{
"success": true,
"data": {
"profile_data": { "...": "Jane Doe" },
"contact_data": {
"contact_emails": [
{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }
],
"contact_phones": [
{ "phone": "+1 415 555 0133" }
],
"has_email": true,
"has_phone": true,
"email_status": "verified",
"email_type": "work",
"contact_current_experiences": [
{
"job_title": "VP of Sales",
"company_name": "Acme",
"company_domain": "acme.com"
}
]
},
"resume_data": { "experiences": [] },
"meta": {}
}
}Since 17 October 2026, resume_data also carries past roles, education, certifications and awards when we hold them. Past employers have no company_id yet. Phones come back only when reveal_email is true. Keep the verified and catch_all_valid addresses for sending, and route the rest to review.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Key missing, wrong or revoked | Check the x-api-key header has the key and no spaces around it. |
| 400 | Two identifiers sent, or invalid JSON | Send exactly one of email, linkedin_url, phone or person_id. |
| 402 | The free 1,000 records are spent | Move to Solo at $97 a month or Agency at $497 a month. See pricing. |
| 404 | We hold nothing for that person | No charge. Return the lead unchanged. Retrying will not change the answer. |
| 429 | Above the plan's rate limit | The limit is 5 requests a second on Free and 200 on Agency. Read Retry-After and queue the calls. |
| Empty title or company | The person has no current role on record | Fall back to profile_data, or enrich by linkedin_url instead of email. |
FAQ
Which of the five tools should I pick?
Use the handler in Step 2 if the lead starts on your own form or app. Use n8n if you already run workflows and want branching. Use Zapier or Make if the lead lands in a CRM or sheet and a no-code step is enough.
How fast is the call?
Run time curl on your own key and see. We publish no latency figure, so any number in a competitor article needs a source and a date.
Does a lead we cannot enrich cost a record?
No. A person we hold nothing for is a 404 and costs nothing. An enrichment that finds nothing is free.
Can I enrich by LinkedIn URL instead of email?
Yes. Send linkedin_url in place of email. If you have neither, search by domain and enrich by person_id.
What does it cost for a steady flow of leads?
Free covers the first 1,000. Paid plans use a fair-use pace, not per-record credits. Solo is $97 a month for one person. Agency is $497 a month for teams, with 200 requests a second.
Read how this fits the wider pipeline in real-time lead data for your B2B sales pipeline, the people data enrichment API guide, and the B2B lead enrichment overview.
Enrich your next lead the second it arrives
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →