Find and verify professional emails and find phone numbers with the Enrow API.
The package is not published on npm: install it from GitHub. npm builds it during the install (Node.js 18 or later, git required).
npm install github:EnrowAPI/enrow-jsAdd #<commit> or #<tag> to the URL to pin a version.
To build it from a clone instead:
git clone https://github.com/EnrowAPI/enrow-js.git
cd enrow-js && npm install && npm run build
# then, from your project
npm install /path/to/enrow-jsimport Enrow from 'enrow';
const enrow = new Enrow('YOUR_API_KEY');
const result = await enrow.email.find(
{ fullName: 'Dwight Schrute', companyDomain: 'dundermifflin.com' },
{ waitForResult: true },
);
console.log(result.qualification); // "valid"
console.log(result.email); // "dwight.schrute@dundermifflin.com"Searches are asynchronous: find() starts a search and resolves with its id right away. Read the result with get(id), receive it on a webhook, or pass { waitForResult: true } and the SDK polls it for you.
// Start a search: resolves with its id
const search = await enrow.email.find({
fullName: 'Dwight Schrute',
companyDomain: 'dundermifflin.com', // or companyName: 'Dunder Mifflin'
custom: { crmId: 'lead_001' }, // returned as-is with the result
settings: {
webhook: 'https://your-app.com/webhooks/enrow',
countryCode: 'US', // helps with companyName
retrieveGender: true,
retrieveCompanyInfo: true, // only effective with countryCode 'FR'
},
});
console.log(search.id);
// Read the result: qualification is "ongoing" until the search ends
const result = await enrow.email.get(search.id);
if (result.qualification === 'valid') {
console.log(result.email, result.info?.gender);
}
// Or wait for it: polls every 2 s (pollInterval), for up to 60 s (timeout)
const found = await enrow.email.find(
{ fullName: 'Dwight Schrute', companyDomain: 'dundermifflin.com' },
{ waitForResult: true, pollInterval: 2000, timeout: 60000 },
);
// Still "ongoing" after the timeout: read it later with enrow.email.get(found.id)const fromProfile = await enrow.email.find(
{ linkedinUrl: 'https://www.linkedin.com/in/dwight-schrute' },
{ waitForResult: true },
);
console.log(fromProfile.linkedinStatus); // "found", "email_not_found"...Enrow reads the profile and looks for the email at the person's current company. This works for single searches only and may not be available on every account: see Search from a LinkedIn profile URL.
// Up to 5,000 searches per batch
const batch = await enrow.email.findBulk({
searches: [
{ fullName: 'Dwight Schrute', companyDomain: 'dundermifflin.com', custom: 'lead_001' },
{ fullName: 'Jim Halpert', companyName: 'Dunder Mifflin', custom: 'lead_002' },
],
settings: { webhook: 'https://your-app.com/webhooks/enrow' },
});
const bulk = await enrow.email.getBulk(batch.id);
if (bulk.general.status === 'completed') {
for (const row of bulk.results ?? []) {
console.log(row.custom, row.qualification, row.email);
}
}const verification = await enrow.verify.single({ email: 'pam.beesly@dundermifflin.com' });
// Once the verification has run ("ongoing" before), or on your webhook
const check = await enrow.verify.get(verification.id);
console.log(check.qualification); // "valid" or "invalid"
// Bulk: up to 5,000 addresses per batch
const batch = await enrow.verify.bulk({
verifications: ['pam.beesly@dundermifflin.com', 'angela.martin@dundermifflin.com'],
});
const results = await enrow.verify.getBulk(batch.id);// From a LinkedIn profile URL (recommended)
const search = await enrow.phone.find({
linkedinUrl: 'https://www.linkedin.com/in/michael-scott/',
});
// Or from a name and a company
const byName = await enrow.phone.find({
firstName: 'Michael',
lastName: 'Scott',
companyDomain: 'dundermifflin.com', // or companyName: 'Dunder Mifflin'
});
// Wait for the result
const phone = await enrow.phone.find(
{ linkedinUrl: 'https://www.linkedin.com/in/michael-scott/' },
{ waitForResult: true },
);
if (phone.qualification === 'found') {
console.log(phone.number, phone.country); // "+15705551234" "US"
}
const details = await enrow.phone.get(search.id);
// Bulk: up to 3,000 searches per batch
const batch = await enrow.phone.findBulk({
searches: [
{ linkedinUrl: 'https://www.linkedin.com/in/michael-scott/' },
{ firstName: 'Dwight', lastName: 'Schrute', companyName: 'Dunder Mifflin' },
],
});
const results = await enrow.phone.getBulk(batch.id);const account = await enrow.account.info();
console.log(account.credits); // 8500import Enrow, { AuthenticationError, InsufficientBalanceError, RateLimitError, EnrowError } from 'enrow';
try {
await enrow.email.find({ fullName: 'Dwight Schrute', companyDomain: 'dundermifflin.com' });
} catch (err) {
if (err instanceof InsufficientBalanceError) {
// 402: not enough credits
} else if (err instanceof RateLimitError) {
// 429: over 10 requests per second on POST endpoints, retry with backoff
} else if (err instanceof AuthenticationError) {
// 401: missing or invalid API key
} else if (err instanceof EnrowError) {
console.log(err.status, err.message);
}
}| Endpoint | Cost |
|---|---|
| Email Finder | 1 credit per email found |
| Email Verifier | 0.25 credit per check |
| Phone Finder | 40 credits per phone found (50 on legacy plans) |
See Credits & billing for the details.
MIT