Keep your data fresh
Know when a dataset releases, what changed in it, and when a code, NDC, NPI or Medicare coverage document you rely on changes: poll the feeds or get signed webhooks.
| Plan | Every plan: release list. Builder: change feed. Pro: webhooks and the coverage change feed |
| Endpoints | /v1/datasets/{dataset}/releases, /v1/changes, /v1/coverage/changes, /v1/webhooks |
| Cost | None of these count as billable calls (the change feeds on the plans that include them) |
Use this when you cache answers or keep a local copy of a dataset: a code retired in the October ICD-10-CM release or an NDC that changed yesterday should never sit in your cache unnoticed.
Every plan: watch releases
curl https://api.healthcare.dev/v1/datasets/icd10cm/releases \
-H "Authorization: Bearer $HDEV_API_KEY" | jq '.data[0] | {version, published_at, added, changed, retired}'Each release says how many records it added, changed and retired. When version differs from
the one you cached, refresh. Every response's meta.data_version names the release it came
from, so you can also tag each cached answer with it.
Builder: page through what changed
Keep the last release you applied (its version), and for each newer release page through its
changes:
curl "https://api.healthcare.dev/v1/changes?dataset=icd10cm&version=fy2027" \
-H "Authorization: Bearer $HDEV_API_KEY"Each item has key, kind (added, changed or retired), data_version and
published_at, oldest first. Tracking the release version means a run that stops halfway can
apply the same release again from the start, and a release is never skipped or applied twice.
TypeScript
import { HealthcareDev } from "@healthcare.dev/sdk";
const hdev = new HealthcareDev();
let applied = "fy2026"; // the last release you applied: load it from your store
// Releases come newest first: take the ones after `applied`, then apply them oldest first.
const { data: releases } = await hdev.datasets.releases("icd10cm");
const i = releases.findIndex((r) => r.version === applied);
const newer = (i === -1 ? releases.slice(0, 1) : releases.slice(0, i)).reverse();
for (const release of newer) {
for await (const change of hdev.changes.iterate({
dataset: "icd10cm",
version: release.version,
})) {
// re-fetch change.key, or mark it retired, in your cache
console.log(change.kind, change.key);
}
applied = release.version; // save it now
}Python
from healthcare_dev import HealthcareDev
hdev = HealthcareDev()
applied = "fy2026" # the last release you applied: load it from your store
releases = hdev.datasets.releases("icd10cm")["data"] # newest first
versions = [r["version"] for r in releases]
newer = list(reversed(versions[: versions.index(applied)])) if applied in versions else versions[:1]
for version in newer:
for change in hdev.changes.iterate(dataset="icd10cm", version=version):
print(change["kind"], change["key"]) # re-fetch or retire it in your cache
applied = version # save it nowIf the release you stored isn't listed (the first run, say), start from a full copy: page through
/v1/datasets/{dataset}/keys and look the records up, then store the newest version.
Retired records stay answerable with status: retired and, where the source names one,
replaced_by. Medicare coverage has its own feed of material document changes on Pro:
GET /v1/coverage/changes (Coverage changes).
Pro: get pushed, signed
Subscribe once and we POST each change to your endpoint. record.changed needs the codes, NDCs,
RxCUIs or NPIs you care about (up to 1,000); coverage.changed filters to procedure codes when
you list them.
curl -X POST https://api.healthcare.dev/v1/webhooks \
-H "Authorization: Bearer $HDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/healthcare-dev",
"events": ["dataset.released", "record.changed", "coverage.changed"],
"datasets": ["icd10cm", "hcpcs"],
"subjects": ["E11.9", "I10", "J1817", "11720"]
}'The response has secret (whsec_...), shown once: store it in your secret manager. Then verify
every delivery against the raw body before trusting it.
TypeScript
import { HealthcareDev, verifyWebhook, WebhookVerificationError } from "@healthcare.dev/sdk";
const hdev = new HealthcareDev();
const { data } = await hdev.webhooks.create({
url: "https://example.com/hooks/healthcare-dev",
events: ["dataset.released", "record.changed", "coverage.changed"],
datasets: ["icd10cm", "hcpcs"],
subjects: ["E11.9", "I10", "J1817", "11720"],
});
console.log(data.id); // store data.secret now
// Your endpoint
export async function POST(req: Request) {
const body = await req.text(); // the raw body, not re-serialized JSON
try {
const event = await verifyWebhook(process.env.HDEV_WEBHOOK_SECRET!, req.headers, body);
// deduplicate by event.id, answer fast, do the work after
console.log(event.type, event.id);
return new Response(null, { status: 204 });
} catch (err) {
if (err instanceof WebhookVerificationError) return new Response(null, { status: 400 });
throw err;
}
}Python
import os
from healthcare_dev import HealthcareDev, WebhookVerificationError, verify_webhook
hdev = HealthcareDev()
hook = hdev.webhooks.create({
"url": "https://example.com/hooks/healthcare-dev",
"events": ["dataset.released", "record.changed", "coverage.changed"],
"datasets": ["icd10cm", "hcpcs"],
"subjects": ["E11.9", "I10", "J1817", "11720"],
})["data"]
print(hook["id"]) # store hook["secret"] now
# In your endpoint (any framework): pass the headers and the raw body
def handle(headers, raw_body: bytes) -> int:
try:
event = verify_webhook(os.environ["HDEV_WEBHOOK_SECRET"], headers, raw_body)
except WebhookVerificationError:
return 400
print(event["type"], event["id"]) # deduplicate by id
return 204Deliveries are retried for about a day, can arrive more than once and out of order: deduplicate
by id and order by published_at (or detected_at for coverage). Details:
Webhooks.
Ask an agent
What changed in the latest ICD-10-CM release? List the retired codes with their replacements, and cite the release version.
The agent uses list_datasets and get_dataset_changes (Builder and up for the changes).
What it is not
A change says that a record we serve was added, changed or retired, not what it means for your claims, formulary or directory: re-read the record (and, for coverage, the linked CMS document) before acting on it. Datasets whose license keeps them out of the API produce no changes or webhook events.
Check MA internal criteria (preview)
Which services a Medicare Advantage plan covers with its own internal coverage criteria, as its public posting says, with links to the plan's documents. Preview: not available yet.
Ground an agent
Connect the MCP server, give the agent a system prompt that keeps it on the data, and cite meta in every answer, so it answers from current, versioned sources instead of memory.