JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 54
  • Score
    100M100P100Q74230F
  • License MIT

Official FHIRfly SDK for Node.js - Healthcare reference data APIs

Package Exports

  • @fhirfly-io/terminology

Readme

@fhirfly-io/terminology

Official FHIRfly SDK for Node.js — typed access to healthcare reference data APIs.

npm version License: MIT

Installation

npm install @fhirfly-io/terminology

Quick Start

import { Fhirfly } from "@fhirfly-io/terminology";

const client = new Fhirfly({ apiKey: "your-api-key" });

// Look up a drug by NDC
const ndc = await client.ndc.lookup("0069-0151-01");
console.log(ndc.data.brand_name); // "Lipitor"

// Look up a provider by NPI
const npi = await client.npi.lookup("1234567890");
console.log(npi.data.name);

Features

  • Full TypeScript support with comprehensive type definitions
  • 17 healthcare domains: NDC, NPI, RxNorm, LOINC, ICD-10, CVX, MVX, FDA Labels, SNOMED CT, UCUM, RxClass, HCPCS, MS-DRG, POS, J-Code/NDC Crosswalk, Connectivity, Claims
  • Search with full-text queries, filters, facets, and pagination
  • Batch lookups for efficient bulk operations
  • Response shapes: compact, standard, or full detail levels
  • Two auth modes: API key (simple) and OAuth2 client credentials (secure)
  • Automatic retries with exponential backoff
  • Detailed error types for proper error handling
  • Zero runtime dependencies

Authentication

API Key (Simple)

const client = new Fhirfly({
  apiKey: "ffly_sk_live_...",
  baseUrl: "https://api.fhirfly.io", // Optional, default shown
  timeout: 30000,              // Optional, request timeout in ms
  maxRetries: 3,               // Optional, retry attempts
  retryDelay: 1000,            // Optional, base retry delay in ms
});

OAuth2 Client Credentials (Secure)

const client = new Fhirfly({
  clientId: "ffly_client_...",
  clientSecret: "ffly_secret_...",
  scopes: ["ndc.read", "npi.read"], // Optional
  tokenUrl: "https://api.fhirfly.io/oauth2/token", // Optional, default shown
});

OAuth2 tokens are cached and automatically refreshed before expiry.

API Reference

NDC (National Drug Codes)

// Single lookup
const ndc = await client.ndc.lookup("0069-0151-01");

// With options
const ndc = await client.ndc.lookup("0069-0151-01", {
  shape: "full",           // "compact" | "standard" | "full"
  include: ["display"],    // Include pre-formatted display strings
});

// Batch lookup (up to 500 codes)
const results = await client.ndc.lookupMany([
  "0069-0151-01",
  "0069-0151-02",
]);

for (const item of results.results) {
  if (item.status === "ok") {
    console.log(item.data.brand_name);
  }
}

// Search
const results = await client.ndc.search({
  q: "advil",
  dosage_form: "TABLET",
  is_active: true,
});

Batch lookups return per-item results and never throw for individual misses. Each item has status: "ok" | "not_found" | "invalid".

NPI (National Provider Identifiers)

// Single lookup
const npi = await client.npi.lookup("1234567890");

// Batch lookup (up to 100)
const results = await client.npi.lookupMany(["1234567890", "0987654321"]);

// Search for providers
const results = await client.npi.search({
  q: "smith",
  specialty: "cardiology",
  state: "CA",
  entity_type: "individual",
});
console.log(`Found ${results.total} providers`);

RxNorm

// Look up by RxCUI
const rx = await client.rxnorm.lookup("213169");
console.log(rx.data.name); // "atorvastatin 10 MG Oral Tablet"

// Search for drugs
const results = await client.rxnorm.search({
  ingredient: "metformin",
  is_prescribable: true,
});

LOINC

// Look up lab code
const loinc = await client.loinc.lookup("2345-7");
console.log(loinc.data.display_name);

// Search
const results = await client.loinc.search({
  q: "glucose",
  class: "CHEM",
  system: "Bld",
});

ICD-10

The API auto-detects CM (diagnoses) vs PCS (procedures) based on code format.

// Diagnosis code (CM)
const diagnosis = await client.icd10.lookup("E11.9");
console.log(diagnosis.data.display); // "Type 2 diabetes mellitus without complications"

