June 11, 202610 min read

Email Finder API in Node.js: Find & Verify Emails with fetch (2026)

Node.js is the go-to runtime for webhook handlers, serverless functions, and CRM automation scripts. This guide covers working code for all four emailfinder.dev endpoints, TypeScript types, batch processing with Promise.all, and an Express webhook handler pattern.

No SDK needed — everything uses the native fetch API available from Node 18+.

Prerequisites

Node 18 or later includes native fetch — no node-fetch package required. Get your API key at emailfinder.dev/register. Set it as an environment variable rather than hardcoding it in your source.

const API_KEY = process.env.EMAILFINDER_API_KEY; const BASE_URL = 'https://www.emailfinder.dev/api';

Person email lookup

Find a verified email from a full name and company domain:

async function findPersonEmail(fullName, domain) { const params = new URLSearchParams({ full_name: fullName, domain }); const res = await fetch(`${BASE_URL}/find-email/person?${params}`, { headers: { Authorization: `Bearer ${API_KEY}` }, }); const data = await res.json(); return data.status === 'found' ? data.email : null; } const email = await findPersonEmail('Jane Doe', 'acme.com'); console.log(email); // jane.doe@acme.com or null

The API returns status: 'found' with an email field, or status: 'not_found'. You are not charged for not_found results.

LinkedIn lookup

Resolve a verified email from any LinkedIn profile URL:

async function findLinkedInEmail(linkedinUrl) { const params = new URLSearchParams({ linkedin_url: linkedinUrl }); const res = await fetch(`${BASE_URL}/find-email/linkedin?${params}`, { headers: { Authorization: `Bearer ${API_KEY}` }, }); const data = await res.json(); return data.status === 'found' ? data : null; } const result = await findLinkedInEmail('linkedin.com/in/janedoe'); if (result) console.log(result.email, result.full_name);

All four endpoints

Company emails — find up to 20 verified addresses at a domain:

async function findCompanyEmails(domain) { const res = await fetch( `${BASE_URL}/find-email/company?domain=${domain}`, { headers: { Authorization: `Bearer ${API_KEY}` } } ); const data = await res.json(); return data.emails ?? []; }

Decision maker — find a role holder at a company without knowing their name:

async function findDecisionMaker(domain, role) { const params = new URLSearchParams({ domain, decision_maker_category: role, }); const res = await fetch(`${BASE_URL}/find-email/decision-maker?${params}`, { headers: { Authorization: `Bearer ${API_KEY}` }, }); const data = await res.json(); return data.status === 'found' ? data : null; } const ceo = await findDecisionMaker('stripe.com', 'ceo'); console.log(ceo?.email, ceo?.full_name);

TypeScript types

Add types to make your integration more robust:

interface EmailFinderResult { status: 'found' | 'not_found'; email?: string; full_name?: string; title?: string; linkedin_url?: string; } async function findPersonEmailTyped( fullName: string, domain: string ): Promise<EmailFinderResult> { const params = new URLSearchParams({ full_name: fullName, domain }); const res = await fetch(`${BASE_URL}/find-email/person?${params}`, { headers: { Authorization: `Bearer ${API_KEY}` }, }); return res.json() as Promise<EmailFinderResult>; }

Batch processing with Promise.all

Find emails for multiple contacts in parallel:

const contacts = [ { name: 'Jane Doe', domain: 'acme.com' }, { name: 'John Smith', domain: 'example.com' }, { name: 'Alice Brown', domain: 'techcorp.io' }, ]; const results = await Promise.all( contacts.map(async (c) => ({ ...c, email: await findPersonEmail(c.name, c.domain), })) ); results.forEach((r) => console.log(r.name, r.email));

The API supports 1,000 requests per minute, so batches of 50–100 concurrent requests are safe. For very large batches, chunk the array and add a small delay between chunks.

Express webhook handler

A pattern for enriching contacts automatically when they enter your CRM:

import express from 'express'; const app = express(); app.use(express.json()); app.post('/webhooks/new-contact', async (req, res) => { const { full_name, company_domain, contact_id } = req.body; // Enrich the contact in the background res.json({ received: true }); const result = await findPersonEmailTyped(full_name, company_domain); if (result.status === 'found') { // Update your CRM with result.email console.log(`Enriched ${contact_id}: ${result.email}`); } }); app.listen(3000);

Respond to the webhook immediately and run the enrichment asynchronously to avoid CRM timeout errors.

Error handling

Handle rate limits and network errors cleanly:

async function findEmailWithRetry(fullName, domain, retries = 3) { for (let i = 0; i < retries; i++) { const res = await fetch( `${BASE_URL}/find-email/person?full_name=${encodeURIComponent(fullName)}&domain=${domain}`, { headers: { Authorization: `Bearer ${API_KEY}` } } ); if (res.status === 429) { await new Promise((r) => setTimeout(r, 1000 * 2 ** i)); continue; } const data = await res.json(); return data.status === 'found' ? data.email : null; } return null; }

Get your free API key

Free credits included. No credit card required.