@fhirfly-io/terminology
v0.14.0
Published
Official FHIRfly SDK for Node.js - Healthcare reference data APIs
Maintainers
Readme
@fhirfly-io/terminology
Official FHIRfly SDK for Node.js — typed access to healthcare reference data APIs.
Installation
npm install @fhirfly-io/terminologyQuick 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); // 1RxClass (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" });MS-DRG (Diagnosis Related Groups)
// 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).
Search
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
- Node.js 18+
- FHIRfly API key (Get one free)
License
MIT - see LICENSE for details.
