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

firmaradar

v0.1.0

Published

Official TypeScript SDK for Firmaradar — enrichment platform for Norwegian company intelligence (KYC, AML, credit, ownership and risk).

Readme

Firmaradar TypeScript SDK

Official TypeScript/JavaScript SDK for Firmaradar — the enrichment platform for Norwegian company intelligence. Firmaradar fuses data from multiple authoritative sources (Brønnøysundregistrene, Skatteetaten, foreign PEP/sanctions registers, public-grants registries) and adds proprietary enrichment on top — so a single call returns a decision-ready view for KYC, AML, credit, ownership and risk workflows, not a raw registry record.

The SDK is a thin, fully typed client over the Firmaradar REST API, built on the platform-native fetch API with zero runtime dependencies — it runs in Node.js (≥ 18.17), browsers, Deno, Bun, Cloudflare Workers and Vercel Edge. Optional LangChain.js / Vercel AI SDK tool wrappers plug the same operations into AI-agent stacks.

Installation

npm install firmaradar                    # core SDK
npm install firmaradar @langchain/core    # + LangChain.js tool wrappers
npm install firmaradar ai                 # + Vercel AI SDK tool wrappers

From source (this repo):

npm install ./sdk/typescript

Requires Node.js 18.17+ (or any runtime with WHATWG fetch).

Authentication

The SDK authenticates with a Firmaradar API key, sent as the X-API-Key header. Pass it explicitly or set the FIRMARADAR_API_KEY environment variable:

import { Firmaradar } from "firmaradar";

const fr = new Firmaradar({ apiKey: "fr_..." }); // or: export FIRMARADAR_API_KEY=fr_...

API keys are managed on your Firmaradar account at firmaradar.no.

Quickstart

import { Firmaradar } from "firmaradar";
const fr = new Firmaradar(); // reads FIRMARADAR_API_KEY
console.log((await fr.companies.get("923609016")).navn);

Going deeper:

// Find a company, then pull its decision-ready profile
const page = await fr.companies.search("Equinor");
const orgnr = page.items[0].orgnr;

const company = await fr.companies.get(orgnr, { fields: ["group", "owners", "grants"] });
console.log(company.navn, "-", company.summary);

// Ownership tree towards ultimate beneficial owners
const tree = await fr.companies.ownership(orgnr, { direction: "up", depth: 5 });
for (const owner of tree.owners) console.log(owner.navn, owner.eierandel_prosent);

// Transparent risk score with component breakdown
const score = await fr.risk.score(orgnr);
console.log(score.score, score.level, score.components);

Every operation returns a Promise — batch with Promise.all:

const companies = await Promise.all(
  ["923609016", "914594685"].map((orgnr) => fr.companies.get(orgnr)),
);

Async AML reports (submit → poll)

AML screening requires a signed DPA with Firmaradar. Calling startReport confirms the screening and records the purpose in the audit trail (60-month retention per Hvitvaskingsloven §35):

const job = await fr.aml.startReport("923609016", { purpose: "kyc_onboarding" });

let status = await fr.aml.getReport(job.rapport_id);
while (status.status === "pending" || status.status === "running") {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  status = await fr.aml.getReport(job.rapport_id);
}

if (status.status === "done") console.log(status.score, status.level, status.pdf_url);

Operations

| Namespace | Method | What it returns | |---|---|---| | companies | search(q?, options?) | Paginated company search | | companies | get(orgnr, options?) | Full enriched company profile | | companies | roles(orgnr, options?) | BRREG roles (board, CEO, signature, auditor) | | companies | ownership(orgnr, options?) | Ownership tree (down / up-UBO / both) | | companies | financials(orgnr, options?) | Financial history per accounting year | | companies | announcements(orgnr) | BRREG announcements (normalized categories) | | risk | score(orgnr) | Risk score 0-100 + level + components | | risk | checkFiv(orgnr) | Foretak-i-vanskeligheter (NUES a-e) assessment | | aml | startReport(orgnr, options?) | Start async AML report (DPA required) | | aml | getReport(reportId) | Poll AML report status/result | | monitoring | add(orgnr, options?) | Add company to monitoring | | monitoring | remove(orgnr) | Remove company from monitoring (idempotent) | | monitoring | list() | List monitored companies |

