Drug safety status
For an NDC: the RxNorm concept, whether FDA lists a current shortage, any recall FDA hasn't terminated, and the label's boxed warning, each with its source and release.
| Plan | Free for each lookup. Pro for the one-call answer with J-codes, ASP and NADAC (Joined answers) |
| Datasets | NDC Directory, RxNorm, FDA drug shortages, FDA drug recalls, FDA drug labels |
| Calls per answer | 4 on Free (NDC, shortages, recalls, labels; a fifth for the label text), 1 on Pro |
Any NDC format works: a product NDC (0003-0894), a package NDC in any 10-digit layout
(0003-0894-21) or 11 digits (00003089421).
Free: one lookup per dataset
NDC=0003-0894-21
H="Authorization: Bearer $HDEV_API_KEY"
# 1. The FDA product and its RxNorm concepts
curl -s "https://api.healthcare.dev/v1/drugs/ndc/$NDC" -H "$H" | jq '.data | {brand_name, generic_name, rxnorm}'
# 2. Current FDA shortage list entries for the product
curl -s "https://api.healthcare.dev/v1/drugs/shortages?ndc=$NDC&status=current" -H "$H" | jq '[.data[] | {presentation, availability, update_date}]'
# 3. FDA recalls of the product FDA hasn't terminated (ongoing, then completed)
curl -s "https://api.healthcare.dev/v1/drugs/recalls?ndc=$NDC&status=ongoing" -H "$H" | jq '[.data[] | {recall_number, classification, report_date}]'
curl -s "https://api.healthcare.dev/v1/drugs/recalls?ndc=$NDC&status=completed" -H "$H" | jq '[.data[] | {recall_number, classification, report_date}]'
# 4. The current label, then its boxed warning
SET_ID=$(curl -s "https://api.healthcare.dev/v1/drugs/labels?ndc=$NDC" -H "$H" | jq -r '.data[0].set_id')
curl -s "https://api.healthcare.dev/v1/drugs/labels/$SET_ID?sections=boxed_warning" -H "$H" | jq '.data | {title, effective_date, sections, url}'Filtering by status leaves only what you need to check. Lists are paged, newest first: follow
links.next when there are more (the SDKs' iterate* helpers do). An empty shortage or recall list is an answer: FDA lists none for the product. It is not a
statement that the product is safe.
TypeScript
import { HealthcareDev } from "@healthcare.dev/sdk";
const hdev = new HealthcareDev();
const ndc = "0003-0894-21";
const all = async <T>(items: AsyncIterable<T>) => {
const out: T[] = [];
for await (const item of items) out.push(item);
return out;
};
const [product, shortages, recalls, labels] = await Promise.all([
hdev.drugs.ndc(ndc),
all(hdev.drugs.iterateShortages({ ndc, status: "current" })),
all(hdev.drugs.iterateRecalls({ ndc })), // every page
hdev.drugs.labels({ ndc }),
]);
const label = labels.data[0]
? await hdev.drugs.label(labels.data[0].set_id, { sections: ["boxed_warning"] })
: undefined;
console.log({
rxcuis: product.data.rxnorm.map((c) => c.rxcui),
current_shortage: shortages.length > 0,
open_recalls: recalls.filter((r) => r.status !== "terminated").map((r) => r.recall_number),
boxed_warning: label?.data.sections.find((s) => s.key === "boxed_warning")?.text ?? null,
label_url: label?.data.url,
});Python
from healthcare_dev import HealthcareDev
hdev = HealthcareDev()
ndc = "0003-0894-21"
product = hdev.drugs.ndc(ndc)["data"]
shortages = list(hdev.drugs.iterate_shortages(ndc=ndc, status="current"))
recalls = list(hdev.drugs.iterate_recalls(ndc=ndc)) # every page
labels = hdev.drugs.labels(ndc=ndc)["data"]
label = hdev.drugs.label(labels[0]["set_id"], sections=["boxed_warning"])["data"] if labels else None
print([c["rxcui"] for c in product["rxnorm"]])
print(len(shortages) > 0)
print([r["recall_number"] for r in recalls if r["status"] != "terminated"])
print(label and label["url"])Pro: one call
GET /v1/drugs/ndc/{ndc}/full joins the same datasets, plus the J-codes and Medicare Part B
payment limit (ASP) and the NADAC rate, in one billed call. Each component says whether it has
an answer, and why not.
curl "https://api.healthcare.dev/v1/drugs/ndc/0003-0894-21/full?view=compact" \
-H "Authorization: Bearer $HDEV_API_KEY"{
"data": {
"ndc": "00003089421",
"product_ndc": "0003-0894",
"rxcuis": ["..."],
"hcpcs_codes": [],
"label_set_ids": ["..."],
"flags": { "active_shortage": false, "open_recall": false, "boxed_warning": true },
"missing": [{ "component": "asp", "status": "not_listed", "reason": "..." }]
}
}const { data } = await hdev.drugs.full("0003-0894-21", { view: "compact" });
console.log(data.flags, data.missing);full = hdev.drugs.full("0003-0894-21", view="compact")["data"]
print(full["flags"], full["missing"])Ask an agent
Is NDC 0003-0894-21 in shortage or under an open FDA recall, and does its label have a boxed warning? Give the RxNorm concept too, and cite each source's data version.
The agent uses map_ndc_to_rxnorm, check_drug_shortages, check_drug_recalls and
get_drug_label, or get_drug_full on Pro.
Read the answer
- Recalls:
statusisongoing,completedorterminated; onlyterminatedrecalls are closed.classificationIis the most serious hazard class. On Pro,open_recallis true for any recall FDA hasn't terminated, however old. - Shortages:
statusiscurrent,resolvedorto_be_discontinued. Entries are per presentation; with a package NDC,fullmatches at the package level where FDA names the package. - Flags of
null(Pro) mean the data to answer isn't available, neverfalse.missinglists every component without an answer, with its reason. - Label text is the FDA label, verbatim. Show NLM's credit line (
meta.license_terms) and the label's version and date, and link to DailyMed (url) for the full label.
What it is not
Reference data, not clinical advice. No shortage or recall listed means FDA lists none, not that a product is safe or available. Dosing and interactions are out of scope: read the label.
Check Medicare coverage for a code and diagnosis
Does a Medicare local coverage document list this diagnosis as supporting this procedure code in this state? With how the answer was reached and the CMS page to check.
Compare payers' prior authorization metrics
Approval, denial, appeal and turnaround rates for prior authorization, as each health plan posts them every year, side by side and compared like with like.