@fiberai/sdk

中文文档
0.0.66发布于 2026/10/31MITTypeScriptESM + CJS构建来源已验证近 30 天下载 2159

Official TypeScript SDK for Fiber AI API

原始使用文档
文档目录29 节
  1. For AI agents (Cursor / Claude / Codex / ChatGPT / Copilot)
  2. Table of Contents
  3. Installation
  4. Quick Start
  5. Authentication
  6. Core Features
  7. Company & People Search
  8. Contact Enrichment
  9. LinkedIn Live Enrichment
  10. Exclusion Lists
  11. Google Maps Search
  12. AI-Powered Research
  13. Advanced Usage
  14. Configuring the built-in client
  15. Pagination Helper
  16. Utility Endpoints
  17. Error Handling
  18. Standard Error Handling
  19. Throwing on Errors
  20. Common HTTP Error Codes
  21. TypeScript Support
  22. Runtime Validation with Zod
  23. Rate Limits & Credits
  24. Rate Limits
  25. Credit Costs
  26. Free Endpoints
  27. Check Your Credits
  28. Support
  29. License

@fiberai/sdk

Official TypeScript/JavaScript SDK for the Fiber AI API - Reach anyone on the planet with verified contacts

npm version License: MIT

For AI agents (Cursor / Claude / Codex / ChatGPT / Copilot)

Do NOT guess operation names — read the canonical agent-facing docs first:

Table of Contents

Installation

npm install @fiberai/sdk
# or
yarn add @fiberai/sdk
# or
pnpm add @fiberai/sdk

Requirements: Node.js 18.0.0 or higher

Quick Start

import { peopleSearch, companySearch, getOrgCredits } from "@fiberai/sdk";

// Check your organization's credit balance
const credits = await getOrgCredits({
  query: { apiKey: "your-api-key" },
});

console.log(`Available credits: ${credits.data?.output.available}`);

// Search for companies
const companies = await companySearch({
  body: {
    apiKey: "your-api-key",
    searchParams: {
      industriesV2: {
        anyOf: ["Software", "Information Technology"],
      },
      // Bucket-valued range. Allowed bounds: 0 | 1 | 10 | 50 | 200 | 500 | 1000 | 5000 | 10000 | null.
      employeeCountV2: {
        lowerBoundExclusive: 50,
        upperBoundInclusive: 1000,
      },
      headquartersCountryCode: {
        anyOf: ["USA"],
      },
    },
    pageSize: 25,
  },
});

// Search for people
const people = await peopleSearch({
  body: {
    apiKey: "your-api-key",
    searchParams: {
      jobTitleV2: {
        anyOf: [
          { type: "term", term: "CEO" },
          { type: "term", term: "CTO" },
          { type: "static-groups", groups: ["c-suite"] },
        ],
      },
      country3LetterCode: { anyOf: ["USA"] },
    },
    pageSize: 25,
  },
});

// Every successful response also carries a `chargeInfo` envelope alongside
// `output`. Source of truth for cost — prefer this over the static table below.
console.log(people.data?.chargeInfo);
// e.g. { method: 'charged-now', creditsCharged: 25, lowCreditAlert: null }

Authentication

All API requests require an API key. Get yours at fiber.ai/app/api.

Include your API key in every request:

  • POST requests: Pass apiKey in the request body
  • GET requests: Pass apiKey as a query parameter
// POST request example
await companySearch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY,
    searchParams: {
      /* ... */
    },
  },
});

// GET request example
await getOrgCredits({
  query: { apiKey: process.env.FIBERAI_API_KEY },
});

Best Practice: Store your API key in environment variables:

# .env
FIBERAI_API_KEY=your_api_key_here

Core Features

Search for companies using 40+ filters including industry, location, revenue, funding, and more.

import { companySearch, companyCount } from "@fiberai/sdk";

// Advanced company search
const result = await companySearch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY,
    searchParams: {
      // Industry filters
      industriesV2: {
        anyOf: ["Software", "Cloud"],
      },

      // Size filters
      employeeCountV2: {
        lowerBoundExclusive: 50,
        upperBoundInclusive: 500,
      },

      // Location filters
      headquartersCountryCode: {
        anyOf: ["USA"],
      },

      // Funding filters
      totalFundingUSD: {
        lowerBound: 1000000,
      },

      // Keywords filter
      keywords: {
        containsAny: ["venture-backed-startup"],
      },
    },
    pageSize: 50,
    cursor: null, // For pagination
  },
});

console.log(`Found ${result.data?.output.data.length} companies`);
console.log(
  `Cursor for next page: ${result.data?.output.nextCursor ?? "none"}`,
);

// Get total count before searching
const count = await companyCount({
  body: {
    apiKey: process.env.FIBERAI_API_KEY,
    searchParams: {
      /* same filters */
    },
  },
});

console.log(`Total companies matching: ${count.data?.output.count}`);

Find decision-makers and key contacts with precise targeting.

import { peopleSearch, peopleSearchCount } from "@fiberai/sdk";

const people = await peopleSearch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    searchParams: {
      // Job title filter. Mix free-form `term` matches with curated
      // `static-groups` ('founder' | 'c-suite' | 'board-member') and
      // `dynamic-groups` ('vp' | 'director' | 'management' | 'entry-level' | ...).
      jobTitleV2: {
        anyOf: [
          { type: "term", term: "CEO" },
          { type: "term", term: "Chief Executive Officer" },
          { type: "static-groups", groups: ["founder", "c-suite"] },
        ],
      },

      // Country filter — ISO 3166-1 alpha-3 codes, not city names.
      country3LetterCode: { anyOf: ["USA"] },

      // Geographic radius filter (use this, not "cities"/"countries").
      location: {
        unionAll: [
          {
            strategy: "radial-distance",
            center: { latitude: 37.7749, longitude: -122.4194 }, // San Francisco
            radius: { unit: "miles", quantity: 50 },
          },
        ],
      },

      // Curated tags. Allowed values include 'decision-maker', 'c-suite',
      // 'experienced-executive', 'second-time-founder', 'phd', etc.
      tags: { anyOf: ["decision-maker", "c-suite"] },

      // Education filter — match by school identifier (LinkedIn id, slug,
      // or domain), not by free-form school name.
      education: {
        anyOf: [
          {
            school: {
              anyOf: [{ domain: "stanford.edu" }, { domain: "harvard.edu" }],
            },
          },
        ],
      },

      getDetailedWorkExperience: true,
      getDetailedEducation: true,
    },

    // `currentCompanies` is a TOP-LEVEL body field, NOT inside searchParams.
    // It expects concrete identifiers, not industry filters. To filter by
    // industry/size/etc, use `syncCombinedSearch` and put company filters
    // under `companyParams`.
    currentCompanies: [
      { domain: "example.com" },
      { linkedinSlugOrURL: "https://linkedin.com/company/example" },
    ],

    pageSize: 100,
  },
});

// Access profile data — `output.data` is a direct array, no `.items` wrapper.
people.data?.output.data.forEach((profile) => {
  console.log(`${profile.name} — ${profile.headline}`);
  console.log(`LinkedIn: ${profile.url}`);

  // There is no `profile.currentJob` field. Current role lives in
  // `experiences[]` filtered by `is_current`.
  const currentRole = profile.experiences?.find((e) => e.is_current);
  if (currentRole) {
    console.log(`Current: ${currentRole.title} at ${currentRole.company_name}`);
  }
});

console.log(`Charged: ${people.data?.chargeInfo.method}`);

Combined Search (Companies + People)

Return matching companies and their employees in a single synchronous call. Filter on the company side (companyParams) and the person side (profileParams) at the same time. For larger result sets you can also run companySearch and peopleSearch independently and paginate each.

import { syncCombinedSearch } from "@fiberai/sdk";

const result = await syncCombinedSearch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    companyParams: {
      industriesV2: {
        anyOf: ["Software"],
      },
      employeeCountV2: {
        lowerBoundExclusive: 200,
      },
    },
    profileParams: {
      jobTitleV2: {
        anyOf: [
          { type: "term", term: "VP of Sales" },
          { type: "term", term: "Sales Director" },
          { type: "static-groups", groups: ["c-suite"] },
          { type: "dynamic-groups", groups: ["vp", "director"] },
        ],
      },
    },
    companyItemLimit: 25,
    profileItemLimit: 100,
  },
});

result.data?.output.companies?.forEach((company) => {
  console.log(company.preferred_name);
});

result.data?.output.profiles?.forEach((profile) => {
  console.log(`${profile.name} - ${profile.headline}`);
});

See syncCombinedSearch for the full parameter surface, or drive the two-step flow via companySearch + peopleSearch when you need cursor-based pagination.

Contact Enrichment

Reveal emails and phone numbers for a known LinkedIn profile. Fiber exposes a three-tier public contract — pick the tier that matches your latency, coverage, and cost tradeoffs:

TierOperationShapeWhen to use
DefaultsyncQuickContactRevealSync, one HTTP callDefault single-profile reveal. Fast, good coverage.
PremiumsyncTurboContactEnrichmentSync, one HTTP callYou need the absolute fastest response and want the widest first-pass waterfall. Premium cost.
ExhaustivetriggerExhaustiveContactEnrichment + pollExhaustiveContactEnrichmentResultAsync, trigger + pollHighest coverage. Kick off a background waterfall that tries every available provider, then poll for results.

For lists of 10–2000 identifiers, use the batch endpoints instead (see Batch Contact Reveal).

Default — syncQuickContactReveal

import { syncQuickContactReveal } from "@fiberai/sdk";

const result = await syncQuickContactReveal({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    linkedinUrl: "https://www.linkedin.com/in/example",
    enrichmentType: {
      getWorkEmails: true,
      getPersonalEmails: true,
      getPhoneNumbers: true,
    },
    // Emails are bounce-validated by default. Set validateEmails: false to skip.
  },
});

console.log("Emails:", result.data?.output.profile?.emails);
console.log("Phones:", result.data?.output.profile?.phoneNumbers);

Premium — syncTurboContactEnrichment

import { syncTurboContactEnrichment } from "@fiberai/sdk";

const result = await syncTurboContactEnrichment({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    linkedinUrl: "https://www.linkedin.com/in/example",
    enrichmentType: {
      getWorkEmails: true,
      getPersonalEmails: true,
      getPhoneNumbers: true,
    },
  },
});

console.log("Emails:", result.data?.output.profile?.emails);

Exhaustive (async waterfall) — triggerExhaustiveContactEnrichment + pollExhaustiveContactEnrichmentResult

triggerExhaustiveContactEnrichment starts a background waterfall that returns the highest coverage at the cost of latency. It returns a taskId immediately; poll pollExhaustiveContactEnrichmentResult every 5–15s until output.done === true.

import {
  triggerExhaustiveContactEnrichment,
  pollExhaustiveContactEnrichmentResult,
} from "@fiberai/sdk";

const trigger: Awaited<ReturnType<typeof triggerExhaustiveContactEnrichment>> =
  await triggerExhaustiveContactEnrichment({
    body: {
      apiKey: process.env.FIBERAI_API_KEY!,
      linkedinUrl: "https://www.linkedin.com/in/example",
      enrichmentType: {
        getWorkEmails: true,
        getPersonalEmails: true,
        getPhoneNumbers: true,
      },
    },
  });

const taskId: string = trigger.data!.output.taskId;

let done: boolean = false;
while (!done) {
  await new Promise<void>((resolve) => setTimeout(resolve, 5000));

  const poll: Awaited<ReturnType<typeof pollExhaustiveContactEnrichmentResult>> =
    await pollExhaustiveContactEnrichmentResult({
      body: { apiKey: process.env.FIBERAI_API_KEY!, taskId },
    });

  done = poll.data?.output.done ?? false;
  if (done) {
    console.log("Emails:", poll.data?.output.profile.emails);
    console.log("Phones:", poll.data?.output.profile.phoneNumbers);
    console.log("Status:", poll.data?.output.profile.status);
  }
}

Batch Contact Reveal — startBatchContactEnrichment + pollBatchContactEnrichment

For 10–2000 LinkedIn identifiers in one task. startBatchContactEnrichment charges credits up front and returns a taskId; pollBatchContactEnrichment returns paginated results with both per-task progress (output.overallStats) and output.done to gate the loop. For larger lists or repeatable workflows, upload a CSV-backed audience and enrich it through the audience workflow instead.

import {
  startBatchContactEnrichment,
  pollBatchContactEnrichment,
} from "@fiberai/sdk";

const start: Awaited<ReturnType<typeof startBatchContactEnrichment>> =
  await startBatchContactEnrichment({
    body: {
      apiKey: process.env.FIBERAI_API_KEY!,
      personDetails: [
        { linkedinUrl: { value: "https://www.linkedin.com/in/example1" } },
        { linkedinUrl: { value: "https://www.linkedin.com/in/example2" } },
      ],
      enrichmentTypes: {
        getWorkEmails: true,
        getPersonalEmails: true,
        getPhoneNumbers: true,
      },
    },
  });

const taskId: string = start.data!.output.taskId;
console.log(`Queued ${start.data!.output.numPeopleEnqueued} profiles`);

let cursor: string | null | undefined = undefined;
let done: boolean = false;

while (!done) {
  await new Promise<void>((resolve) => setTimeout(resolve, 10000));

  const poll: Awaited<ReturnType<typeof pollBatchContactEnrichment>> =
    await pollBatchContactEnrichment({
      body: {
        apiKey: process.env.FIBERAI_API_KEY!,
        taskId,
        cursor,
        take: 100,
      },
    });

  if (!poll.data) break;

  for (const row of poll.data.output.pageResults) {
    console.log(row.inputs.linkedinUrl.value, row.outputs?.emails);
  }

  done = poll.data.output.done;
  cursor = poll.data.output.nextCursor ?? null;

  // `nextCursor` may go null before `done` flips — pause and re-poll if so.
  if (!done && !cursor) await new Promise<void>((r) => setTimeout(r, 5000));
}

LinkedIn Live Enrichment

Get real-time data from LinkedIn with live scraping.

Live Profile Enrichment

import { profileLiveEnrich } from "@fiberai/sdk";

const profile = await profileLiveEnrich({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    // `identifier` accepts a slug ('williamhgates'), a full LinkedIn URL,
    // a Sales Navigator URN ('ACwAAA...'), or a numeric LinkedIn user ID.
    identifier: "https://www.linkedin.com/in/example",
  },
});

// `output` is a discriminated union: { found: true; profile: ... } |
// { found: false; message: string }. Narrow on `output.found` before
// touching `output.profile`.
const out = profile.data?.output;
if (out?.found) {
  console.log(out.profile.name);
  console.log(out.profile.summary);
  console.log(out.profile.experiences);
  console.log(out.profile.detailed_education);
} else if (out) {
  console.warn("not found:", out.message);
}

Live Company Enrichment

import { companyLiveEnrich } from "@fiberai/sdk";

const company = await companyLiveEnrich({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    // The `type` discriminator picks how `value` is interpreted:
    //   'slug'   — LinkedIn slug, e.g. 'microsoft'
    //   'orgId'  — LinkedIn organization id, e.g. '1441'
    //   'liUrl'  — full LinkedIn URL, e.g. 'https://www.linkedin.com/company/microsoft'
    type: "liUrl",
    value: "https://www.linkedin.com/company/example",
  },
});

// Company fields live under `output.company`, not directly on `output`.
console.log(company.data?.output.company.headline);
console.log(company.data?.output.company.description);
console.log(company.data?.output.company.follower_count);

Fetch LinkedIn Posts

import { profilePostsLiveFetch, companyPostsLiveFetch } from "@fiberai/sdk";

// Get profile posts. `identifier` accepts a slug, full LinkedIn URL,
// or Sales Navigator URN — same shape as `profileLiveEnrich`.
const profilePosts = await profilePostsLiveFetch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    identifier: "https://www.linkedin.com/in/example",
    cursor: null, // For pagination
  },
});

// Get company posts. `identifier` accepts a LinkedIn slug, URL, or org ID.
const companyPosts = await companyPostsLiveFetch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    identifier: "https://www.linkedin.com/company/example",
    cursor: null,
  },
});

Exclusion Lists

Manage exclusion lists to filter out companies or prospects from searches.

import {
  createCompanyExclusionList,
  addCompaniesToExclusionList,
  getExcludedCompaniesForExclusionList,
  createCompanyExclusionListFromAudience,
} from "@fiberai/sdk";

// Create an exclusion list
const list = await createCompanyExclusionList({
  body: {
    apiKey: process.env.FIBERAI_API_KEY,
    name: "Competitors",
    isOrganizationWide: true,
  },
});

// Add companies to the list
await addCompaniesToExclusionList({
  body: {
    apiKey: process.env.FIBERAI_API_KEY,
    listId: list.data.output.listId,
    companies: [
      { domain: "competitor1.com", linkedinUrl: null },
      { domain: "competitor2.com", linkedinUrl: null },
    ],
  },
});

// Create exclusion list from an existing audience
const audienceList = await createCompanyExclusionListFromAudience({
  body: {
    apiKey: process.env.FIBERAI_API_KEY,
    audienceId: "audience-123",
    name: "Existing Customers",
    isOrganizationWide: true,
  },
});

// View excluded companies
const excluded = await getExcludedCompaniesForExclusionList({
  body: {
    apiKey: process.env.FIBERAI_API_KEY,
    exclusionListId: list.data.output.listId,
    pageSize: 100,
  },
});

Search for local businesses on Google Maps.

import {
  googleMapsSearch,
  checkGoogleMapsResults,
  pollGoogleMapsResults,
} from "@fiberai/sdk";

// Start Google Maps search. `query` is the keywords only (no location info)
// and `strategy` is required — see below for the available strategies.
const search = await googleMapsSearch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    query: "coffee shops",
    maxResults: 100,
    strategy: {
      // Options:
      //   { strategy: 'whole-usa' }
      //   { strategy: 'specific-areas', unionAll: [{ regionType: 'circle', center: {latitude, longitude}, radiusMiles }] }
      //   { strategy: 'world-cities', countriesAndRegions: { unionAll: ['USA', 'GBR', ...] } }
      strategy: "specific-areas",
      unionAll: [
        {
          regionType: "circle",
          center: { latitude: 37.7749, longitude: -122.4194 },
          radiusMiles: 10,
        },
      ],
    },
  },
});

const searchID = search.data!.output.searchID;

// Check search progress.
const progress = await checkGoogleMapsResults({
  body: { apiKey: process.env.FIBERAI_API_KEY!, searchID },
});

console.log(`Progress: ${progress.data?.output.percentageCompleted}%`);

// Poll for results once complete.
if (progress.data?.output.status === "COMPLETED") {
  const results = await pollGoogleMapsResults({
    body: {
      apiKey: process.env.FIBERAI_API_KEY!,
      searchID,
      pageSize: 50,
    },
  });

  results.data?.output.results.forEach((place) => {
    console.log(`${place.name} — ${place.address}`);
    console.log(`Rating: ${place.rating}, Reviews: ${place.numReviews}`);
    console.log(`Website: ${place.website}`);
  });
}

AI-Powered Research

Use AI agents for intelligent company research and domain lookup.

import { domainLookupTrigger, domainLookupPolling } from "@fiberai/sdk";

// Trigger domain lookup. `overAllContext` is required and helps the agent
// disambiguate similar names; `companyInfo` is an array of objects (not
// a list of bare strings).
const lookup = await domainLookupTrigger({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    overAllContext: "YC startups in the US",
    companyInfo: [
      { name: "Acme Corp" },
      { name: "Globex", country: "USA" },
      { name: "Initech" },
    ],
  },
});

const domainAgentRunId = lookup.data!.output.domainAgentRunId;

// Poll for results.
let lookupDone = false;
while (!lookupDone) {
  await new Promise((resolve) => setTimeout(resolve, 3000));

  const results = await domainLookupPolling({
    body: {
      apiKey: process.env.FIBERAI_API_KEY!,
      domainAgentRunId,
      pageSize: 10,
    },
  });

  lookupDone = results.data?.output.status === "DONE";

  if (lookupDone) {
    results.data?.output.data.forEach((company) => {
      console.log(`${company.companyName}: ${company.bestDomain}`);
      console.log(`Confidence: ${company.confidence}/10`);
      console.log(`Rationale: ${company.rationale}`);
    });
  }
}

Advanced Usage

Configuring the built-in client

The SDK exports a pre-configured client that already points at https://api.fiber.ai. Every operation uses it by default — you do not need to call createClient to make requests.

If you need to customize headers, swap in a custom fetch, or add request/response interceptors, mutate the shared instance:

import { client } from "@fiberai/sdk";

// One-time configuration: extra headers, a custom fetch, etc.
client.setConfig({
  headers: { "X-Trace-Id": "my-app/1.0.0" },
});

// Log every outgoing request — handy as a poor man's debug mode.
client.interceptors.request.use((request) => {
  console.log(`[fiberai] ${request.method} ${request.url}`);
  return request;
});

createClient from the package is for the rare case where you want a second, independent client (e.g. multi-tenant apps). Pass it via the client: option on any operation.

Pagination Helper

import type { CompanySearchData, CompanySearchResponse } from "@fiberai/sdk";

async function* paginateCompanies(
  initial: CompanySearchData,
): AsyncGenerator<
  NonNullable<CompanySearchResponse["data"]>["output"]["data"]
> {
  let cursor: string | null | undefined = initial.body.cursor ?? null;

  do {
    const result = await companySearch({
      ...initial,
      body: { ...initial.body, cursor },
    });

    if (!result.data) break;
    yield result.data.output.data;
    cursor = result.data.output.nextCursor;
  } while (cursor);
}

// Usage
for await (const companies of paginateCompanies({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    searchParams: {
      /* ... */
    },
    pageSize: 100,
  },
})) {
  console.log(`Processing batch of ${companies.length} companies`);
  // Process batch
}

Utility Endpoints

import {
  getRegions,
  getLanguages,
  getTimeZones,
  getIndustries,
  getTags,
  getNaicsCodes,
  getAccelerators,
} from "@fiberai/sdk";

// Get available regions for filtering
const regions = await getRegions({
  query: { apiKey: process.env.FIBERAI_API_KEY },
});

// Get available industries
const industries = await getIndustries({
  query: { apiKey: process.env.FIBERAI_API_KEY },
});

// Get profile and company tags
const tags = await getTags({
  query: { apiKey: process.env.FIBERAI_API_KEY },
});

Error Handling

Standard Error Handling

By default, every operation returns { data, error, response }. Branch on the HTTP status from response.status rather than string-matching the error body — error payloads are not guaranteed to contain a parseable message for every failure mode.

