You can enrich Airtable records with LeadOcean using the Run a script automation action and no extra tool. The script reads an email or LinkedIn URL from a record, calls POST /v1/people/enrich, and writes job title, company and phone back to that record. Airtable scripts can call outside APIs with fetch, so the script is the whole integration.
This is a recipe, not a marketplace app. LeadOcean has no Airtable extension, and you do not need one. Run a script is not available on Airtable's Free plan (Airtable help center, October 2026), so you need a paid Airtable workspace.
How it works
- Create an API key. Sign up at
app.leadocean.io, open API keys, and copy a key. The Free plan gives both scopes (search and enrich) inside 1,000 records. - Add the fields. In your table add
Email,LinkedIn URL,Name,Job title,Company,PhoneandEnrich status. Leave the last five empty. - Make a view. Create a view named
Needs enrichment. Filter it to records whereEmailorLinkedIn URLis not empty andEnrich statusis empty. - Create the automation. Use the trigger "When a record enters a view" and pick
Needs enrichment. Airtable recommends a view built for the automation. - Add a Run a script action. Add three input variables:
recordId,emailandlinkedin, each mapped from the trigger record. Paste the script from Configuration. - Test, then turn it on. Run the test on one record. The record gets
doneinEnrich statusand drops out of the view. - Backfill or schedule. Existing rows that match the view run when the automation is switched on. For a nightly pass, swap the trigger for "At a scheduled time" and add a Find records step.
Dedupe comes from the view. A record with Enrich status filled never re-enters it, so a re-run never spends a second record. Clear the cell to re-enrich on purpose.
Configuration
The script uses the canonical endpoint and the x-api-key header. It handles one record per run, which keeps it well inside the action's timeout: 30 seconds, temporarily raised to 120 (Airtable help, October 2026). It writes the result with updateRecordAsync.
const BASE = "https://api.leadocean.io";
const cfg = input.config(); // recordId, email, linkedin, key
const table = base.getTable("Leads");
const body = cfg.email
? { email: String(cfg.email).trim().toLowerCase(), reveal_email: true }
: { linkedin_url: String(cfg.linkedin).trim(), reveal_email: true };
const res = await fetch(BASE + "/v1/people/enrich", {
method: "POST",
headers: { "x-api-key": cfg.key, "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (res.status === 404) {
await table.updateRecordAsync(cfg.recordId, { "Enrich status": "no match" });
} else if (res.status !== 200) {
await table.updateRecordAsync(cfg.recordId, { "Enrich status": "error " + res.status });
} else {
const d = (await res.json()).data;
const prof = d.profile_data || {};
const c = d.contact_data || {};
const job = (c.contact_current_experiences || [])[0] || {};
const phone = (c.contact_phones || [])[0] || {};
await table.updateRecordAsync(cfg.recordId, {
"Name": prof.profile_full_name || "",
"Job title": job.job_title || "",
"Company": job.company_name || "",
"Phone": phone.phone || "",
"Enrich status": "done",
});
}Add key as a fourth input variable and paste your LeadOcean key as its value. Anyone who can edit the automation can read it, so create a dedicated key for Airtable and revoke it from the app if the base is shared by mistake. Agency includes 5 API keys.
The same request from a terminal, to test a key before you touch the base:
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}'Send exactly one of linkedin_url, email, phone or person_id. There is no name plus domain lookup. To start from a company domain, search first with /v1/people/search, then enrich by person_id.
Field mapping
Paths are under data in the response, from the enrich docs, October 2026.
| LeadOcean field | Airtable field | Note |
|---|---|---|
input email or linkedin_url | Email or LinkedIn URL | Exactly one per call |
profile_data.profile_full_name | Name | Full name as one string |
contact_data.contact_current_experiences[0].job_title | Job title | The current role |
contact_data.contact_current_experiences[0].company_name | Company | Same object as the title |
contact_data.contact_phones[0].phone | Phone | Only with reveal_email: true |
| script result | Enrich status | done, no match or error <code> |
Use plain text fields for the output. The script sends reveal_email: true, which also returns contact_data.contact_emails[] with a status per address. It costs no extra record.
Cost at 10,000 rows
Ten thousand rows cost 10,000 records at most, and fewer if some do not match. A person LeadOcean holds nothing for returns 404 and costs nothing.
| Item | What it costs |
|---|---|
| LeadOcean Free | $0, but the 1,000 records are for life, so Free covers 1,000 rows, not 10,000 |
| LeadOcean Solo | $97 a month. Allows 10k enrichments every 5 hours, so one pass fits |
| LeadOcean Agency | $497 a month. 1M enrichments a day |
| Airtable Team | $20 per seat a month, billed annually; the page shows no monthly-billed rate. 25,000 automation runs, 50,000 records per base (Airtable pricing, October 2026) |
One run enriches one record, so 10,000 rows use 10,000 of the 25,000 monthly runs on Team. Failed runs count too (Airtable help center, October 2026), so fix a broken script before you backfill. Airtable's Free plan has 100 automation runs and 1,000 records per base, which rules it out here.
Airtable's API allows 5 requests a second per base (Airtable API docs, September 2026). The script writes through Airtable's own scripting API, not the REST API, so the limit that matters is LeadOcean's: 5 a second on Free, 50 on Solo, 200 on Agency.
Paid plans have a fair-use pace, not credits. Reaching it slows the key until the window resets. Nothing to top up. See pricing.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
error 401 in Enrich status | Key missing or pasted with a space | Re-paste the key into the key input variable |
error 402 | Free plan's 1,000 records are spent | Move to Solo, or enrich a smaller list |
error 429 | Many records entered the view at once | Retry after the Retry-After header, or move to a plan with a higher rate |
Every record says no match | Personal emails or typos | Fill LinkedIn URL and trim whitespace |
| Run a script is missing | Workspace is on Airtable Free | Move the workspace to a paid plan |
| Automation never fires | Record does not match the view filter | Open the view and check the filter on Enrich status |
FAQ
Is there a LeadOcean extension for Airtable?
No. This recipe uses the Run a script action. You own the code and can change the mapping.
Can I enrich from a company domain?
Not directly. Enrich needs an email, LinkedIn URL, phone or person_id. Use GET /v1/companies/{domain}/people or /v1/people/search to list people at a domain, import the person_id values, and enrich those.
Will a re-run charge me twice?
Not if Enrich status is filled. The view skips finished records.
When should I skip Airtable?
For a big list, skip the base. Size it first with the free GET /v1/companies/count call or the leadocean_count_leads MCP tool, then pull it with POST /v1/exports. The app at app.leadocean.io also has an Exports page with a filter builder and a price preview, and you can import the CSV into Airtable afterwards. Bulk CSV export is not on Free.
Read email_status before you send anything. Bounced emails are not refunded.
The same pattern works from Retool, Notion and Folk. Back to all integrations.
Fill your next Airtable base from one API key
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →