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

How-to guide

How to Enrich a Lead the Moment It Comes In (5 Tools)

One enrich call, a webhook handler, then n8n, Zapier and Make. Each step has a request you can run today.

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

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/enrich call 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.

bash
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.

bash
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.

js
// 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 fieldValue
MethodPOST
URLhttps://api.leadocean.io/v1/people/enrich
AuthenticationGeneric Credential Type, then Header Auth
Send BodyJSON
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.

  1. Trigger: HubSpot "New Contact" or Google Sheets "New Spreadsheet Row".
  2. Filter: continue only if the email is not empty.
  3. Webhooks by Zapier, event Custom Request. Method POST, the enrich URL, the JSON body below, headers x-api-key and content-type.
  4. Update the contact with the title, company and email status from the response.
json
{
  "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 fieldValue
URLhttps://api.leadocean.io/v1/people/enrich
MethodPOST
AuthenticationAPI key, header x-api-key
Body content typeJSON
Request content{"email": "{{1.email}}", "reveal_email": true}
Parse responseYes

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.

json
{
  "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

ErrorCauseFix
401Key missing, wrong or revokedCheck the x-api-key header has the key and no spaces around it.
400Two identifiers sent, or invalid JSONSend exactly one of email, linkedin_url, phone or person_id.
402The free 1,000 records are spentMove to Solo at $97 a month or Agency at $497 a month. See pricing.
404We hold nothing for that personNo charge. Return the lead unchanged. Retrying will not change the answer.
429Above the plan's rate limitThe limit is 5 requests a second on Free and 200 on Agency. Read Retry-After and queue the calls.
Empty title or companyThe person has no current role on recordFall 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 →