Skip to main content
Agents & LLMs: a Markdown version of this page is available by appending .md to the URL, and the full documentation index is at llms.txt.
blitz-api-js is the official, typed TypeScript SDK for the Blitz API. It is fetch-based, Zod-validated, ships both ESM and CommonJS builds with .d.ts / .d.cts types, and uses snake_case request and response fields that match the API reference exactly.

npm

blitz-api-js on the npm registry.

GitHub

Source, changelog, and issues.

Install

npm install blitz-api-js
# or: pnpm add blitz-api-js  /  yarn add blitz-api-js
Requires Node.js 20+ (or any runtime with a global fetch). Ships both ESM and CommonJS builds.

Quickstart

import { BlitzAPI } from "blitz-api-js";

// api_key defaults to the BLITZ_API_KEY environment variable.
const client = new BlitzAPI();

// Health-check the key before a batch job.
const info = await client.account.key_info();
console.log(info.valid, info.remaining_credits, info.max_requests_per_seconds);

// LinkedIn profile URL -> verified work email.
const email = await client.enrichment.email({
  person_linkedin_url: "https://www.linkedin.com/in/example-person",
});
if (email.found) console.log(email.email);

// Search people — list methods are paginated; one page's items live on `.data`.
const page = await client.search.people({
  company: { industry: { include: ["Software Development"] } },
  people: { job_level: ["VP"] },
  max_results: 10,
});
for (const person of page.data) {
  console.log(person.full_name, person.headline);
}
CommonJS works too:
const { BlitzAPI } = require("blitz-api-js");

Authentication

Pass the key explicitly or via the BLITZ_API_KEY environment variable. It is sent in the x-api-key header on every request.
const explicit = new BlitzAPI({ api_key: "sk_..." }); // explicit
const fromEnv = new BlitzAPI();                        // reads BLITZ_API_KEY
Never expose your API key in client-side code (browsers, mobile apps). Always call Blitz from your backend.

Endpoints

All methods are grouped into four namespaces. Each takes a single options object (snake_case keys) and returns a typed, Zod-validated response. The three search list methods (people, companies, employee_finder) return a paginated PagePromise (see Pagination); waterfall_icp and the enrichment / utils / account methods return their response directly.

client.account

const info = await client.account.key_info();
console.log(info.valid, info.remaining_credits, info.max_requests_per_seconds);
console.log(info.allowed_apis);
// People across many companies (cursor-paginated — see Pagination below).
const people = await client.search.people({
  company: {
    industry: { include: ["IT Services and IT Consulting"] },
    employee_range: ["51-200", "201-500"],
    hq: { sales_region: ["EMEA"] },
  },
  people: {
    job_level: ["VP", "Director"],
    job_function: ["Sales & Business Development"],
    min_connections: 200,
  },
  max_results: 25,
});
for (const person of people.data) {
  console.log(person.full_name, person.headline, person.linkedin_url);
}

// Companies by ICP (cursor-paginated).
const companies = await client.search.companies({
  company: {
    keywords: { include: ["SaaS"] },
    industry: { include: ["Software Development"] },
    hq: { country_code: ["FR", "DE"] },
    employee_range: ["51-200", "201-500"],
  },
  max_results: 25,
});
for (const company of companies.data) {
  console.log(company.name, company.industry, company.employees_on_linkedin);
}

// All employees at one company (page-paginated).
const employees = await client.search.employee_finder({
  company_linkedin_url: "https://www.linkedin.com/company/openai",
  job_level: ["C-Team", "VP", "Director"],
  job_function: ["Sales & Business Development"],
  sales_region: ["NORAM"],
  max_results: 50,
});
console.log(`Page ${employees.response.page} of ${employees.response.total_pages}`);
for (const person of employees.data) {
  console.log(person.full_name, person.headline);
}

// Single best decision-maker via a priority cascade (returned directly).
const match = await client.search.waterfall_icp({
  company_linkedin_url: "https://www.linkedin.com/company/openai",
  cascade: [
    { include_title: ["CTO", "VP Engineering"], location: ["WORLD"], include_headline_search: false },
    { include_title: ["Engineering Director", "Engineering Manager"], location: ["WORLD"], include_headline_search: false },
  ],
  max_results: 5,
});
for (const item of match.results) {
  console.log(`[Tier ${item.icp} | Rank #${item.ranking}]`, item.person.full_name);
}

client.enrichment

// LinkedIn profile URL -> verified work email.
const email = await client.enrichment.email({ person_linkedin_url: "https://www.linkedin.com/in/example-person" });
if (email.found) console.log(email.email);