import { companySearch } from "@fiberai/sdk";

const result = await companySearch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    searchParams: {
      /* ... */
    },
  },
});

if (result.error) {
  switch (result.response.status) {
    case 400:
      console.error("Bad request:", result.error);
      break;
    case 401:
      console.error("Invalid API key");
      break;
    case 402:
      // 402 errors carry an `outOfCreditsAlert` with a top-up link.
      console.error("Insufficient credits:", result.error);
      break;
    case 429:
      console.error("Rate limit exceeded — back off and retry");
      break;
    default:
      console.error(
        `Request failed (${result.response.status}):`,
        result.error,
      );
  }
} else {
  console.log("Success:", result.data?.output);
  console.log("Charged:", result.data?.chargeInfo);
}

Throwing on Errors

try {
  const result = await companySearch({
    body: {
      apiKey: process.env.FIBERAI_API_KEY!,
      searchParams: {
        /* ... */
      },
    },
    throwOnError: true,
  });

  // result.data is guaranteed to exist when throwOnError is true.
  console.log(result.data.output);
} catch (error) {
  console.error("Request failed:", error);
}

Common HTTP Error Codes

CodeMeaningSolution
400Bad RequestCheck your request parameters
401UnauthorizedVerify your API key is valid
402Payment RequiredInsufficient credits - top up your account
403ForbiddenYou don't have access to this resource
404Not FoundResource doesn't exist
429Too Many RequestsRate limit exceeded - slow down requests
500Internal Server ErrorContact support

TypeScript Support

All SDK methods are fully typed with TypeScript.

import { companySearch } from "@fiberai/sdk";

// SDK functions return `{ data, error, response }`. Annotate the awaited call
// with `Awaited<ReturnType<typeof fn>>` — the exported `<Op>Response` /
// `<Op>Errors` types describe the inner body union, NOT the wrapper.
const result: Awaited<ReturnType<typeof companySearch>> = await companySearch({
  body: {
    apiKey: process.env.FIBERAI_API_KEY!,
    searchParams: {
      industriesV2: { anyOf: ["Software"] },
      employeeCountV2: {
        lowerBoundExclusive: 50,
        upperBoundInclusive: 1000,
      },
    },
    pageSize: 25,
  },
});

if (result.data) {
  console.log(`${result.data.output.data.length} companies`);
  console.log(result.data.chargeInfo);
}

// Need a name for the request shape (e.g. building a request in one place,
// passing it elsewhere)? Derive it from the function — the bare `<Op>Data`
// export carries an internal `url` literal and is not meant to be
// hand-constructed.
type CompanySearchArgs = Parameters<typeof companySearch>[0];

Naming convention: every operation foo ships companion types: FooResponse (200 body union) and FooErrors (4xx/5xx body union). Use Parameters<typeof foo>[0] for input args and Awaited<ReturnType<typeof foo>> for the result envelope. The same applies to peopleSearch, syncQuickContactReveal, etc.

Runtime Validation with Zod

Every request and response shape is also published as a Zod schema, generated from the same OpenAPI spec as the TypeScript types. They live behind the dedicated @fiberai/sdk/zod subpath so apps that don't need runtime validation pay zero bundle cost — the main entry stays under 50 KB while the Zod bundle (~3–6 MB depending on the API surface) is only loaded if you import it.

import { zPeopleSearchData, zCompanySearchData } from "@fiberai/sdk/zod";
import { peopleSearch } from "@fiberai/sdk";

const rawInput: unknown = JSON.parse(req.body);

const parsed: ReturnType<typeof zPeopleSearchData.parse> =
  zPeopleSearchData.parse(rawInput);

const result: Awaited<ReturnType<typeof peopleSearch>> =
  await peopleSearch(parsed);

Use safeParse if you want to handle validation failures without throwing. Zod 4 ships top-level error helpers — use z.flattenError for form-friendly output or z.treeifyError for nested shapes:

