npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

enrichmentapi

v0.1.0

Published

Node SDK for EnrichmentAPI's enrichment endpoints (person, company, email finder/verifier, employee finder, funding).

Readme

enrichmentapi

Node SDK for EnrichmentAPI — typed methods for its 8 enrichment endpoints, sane per-endpoint timeouts, and consistent error handling, so you don't have to hand-roll fetch calls, api_key query params, and ad-hoc error checks yourself.

This is a thin client against the public https://api.enrichmentapi.io API — it does not depend on or import the EnrichmentAPI server codebase, Mongo, or any of its internal env vars. It's a standalone package.

Install

npm install enrichmentapi

Usage

import { EnrichmentAPIClient, EnrichmentAPIError } from "enrichmentapi";

const client = new EnrichmentAPIClient(process.env.ENRICHMENTAPI_KEY);

try {
  const domain = await client.companyToDomain("stripe");
  console.log(domain);
} catch (err) {
  if (err instanceof EnrichmentAPIError) {
    console.error(`Request failed (${err.statusCode}): ${err.message}`);
  } else {
    throw err;
  }
}

Get your API key from your account dashboard at enrichmentapi.io.

Examples

Verified live against the real API (person/company/employeeFinder spend credits on your account — they hit a live LinkedIn scrape/search on a cache miss, the others don't):

await client.person("https://www.linkedin.com/in/satyanadella");
// -> { name, first_name, last_name, headline, current_company, current_role, location, about, education, ... }

await client.company("https://www.linkedin.com/company/stripe");
// -> [{ company_name, universal_name_id, industry, location, follower_count, about, ... }]  <- note: an ARRAY

await client.employeeFinder("Stripe", { domain: "stripe.com", limit: 3 });
// -> { success: true, company: "Stripe", people: [{ linkedin_url, slug, name, title, description }, ...] }

await client.emailFinder("satya", "nadella", "microsoft.com");
// -> { email: "[email protected]", find_mail: true, is_reachable: true }

await client.verifyEmail("[email protected]");
// -> { email, isReachable: "invalid" | "safe" | "risky" | ..., confidence_level, image, references }

await client.reverseEmail({ firstName: "Bill", lastName: "Gates" });
// -> { people: [{ fullName, first_name, last_name, public_identifier, profile_url, headline, ... }, ...] }

await client.companyToDomain("microsoft");
// -> { success: true, company: "microsoft", websites: [{ domain, image, isVirtual }, ...] }

await client.companyFunding("stripe.com");
// -> { company, domain, total_raised, currency, valuation, rounds: [{ series, amount, date_month, date_year, investors, ... }] }

Methods

| Method | Endpoint | Purpose | |---|---|---| | person(profileId) | GET /person | LinkedIn profile enrichment | | company(companyId, opts?) | GET /company | LinkedIn company enrichment | | employeeFinder(company, opts?) | GET /employee_finder | Find employees at a company | | emailFinder(firstName, lastName, domain) | GET /email_finder | Guess a work email from name + domain | | verifyEmail(email) | GET /verify_email | Verify email deliverability | | reverseEmail({ email } \| { firstName, lastName }) | GET /reverse_email | Find a person from an email or name | | companyToDomain(company) | GET /company_to_domain | Resolve a company name to its domain | | companyFunding(domain) | GET /company_funding | Company funding/investment data |

Not included: /tech_stack (currently returns a hardcoded 503 Under Maintenance in EnrichmentAPI itself), and the older /employees / /investment / /email routes, which are superseded by the endpoints above.

person and company use a longer timeout (70s) than the other methods (20s) — both hit a live LinkedIn scrape upstream on a cache miss.

Error handling

Every failure — a non-2xx HTTP status, an explicit {success:false} response body (EnrichmentAPI reports some failures this way even on 2xx-adjacent paths), a request timeout, or a non-JSON response — throws an EnrichmentAPIError with:

  • message — human-readable failure reason
  • statusCode — HTTP status, or 0 if no HTTP response was ever received (timeout, network failure, or client-side validation like an incomplete reverseEmail query)
  • body — the parsed response body, if one was received

On success, methods resolve with the parsed JSON response body as-is. The response shape is not uniform across endpoints, or even within one endpoint:

  • A cached /person hit returns the raw record with no success field at all, while /company_to_domain and /employee_finder include success: true.
  • company()'s response is a JSON array of one record, not an object — confirmed live (see Examples above) — while every other method returns a plain object.

There's no published schema to type response bodies against yet, so they're typed as unknown — narrow/ validate on your end if you need guarantees beyond "this is valid JSON from a successful call."

Testing

npm test          # unit tests against a mocked fetch, no network calls or API key needed
npm run smoke      # one live call against the real API -- needs ENRICHMENTAPI_KEY

For the smoke test:

cp example.env .env   # then edit .env and set ENRICHMENTAPI_KEY
npm run build
npm run smoke

Development

src/
  client.ts   # EnrichmentAPIClient class + private request() helper
  errors.ts   # EnrichmentAPIError
  types.ts    # per-endpoint option types
  index.ts    # public exports
test/
  client.test.ts   # unit tests, mocked fetch
scripts/
  smoke-test.mjs   # end-to-end connectivity + live-call check, see Testing above
npm run build   # tsup -> dist/ (ESM + CJS + .d.ts)
npm test

Troubleshooting

Process crashes with Assertion failed: !(handle->flags & UV_HANDLE_CLOSING) (Windows only) — happens if your script calls process.exit() immediately after an SDK call resolves. The client uses AbortSignal.timeout() internally, and on Windows, forcing an immediate exit can race libuv's cleanup of that timer's handle. Set process.exitCode instead and let the script finish naturally (as scripts/smoke-test.mjs does) rather than calling process.exit() directly.

verifyEmail times out under its default 20s timeout — seen live against the real API; the endpoint can run a live SMTP-style check that occasionally exceeds 20s. This matches enrichmentapi-mcp's default timeout for the same endpoint (parity, not a bug in this SDK) — if it's a recurring problem, that's worth raising with EnrichmentAPI directly rather than just retrying client-side.