> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blitz-api.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript / JavaScript SDK

<div style={{position:'absolute',width:'1px',height:'1px',padding:0,margin:'-1px',overflow:'hidden',clipPath:'inset(50%)',whiteSpace:'nowrap',border:0}}>
  > **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](https://docs.blitz-api.ai/llms.txt).
</div>

`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](/api-reference/account/get-api-key-details) exactly.

<CardGroup cols={2}>
  <Card title="npm" icon="npm" href="https://www.npmjs.com/package/blitz-api-js">
    `blitz-api-js` on the npm registry.
  </Card>

  <Card title="GitHub" icon="github" href="https://github.com/api-blitz/blitz-api-js">
    Source, changelog, and issues.
  </Card>
</CardGroup>

## Install

```bash theme={null} theme={null}
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

```ts theme={null} theme={null}
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:

```js theme={null} theme={null}
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.

```ts theme={null} theme={null}
const explicit = new BlitzAPI({ api_key: "sk_..." }); // explicit
const fromEnv = new BlitzAPI();                        // reads BLITZ_API_KEY
```

<Warning>
  Never expose your API key in client-side code (browsers, mobile apps). Always call Blitz from your backend.
</Warning>

## Endpoints

All methods are grouped into five namespaces. Each takes a single options object (snake\_case keys) and returns a typed, Zod-validated response. The five **list** methods (`search.people`, `search.companies`, `search.employee_finder`, `jobs.search`, `jobs.company`) return a paginated `PagePromise` (see [Pagination](#pagination)); `waterfall_icp` and the `enrichment` / `utils` / `account` methods return their response directly.

### `client.account`

```ts theme={null} theme={null}
const info = await client.account.key_info();
console.log(info.valid, info.remaining_credits, info.max_requests_per_seconds);
console.log(info.allowed_apis);
```

### `client.search`

```ts theme={null} theme={null}
// 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.jobs`

```ts theme={null} theme={null}
// Live job postings across companies (cursor-paginated — see Pagination below).
const jobs = await client.jobs.search({
  job: {
    title: { include: ["Head of Sales"] },
    seniority: { include: ["5-10"] },
    employment_type: { include: ["FULL_TIME"] },
    work_arrangement: { include: ["Hybrid", "Remote OK"] },
    date_posted: { last_days: 30 },
  },
  company: {
    industry: { include: ["Software Development"] },
    size: { include: ["51-200", "201-500"] },
  },
  max_results: 25,
});
for (const job of jobs.data) {
  console.log(job.company_name, job.title, job.location?.city);
}

// Postings at one company (cursor-paginated).
const companyJobs = await client.jobs.company({
  company_linkedin_url: "https://www.linkedin.com/company/openai",
  job: { field: { include: ["Software Engineering"] } },
  max_results: 25,
});
for (const job of companyJobs.data) {
  console.log(job.title, job.url);
}
```

### `client.enrichment`

```ts theme={null} theme={null}
// 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);

// Company employees grouped by country.
const byCountry = await client.enrichment.company_distribution_by_country({
  company_linkedin_url: "https://www.linkedin.com/company/openai",
});
for (const row of byCountry.distribution) {
  console.log(row.country, row.count, row.percentage_ratio);
}

// Company employees grouped by department.
const byDepartment = await client.enrichment.company_distribution_by_department({
  company_linkedin_url: "https://www.linkedin.com/company/openai",
});
for (const row of byDepartment.distribution) {
  console.log(row.department, row.count, row.percentage_ratio);
}
```

### `client.utils`

```ts theme={null} theme={null}
// Current server date/time.
const now = await client.utils.current_date();
```

## Pagination

The list methods (`search.people`, `search.companies`, `search.employee_finder`, `jobs.search`, `jobs.company`) return a `PagePromise` — `await` it for the first page, or `for await` to stream every item across all pages (each fetched on demand).

```ts theme={null} theme={null}
// 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](/sdks/pagination)** for `max_items`, `.collect()`, manual paging, page metadata, and the per-result billing caveat.

## Configuration

```ts theme={null} theme={null}
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, per endpoint; 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 per-endpoint request-per-second limit (`rate_limit_rps`, default 5) and retries automatically on `429` — see **[Rate limits & retries](/sdks/rate-limits)**.

## Error handling

```ts theme={null} theme={null}
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](/sdks/rate-limits)** 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.

```ts theme={null} theme={null}
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

<CardGroup cols={2}>
  <Card title="Python SDK" icon="python" href="/sdks/python">
    The same API surface with sync + async clients.
  </Card>

  <Card title="Field Normalization" icon="list-check" href="/guide/reference/normalization">
    Accepted values for industry, job level, job function, and geography filters.
  </Card>

  <Card title="API reference" icon="code" href="/api-reference/account/get-api-key-details">
    Full request/response schemas and an interactive try-it console.
  </Card>

  <Card title="Recipes" icon="rotate" href="/guide/recipes/icp-list-building">
    End-to-end workflows: build an ICP list, enrich it, and sync to your CRM.
  </Card>
</CardGroup>