import { z } from "zod";
import { zCompanySearchData } from "@fiberai/sdk/zod";

const parsed: ReturnType<typeof zCompanySearchData.safeParse> =
  zCompanySearchData.safeParse(req.body);

if (!parsed.success) {
  return res.status(400).json({ errors: z.flattenError(parsed.error) });
}

Naming convention: every TypeScript type Foo has a matching zFoo schema. So PeopleSearchData ↔ zPeopleSearchData, CompanySearchResponse ↔ zCompanySearchResponse, etc.

zod ships as a runtime dependency of @fiberai/sdk and is externalized from the bundle (so package managers dedupe with whatever Zod copy your app already has). If you don't import @fiberai/sdk/zod, your bundler tree-shakes the schemas out and you never pay for them.

Rate Limits & Credits

Rate Limits

Each endpoint has its own rate limit. Common limits:

  • Company/People Search: 180 requests/minute
  • Contact Enrichment: 120 requests/minute (single), 10 requests/minute (batch)
  • Live Enrichment: 60 requests/minute
  • Utility Endpoints: 10-50 requests/minute

Credit Costs

Pricing varies by plan and is configured per-organization. Don't hard-code costs into your app — every successful response carries a chargeInfo envelope alongside output that tells you exactly what was charged for that call:

const result = await peopleSearch({
  /* ... */
});

console.log(result.data?.chargeInfo);
// {
//   method: 'charged-now',          // 'charged-now' | 'charging-later' | 'charged-for-async-process' | 'free'
//   creditsCharged: 25,             // present when method !== 'free'
//   lowCreditAlert: null            // populated with a top-up URL when running low
// }

For a non-charging dry-run estimate of contact enrichment costs, use estimateEnrichmentCost. For the per-org pricing breakdown across operations, inspect getOrgCredits().data.output.creditsPerOperation.

Free Endpoints

The following endpoints never charge credits:

  • getOrgCredits — Check credit balance
  • getRegions, getLanguages, getTimeZones, getIndustries, getTags, getNaicsCodes, getAccelerators — Utility endpoints
  • All exclusion-list management endpoints

Check Your Credits

import { getOrgCredits } from "@fiberai/sdk";

const credits = await getOrgCredits({
  query: { apiKey: process.env.FIBERAI_API_KEY! },
});

console.log(`Available: ${credits.data?.output.available}`);
console.log(`Used: ${credits.data?.output.used}`);
console.log(`Max: ${credits.data?.output.max}`);
console.log(`Resets on: ${credits.data?.output.usagePeriodResetsOn}`);

Support

License

MIT


Made with ❤️ by Fiber AI

版本与发布记录

@fiberai/sdk 共发布 66 个版本,首次发布于 2026/01/24;过去 12 个月发布了 66 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.0.66latest2026/10/3114 天前
0.0.652026/10/2916 天前
0.0.642026/10/2817 天前
0.0.632026/10/2619 天前
0.0.622026/10/2322 天前
0.0.612026/10/1728 天前

关于 @fiberai/sdk 的常见问题

@fiberai/sdk 是什么?

Official TypeScript SDK for Fiber AI API

如何安装 @fiberai/sdk?

在项目目录运行 npm install @fiberai/sdk,或使用 pnpm add / yarn add / bun add。

@fiberai/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@fiberai/sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@fiberai/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@fiberai/sdk 可以商用吗?

@fiberai/sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@fiberai/sdk 的下载量有多少?

根据 npm 官方下载统计,@fiberai/sdk 在 2026/10/15 – 2026/11/13 这 30 天内被下载 2,159 次,日均约 72 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fiberai/sdk 还在维护吗?

最新版本 0.0.66 发布于 2026/10/31(14 天前);至今共发布 66 个版本,其中过去 12 个月发布了 66 个;首次发布于 2026/01/24。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。