RAG snapshots
Whole datasets as citable text chunks with precomputed vectors, versioned per release, for your own retrieval index (Team).
A RAG snapshot is one release of a dataset as files you load into your own retrieval index: every active record as a short text chunk with a citation, a precomputed vector per chunk, the dataset's license and a manifest with each file's size and SHA-256. A snapshot is built each time a release publishes, and the newest three per dataset stay available. Snapshots are on the Team plan (see Plans) and never count as billable calls.
Snapshots cover ICD-10-CM, ICD-10-PCS, HCPCS Level II, the NDC Directory and RxNorm: the datasets
that are public and whose terms allow copies. Licensed data (taxonomy names) and derived answers
(Medicare coverage support) are lookups only: asking for their snapshots returns 403 forbidden
with the reason. CPT and CDT descriptors are never included.
Download one
# Every snapshot of a dataset, newest first, with its manifest
curl https://api.healthcare.dev/v1/datasets/icd10cm/snapshots \
-H "Authorization: Bearer $HDEV_API_KEY"
# The newest one (or a release, e.g. /snapshots/fy2027), with a signed URL per file
curl https://api.healthcare.dev/v1/datasets/icd10cm/snapshots/latest \
-H "Authorization: Bearer $HDEV_API_KEY"data.downloads has one URL per file. Each works for 15 minutes (data.expires_at) without an API
key; ask again for fresh ones. The SDKs have client.datasets.snapshots(dataset) and
client.datasets.snapshot(dataset, version = "latest").
Files
| File | What it holds |
|---|---|
chunks.jsonl.gz | One JSON object per line, gzip-compressed: a chunk per active record with text. |
embeddings.f32 | The vectors: rows x dims float32, little-endian, row-major, no header. |
LICENSE.txt | What you may do with the data and the attribution it needs, from the source terms. |
manifest.json | Counts, the embedding format, the license and each other file's size and SHA-256. |
Line i of the chunks file (counting from 0) goes with row i of the vectors file; each chunk also
carries its row. A chunk:
{
"id": "icd10cm:E1122",
"row": 1,
"dataset": "icd10cm",
"version": "fy2027",
"key": "E1122",
"title": "ICD-10-CM E11.22",
"text": "Type 2 diabetes mellitus with diabetic chronic kidney disease",
"text_sha256": "…",
"status": "active",
"citation": {
"source": "cms-icd10",
"data_version": "fy2027",
"retrieved_at": "2026-10-25T12:00:00.000Z",
"license": "Public domain (CMS / CDC NCHS)",
"license_terms": { "display": "…", "attribution": null, "url": "…" },
"source_url": "https://www.cms.gov/medicare/coding-billing/icd-10-codes",
"url": "https://api.healthcare.dev/v1/codes/icd10cm/E1122"
}
}idis stable across releases: the same record keeps it.text_sha256changes only when the text does, and so does the vector, so you can update an index by re-embedding nothing and replacing only chunks whose hash changed.textis the record in plain words, exactly what the vector encodes. Codes and ids are intitleandkey.citationhas the same fields as a response'smeta, plusurl, the record in the API.retrieved_atis when the snapshot was built. Showlicense_terms.attributionwhere your product shows the data.
The manifest's embedding describes the vectors: dims floats each, unit length (so cosine
similarity is the dot product), and an opaque id. Vectors with the same id are comparable across
snapshots and datasets; when the id changes, reload every vector. To rank records against a
question in the same space, use search by meaning; or embed the chunks' text with a
model of your own.
Verify the files
Check every file against the manifest before using it. The hashes are of the files as downloaded, before decompressing.
sha256sum chunks.jsonl.gz embeddings.f32 LICENSE.txt
jq -r '.files[] | "\(.sha256) \(.path)"' manifest.json | sha256sum -c -Load the vectors
TypeScript (Node):
import { readFileSync } from "node:fs";
import { gunzipSync } from "node:zlib";
const manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
const { dims, rows } = manifest.embedding;
const chunks = gunzipSync(readFileSync("chunks.jsonl.gz"))
.toString("utf8")
.trim()
.split("\n")
.map((line) => JSON.parse(line));
const raw = readFileSync("embeddings.f32");
// Little-endian float32: on little-endian machines (x86, ARM) a view needs no copy.
const all = new Float32Array(raw.buffer, raw.byteOffset, rows * dims);
const vector = (row: number) => all.subarray(row * dims, (row + 1) * dims);
// Nearest neighbours of a chunk, by dot product (vectors are unit length).
const dot = (a: Float32Array, b: Float32Array) => a.reduce((s, x, i) => s + x * b[i]!, 0);
const q = vector(chunks[0].row);
const nearest = chunks
.map((c) => ({ c, score: dot(q, vector(c.row)) }))
.sort((a, b) => b.score - a.score)
.slice(0, 5);Python:
import gzip, json
import numpy as np
manifest = json.load(open("manifest.json"))
dims, rows = manifest["embedding"]["dims"], manifest["embedding"]["rows"]
with gzip.open("chunks.jsonl.gz", "rt", encoding="utf-8") as f:
chunks = [json.loads(line) for line in f]
vectors = np.fromfile("embeddings.f32", dtype="<f4").reshape(rows, dims)
# Nearest neighbours of a chunk (unit vectors: dot product = cosine similarity)
scores = vectors @ vectors[chunks[0]["row"]]
for i in np.argsort(-scores)[:5]:
print(chunks[i]["title"], chunks[i]["text"])np.memmap("embeddings.f32", dtype="<f4", mode="r", shape=(rows, dims)) maps the larger files
(NDC, RxNorm) without reading them into memory.
Errors
| Status | type | When |
|---|---|---|
403 | plan-upgrade-required | The plan is below Team. |
403 | forbidden | The dataset's terms or kind of data keep it out of bulk copies. |
404 | not-found | An unknown dataset, one without snapshots, or no snapshot of that version. |
503 | unavailable | Downloads are briefly unavailable; retry. |