All responses are typed (Company, RiskScore, AmlReportStatus, ...) with wire-format field names — the same names you see on every other Firmaradar surface (REST, MCP, n8n, Make, Power Automate). Responses tolerate additive API changes: unknown fields are kept, never fatal.

Error handling

Non-2xx responses throw typed errors mapped from the API's error contract (HTTP status + stable error_code):

import {
  AuthenticationError,     // 401 — bad/expired API key
  PermissionDeniedError,   // 403 — not authorized / compliance gate / DPA missing
  NotFoundError,           // 404 — unknown orgnr / report id
  ConflictError,           // 409 — e.g. company already monitored
  ValidationError,         // 400/422 — malformed parameters
  QuotaExceededError,      // 402/429 — quota or rate limit (see .retryAfterS)
  ServiceUnavailableError, // 5xx — transient; retry later
  APIConnectionError,      // network unreachable (APITimeoutError for timeouts)
} from "firmaradar";

try {
  await fr.monitoring.add("923609016");
} catch (err) {
  if (err instanceof ConflictError) {
    // already monitored — fine
  } else if (err instanceof QuotaExceededError) {
    const retryInS = err.retryAfterS ?? 60;
  } else if (err instanceof PermissionDeniedError) {
    console.log(err.statusCode, err.errorCode, err.message); // e.g. 403 EXTENSION_NOT_ACTIVE
  } else {
    throw err;
  }
}

Malformed organisation numbers are rejected client-side (RangeError) before they cost an API call; "923 609 016"-style formatting is normalized automatically.

LangChain.js integration

Requires the optional peer dependency @langchain/core (≥ 0.3.44):

import { getTools } from "firmaradar/langchain";

const tools = getTools({ apiKey: "fr_..." }); // 13 structured tools
// -> pass to createAgent / bindTools / createToolCallingAgent / ...

Vercel AI SDK integration

Requires the optional peer dependency ai (v5 or newer):

import { generateText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { getTools } from "firmaradar/ai";

const result = await generateText({
  model: anthropic("claude-sonnet-4-5"),
  tools: getTools({ apiKey: "fr_..." }),
  prompt: "Gjør due diligence på orgnr 923609016",
});

Tool names, descriptions and argument schemas are shared between both integrations and mirror the Firmaradar Python SDK and the Firmaradar MCP server — the same operations behave identically whether an agent reaches them over MCP, LangChain or the AI SDK. The framework-agnostic catalog (TOOL_SPECS, invokeTool, executeTool) is exported from the core entry point, so any other agent framework can be wired up without extra dependencies.

Note: the AI SDK's own type definitions reference the json-schema package without shipping its types. If you compile with skipLibCheck: false, add npm install -D @types/json-schema (this applies to every ai consumer, not just this SDK).

Configuration

| Setting | Option | Environment variable | Default | |---|---|---|---| | API key | apiKey | FIRMARADAR_API_KEY | — (required) | | Base URL | baseUrl | FIRMARADAR_BASE_URL | https://firmaradar.no | | Timeout | timeoutMs (milliseconds) | FIRMARADAR_TIMEOUT_S (seconds) | 30 s | | Transport | fetch | — | global fetch |

The environment variables are shared with the Firmaradar Python SDK, so one configuration serves both.

Development

cd sdk/typescript
npm install
npm test            # vitest — no network, no API key (mocked fetch)
npm run typecheck   # tsc --strict
npm run build       # dual ESM (dist/esm) + CJS (dist/cjs) via tsc

From the repo root: npm --prefix sdk/typescript test.

License

Apache-2.0 — © Firmaradar AS.