// Procedure code (PCS)
const procedure = await client.icd10.lookup("02HA0QZ");

// Batch lookup (mix of CM and PCS, up to 100)
const results = await client.icd10.lookupMany(["E11.9", "I10", "02HA0QZ"]);

// Search
const results = await client.icd10.search({
  q: "diabetes",
  code_system: "CM",
  billable: true,
});

CVX (Vaccine Codes)

const cvx = await client.cvx.lookup("208");
console.log(cvx.data.display);

// Search for COVID vaccines
const results = await client.cvx.search({
  is_covid_vaccine: true,
  status: "active",
});

MVX (Vaccine Manufacturers)

const mvx = await client.mvx.lookup("PFR");
console.log(mvx.data.manufacturer_name); // "Pfizer, Inc"

const results = await client.mvx.search({ q: "pfizer" });

FDA Labels

// Look up by Set ID, NDC, or RxCUI (auto-detected)
const label = await client.fdaLabels.lookup("0069-0151-01");

// With safety sections
const label = await client.fdaLabels.lookup("0069-0151-01", {
  bundle: "safety",
});

// With specific sections
const label = await client.fdaLabels.lookup("0069-0151-01", {
  sections: ["boxed_warning", "dosage_and_administration"],
});

// Batch (up to 50, metadata only)
const results = await client.fdaLabels.lookupMany(["0069-0151-01", "0002-1433-80"]);

// Search
const results = await client.fdaLabels.search({
  substance: "acetaminophen",
  product_type: "otc",
});

SNOMED CT (IPS)

Access to ~12,000 curated clinical concepts from the SNOMED CT IPS (International Patient Set), licensed under CC BY 4.0.

// Look up a concept
const concept = await client.snomed.lookup("73211009");
console.log(concept.data.preferred_term); // "Diabetes mellitus"

// Batch lookup (up to 100)
const results = await client.snomed.lookupMany(["73211009", "38341003"]);

// Search by category
const results = await client.snomed.search({
  q: "diabetes",
  ips_category: "condition",
});

// List all IPS categories
const categories = await client.snomed.categories();

// Reverse mappings (what ICD-10/RxNorm/NDC codes map to this concept?)
const mappings = await client.snomed.mappings("73211009");

UCUM (Units of Measure)

Unified Code for Units of Measure — lookup, validate, search, and convert healthcare units.

// Look up a UCUM unit
const unit = await client.ucum.lookup("mg");
console.log(unit.data.display); // "milligram"

// Validate a UCUM expression
const validation = await client.ucum.validate("mg/dL");
console.log(validation.data.is_valid); // true

// Search for units
const results = await client.ucum.search({ q: "milligram" });

// Convert between units
const conversion = await client.ucum.convert({
  value: 1000,
  from: "mg",
  to: "g",
});
console.log(conversion.data.result); // 1

RxClass (Drug Classifications)

RxClass drug classification hierarchy from NLM — look up drug classes, search, and find class members.

// Look up a drug class
const rxclass = await client.rxclass.lookup("N0000175503");
console.log(rxclass.data.class_name); // "HMG-CoA Reductase Inhibitors"

// Search for drug classes
const results = await client.rxclass.search({
  q: "statin",
  class_type: "EPC",
});

// Get members of a drug class (drugs belonging to the class)
const members = await client.rxclass.members("N0000175503");
for (const drug of members.data.members) {
  console.log(`${drug.rxcui}: ${drug.name}`);
}

HCPCS Level II

// Look up a procedure code
const hcpcs = await client.hcpcs.lookup("A0425");
console.log(hcpcs.data.short_description); // "Ground mileage, per statute mile"

// Look up a modifier
const mod = await client.hcpcs.lookupModifier("25");
console.log(mod.data.short_description);

// Batch lookup (up to 100)
const results = await client.hcpcs.lookupMany(["A0425", "E0100"]);

// Search
const results = await client.hcpcs.search({ q: "ambulance" });
// Look up a DRG code
const drg = await client.msdrg.lookup("470");
console.log(drg.data.title); // "Major Joint Replacement..."

// Search
const results = await client.msdrg.search({
  q: "cardiac",
  type: "SURG",
});

POS (Place of Service)

// Look up a POS code
const pos = await client.pos.lookup("11");
console.log(pos.data.name); // "Office"