// LinkedIn profile URL -> direct phone (US only).
const phone = await client.enrichment.phone({ person_linkedin_url: "https://www.linkedin.com/in/example-person" });
if (phone.found) console.log(phone.phone);

// Work email -> full person profile.
const byEmail = await client.enrichment.email_to_person({ email: "jane.doe@acme.com" });
if (byEmail.found) console.log(byEmail.person.full_name);

// Phone number -> full person profile (US only).
const byPhone = await client.enrichment.phone_to_person({ phone: "+14155551234" });
if (byPhone.found) console.log(byPhone.person.full_name);

// Company LinkedIn URL -> full company profile.
const company = await client.enrichment.company({ company_linkedin_url: "https://www.linkedin.com/company/openai" });
console.log(company.company.name, company.company.industry, company.company.employees_on_linkedin);

// Website domain -> Company LinkedIn URL.
const toLinkedin = await client.enrichment.domain_to_linkedin({ domain: "openai.com" });
if (toLinkedin.found) console.log(toLinkedin.company_linkedin_url);

// Company LinkedIn URL -> email domain.
const toDomain = await client.enrichment.linkedin_to_domain({ company_linkedin_url: "https://www.linkedin.com/company/openai" });
if (toDomain.found) console.log(toDomain.email_domain);

client.utils

// Current server date/time.
const now = await client.utils.current_date();

// Company employees grouped by country.
const distribution = await client.utils.company_employment_distribution({
  company_linkedin_url: "https://www.linkedin.com/company/openai",
});

Pagination

The search methods (people, companies, employee_finder) return a PagePromiseawait it for the first page, or for await to stream every item across all pages (each fetched on demand).
// Stream every match across all pages — no cursor handling needed.
for await (const person of client.search.people({ people: { job_level: ["VP"] } })) {
  console.log(person.full_name);
}
See Pagination for max_items, .collect(), manual paging, page metadata, and the per-result billing caveat.

Configuration

const client = new BlitzAPI({
  api_key: undefined,   // falls back to BLITZ_API_KEY
  base_url: "https://api.blitz-api.ai",
  timeout: 30,          // default per-request timeout, seconds (via AbortSignal.timeout)
  max_retries: 3,       // retries on 429 / 5xx / pre-response network errors
  rate_limit_rps: 5,    // client-side token bucket; null to disable
  fetch: undefined,     // custom fetch implementation (tests / runtimes)
});

// Override the timeout for a single call — pass an options object as the last argument:
await client.enrichment.email({ person_linkedin_url: "..." }, { timeout: 5 });
A single client instance stays under your key’s request-per-second limit (rate_limit_rps, default 5) and retries automatically on 429 — see Rate limits & retries.

Error handling

import {
  APIConnectionError,
  APIResponseValidationError,
  APIStatusError,
  APITimeoutError,
  AuthenticationError,
  BlitzError,
  InsufficientCreditsError,
  NotFoundError,
  RateLimitError,
  ServerError,
} from "blitz-api-js";

try {
  await client.enrichment.email({ person_linkedin_url: "..." });
} catch (err) {
  if (err instanceof InsufficientCreditsError) {
    // 402 — out of credits
  } else if (err instanceof AuthenticationError) {
    // 401 — bad key
  } else if (err instanceof APIResponseValidationError) {
    // 2xx, but the body wasn't valid JSON or didn't match the schema
  } else if (err instanceof APIStatusError) {
    console.log(err.status_code, err.message, err.body, err.request_id);
  } else if (err instanceof BlitzError) {
    // base class for everything this SDK raises
  }
}
401 / 402 / 404 throw immediately; 429 and 5xx are retried automatically; timeouts surface as APITimeoutError (not retried). See Rate limits & retries for the full retry and timeout behavior.

Types & enums

Response objects keep their snake_case wire keys and preserve unknown fields — if the API adds a property before this SDK models it, the value is still present (typed as unknown); known fields stay precisely typed.
import { INDUSTRY } from "blitz-api-js";              // the full value array (534 industries)
import type { CompanyFilter, Industry } from "blitz-api-js";
Enum-backed filter fields (e.g. industry, job_level, continent) accept a known value — autocompleted from a union like Industry — or any raw string, so a value missing from the vendored taxonomy never blocks you.

Next steps

Python SDK

The same API surface with sync + async clients.

Field Normalization

Accepted values for industry, job level, job function, and geography filters.

API reference

Full request/response schemas and an interactive try-it console.

Recipes

End-to-end workflows: build an ICP list, enrich it, and sync to your CRM.