// List all POS codes (~52 total)
const all = await client.pos.list();

J-Code/NDC Crosswalk

// J-code → NDCs (which NDCs map to this J-code?)
const jcode = await client.jcode.byHcpcs("J9035");
console.log(`${jcode.data.ndc_count} NDCs for ${jcode.data.hcpcs_description}`);

// NDC → J-codes (which J-codes cover this NDC?)
const reverse = await client.jcode.byNdc("00004110002");
for (const entry of reverse.data.hcpcs_codes) {
  console.log(`${entry.hcpcs_code}: ${entry.hcpcs_description}`);
}

Connectivity Intelligence

Discover how to reach a provider's organization electronically — FHIR endpoints, Direct addresses, and more.

// Look up connectivity options for a provider
const conn = await client.connectivity.lookup("1234567890");

console.log(conn.provider_summary.name);

for (const target of conn.connectivity_targets) {
  console.log(`${target.name} (${target.type})`);
  for (const ep of target.endpoints) {
    console.log(`  ${ep.type}: ${ep.url} [${ep.status}]`);
  }
}

Claims Intelligence

CMS claims editing and payment data. Requires the claims.read scope.

// NCCI PTP: Can these codes be billed together?
const ncci = await client.claims.validateNcci("99213", "99214");
console.log(ncci.data.can_bill_together); // true/false
console.log(ncci.data.summary);

// MUE: Maximum units for a code
const mue = await client.claims.lookupMue("99213");
for (const limit of mue.data.limits) {
  console.log(`${limit.service_type}: max ${limit.mue_value} units`);
}

// Batch MUE (up to 100 codes)
const mueResults = await client.claims.lookupMueMany(["99213", "99214"]);

// PFS/RVU: Fee schedule and relative value units
const pfs = await client.claims.lookupPfs("99213");
console.log(`Work RVU: ${pfs.data.rvu.work}`);
console.log(`Non-facility payment: $${pfs.data.calculated_payment.non_facility}`);

// Batch PFS (up to 100 codes)
const pfsResults = await client.claims.lookupPfsMany(["99213", "99214", "99215"]);

// LCD/NCD Coverage determination
const coverage = await client.claims.checkCoverage("99213");
console.log(`${coverage.data.policies_found} coverage policies found`);

Response Shapes

All lookup and search methods accept a shape option to control response detail:

Shape Description
compact Minimal fields for quick lookups and autocomplete
standard Balanced detail (default for REST)
full Complete data with provenance (default for MCP/agents)
const ndc = await client.ndc.lookup("0069-0151-01", { shape: "full" });

Exceptions: SNOMED always returns full data (no shapes). FDA Labels lookup uses a metadata + sections model instead of shapes; search uses shapes. UCUM validate and convert return fixed result shapes (no shape parameter).

All endpoints except Connectivity and RxClass members support full-text search with filters, facets, and pagination:

const results = await client.ndc.search(
  { q: "advil", is_active: true },        // Search params
  { shape: "compact", limit: 50, page: 1 } // Options
);

console.log(`${results.total} results, page ${results.page}`);
console.log(results.facets); // Facet counts for filtering

for (const item of results.items) {
  console.log(item.name);
}

if (results.has_more) {
  // Fetch next page...
}

Error Handling

The SDK provides typed errors for different failure scenarios:

import {
  Fhirfly,
  NotFoundError,
  RateLimitError,
  AuthenticationError
} from "@fhirfly-io/terminology";

try {
  const ndc = await client.ndc.lookup("invalid-code");
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log(`Code not found: ${error.code_value}`);
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after: ${error.retryAfter}s`);
  } else if (error instanceof AuthenticationError) {
    console.log("Invalid API key");
  }
}

Error Types

Error Status Description
AuthenticationError 401 Invalid or missing API key
NotFoundError 404 Code/identifier not found
ValidationError 400 Invalid request parameters
RateLimitError 429 Rate limit exceeded
QuotaExceededError 429 Monthly quota exceeded
ServerError 5xx Server-side error
NetworkError - Network connectivity issue
TimeoutError - Request timed out

RateLimitError indicates short-term throttling; QuotaExceededError indicates monthly plan limits.

Requirements

License

MIT - see LICENSE for details.